Format Contents API: If-Match stops two agents overwriting each other

Per-file sha checks do not catch two agents editing different files. Send If-Match with package_sha and handle 409 format_package_sha_mismatch.

5 min readSume
All posts

To keep two agents from overwriting each other's work on a Sume Format, send If-Match: <package_sha> on every write. A per-file sha only protects the file you touch. Two agents that edit different files each hold a current file sha, so both writes land, yet the second agent planned its edit against an old package. The If-Match header closes that gap, and a stale value returns 409 format_package_sha_mismatch.

Where the value comes from

The package sha is commit.tree.sha from your last write. It is also the package_sha field on the Format record, and POST /v1/formats returns it when you create a Format. It is a bare 40-character hex string, not an HTTP ETag in quotes. Formats published before package_sha existed ignore the header instead of returning a 409 that no one could satisfy.

The two checks side by side

The table compares the two guards. Both come from the Contents docs, as of 2026-10-09.

Per-file sha versus package If-Match, as of 2026-10-09
GuardSent asProtects againstError when stale
File shaField in the bodyTwo writers on the same file409 format_content_sha_mismatch
File sha missing(not sent)Overwriting an existing path blindly409 format_content_sha_required
Package shaIf-Match headerTwo writers on different files409 format_package_sha_mismatch

A safe edit loop

Use the loop below for each agent turn that edits a Format. It needs one read and one write when nothing has moved, and one extra read when something has.

  • Read the whole package with GET …/contents?recursive=1. Each row carries its sha and body.
  • Plan the edit and build a files change set. Paths you do not name are kept, so you cannot delete a file this way.
  • PUT …/contents with If-Match set to the package sha and the current sha on each existing path.
  • On 409 format_package_sha_mismatch, read error.details.package_sha, re-read the package, redo the plan and write again.
  • Keep the new commit.tree.sha for the next write.

What the guard does not do

A change to a package has no effect on a run that already started. Each run reads the package it started with, and the receipt's format.version records which version ran. The API has no revert, blame or history browsing, and no clone URL, so keep your own copy of anything you may need to restore. A 503 format_git_unavailable means nothing was saved, so retry the write.

Reading the 409 in code

The 409 is part of normal operation with several writers, so write the retry on purpose. The error carries the current package sha in error.details.package_sha, which saves one request, but the contents of the package changed too, so you must re-read the files and rebuild your change set. Do not just resend the old body with the new header: that would defeat the check, and the per-file sha values would probably mismatch anyway.

Limit the retries. If two agents keep colliding, one of them is editing a file the other also needs, and the better fix is to give each agent its own files, for example one references/ note for each. The author of each commit is always the owner of the key, whatever author the body names.

Sources

Related posts

More in Formats

All Formats posts

Written by Sume