Shipped: coherence over the store you already run
Your agents already share state through a store you already run. The lost update lives there too.
The last receipt in this series showed the write-side guarantees going live: version-CAS for the concurrent lost update, invalidation-deny for the sequential stale-read-then-write, a read fence for the zombie commit. All of it real, all of it machine-checked. And all of it living in surfaces this library ships: a store class you drop into LangGraph, a volume that manages files on disk. Which leaves the obvious objection standing. The state your agents actually fight over is not in our store. It is a row in your Postgres and an object in your S3 bucket, and nobody migrates their production state into a coherence library to get a guarantee.
As of v0.13.0 you don’t have to. This post is the receipt.
The key idea: coherence as a layer, never a store
The new surface is a contract called CoherenceSubstrate, with two shipped bindings: CoherentRow for a Postgres row and CoherentObject for an S3 object. The split of responsibilities is strict, and it is the whole design.
Your store keeps the bytes. It stays the system of record, keeps its backups, its permissions, its durability story. The coordinator holds only coherence metadata: a monotonic version, per-agent MESI state, a fixed-width content hash, and an opaque token the substrate hands back. There is no path in the contract for the coordinator to become a store, and the capability tiers enforce that floor. If the binding disappears tomorrow, your data is exactly where it always was.
What your database already does, and what it cannot
Postgres and S3 each ship a conditional write. UPDATE ... WHERE version = ? on a row, If-Match on an object. Used well, that native check already rejects a single lost update at the moment you write, and the bindings ride it rather than replacing it. If you are using it today, keep using it. That part of the problem was solved before we got here.
Here is what the conditional write cannot do. It cannot tell the other agent anything. Agent A reads the row at version 7 and starts a two-minute reasoning pass over it. Agent B commits version 8. A’s conditional write will bounce two minutes from now, which protects the row. But A spent those two minutes reasoning over a value that was already dead, and everything else A wrote in that window, the plan, the summary, the tool call it fired, was derived from version 7 and landed fine. The row survived. The work is contaminated. A version check protects the write. It does not protect the reader.
That cross-agent half is what the bindings add. When B commits, A’s cached read is marked stale at the coordinator. A’s next binding-mediated read or write is denied before it acts on the moved state, fail-closed. The conflict comes back in the same typed shape every other surface in this library returns. Recovery is the same everywhere too: reacquire(), take a fresh read, proceed against what is actually there. One protocol, one conflict shape, one recovery verb, whether the state is a row, an object, or a file.
The same story, on your substrate
Run the scenario from this series one more time, on a Postgres row this time. Two sessions read the row at version 7. Both distill. Both write. In the unguarded run, the second write lands on top of the first and a lesson vanishes, no error, no log line. The demos ship with that run included, on purpose: python -m examples.coherent_row.main --baseline shows the clobber before anything prevents it. Drop the flag and the same interleaving produces a stale-marked read, a denied write, a typed conflict, a reacquire, and both writes surviving. examples/coherent_object tells the identical story against S3. Offline, deterministic, exit 0 only if the invariants held.
The peers multiplied: subagents get their own identity
There is a second shipped piece in v0.13.0, and it matters to anyone running Claude Code with subagents. Until now, a subagent’s writes blended into its parent session. One session identity, several actual writers, which is exactly the blur this whole series argues against. Now a subagent’s hook payload carries the parent session plus its own agent id, and the identity derivation folds in both. Each subagent becomes a first-class coherence peer: last_writer points at the subagent that actually wrote, sibling collisions are detected as collisions, and when a subagent stops, only its own grants are released, not the parent’s. With no agent id present the derivation is byte-identical to before, so nothing changes for main-thread sessions.
Three failures, three runnable receipts
The release also ships three demos that each replay a failure this series has described, then prevent it. Each is offline and exit-0-gated, so they double as CI checks.
| Demo | The lived failure | What the guarded run does |
|---|---|---|
examples/rag_stale_memory |
An agent caches a memory record, a peer appends a fact, the agent’s stale write-back erases it | The stale write is denied, the agent reacquires and re-applies, both facts survive |
examples/ci_merge_gate |
Three PRs merge clean, CI stays green, the product breaks: a merge validated against a base a peer already moved | gate() holds the merge and re-fires the validation on the fresh base |
examples/gate_effect_ordering |
A deploy planned from inputs that moved before it fired | gate() holds the effect and re-plans on current state |
Two smaller receipts ride along. A three-act CCSStore demo (examples/ccsstore_read_side) makes the read/write split explicit: the read-side invalidation CCSStore ships, the write-back it deliberately does not check, and the write_cas call that closes the gap. And the stale-write-guard-fs MCP server now publishes to the official MCP Registry automatically on every release, under its corrected name, io.github.Cohexa-ai/stale-write-guard-fs.
The scope, stated plainly
Same fence as every receipt, drawn around the new surface.
Everything above is single-host. That scope did not move in this release. Two writers on two machines are still not covered by a shipped guarantee, and the demo-grade cross-host transport is still a demo.
The bindings are cooperative. A writer that goes straight to Postgres or S3 without the binding is not caught at write time. The coordinator detects the divergence on the next mediated read, from the content hash, but detection after the fact is not prevention, and we will not blur that line. The guarantee covers the writers you route through the binding.
The bindings layer on top of your substrate’s own conditional write, they do not replace it, and they do not make a weak substrate strong. Each binding declares an honest capability tier derived from what the substrate can actually enforce, and the conformance kit checks the declared tier against observed behavior. And the standing not-shipped list still stands: no production cross-host fencing, no cross-artifact write-skew prevention, no semantic constraints or claims index, no advisory-versus-enforce toggle, no source-watcher. When they ship, they get their own receipt. Since the last receipt, for completeness: snapshot sessions landed in v0.11.0 and the all-or-nothing multi-file publish landed in v0.12.0, both single-host, both in the release notes.
Why it matters
The write-side guarantees stopped being an argument for a particular store the moment they stopped living in one. The contract is the durable part. Any substrate that can produce a version token and a conditional write can join it, and every substrate that joins speaks the same typed conflict and the same recovery. Coherence becomes something you add to the state you already have, not something you migrate to. That is the shape that compounds.
Get it running
pip install "agent-coherence[coherent-row]" # Postgres
pip install "agent-coherence[coherent-object]" # S3
Run the baseline first. Watch the clobber, then watch it stop:
python -m examples.coherent_row.main --baseline
python -m examples.coherent_row.main
The full surface, the manifest format, and the tier definitions are in the BYO-substrate guide, and the complete change list is in the v0.13.0 release notes. Start on one host, on the store you already run. That is where the fix is real.