Chaining
August 28, 2026 · View on GitHub
A single capsule records one action. Chaining links capsules into a verifiable trail within one stream. This is where the may/did distinction becomes a sequence. Cross-organizational chaining guidance is under revision — see below.
How the link works
Every capsule is identified by its capsule_id — the SHA-256 of its canonical
content (a content address). A capsule links to a prior one by putting that id in
chain.parent_capsule_id, with a relation:
"chain": { "parent_capsule_id": "4650e8f9…16f03", "relation": "confirms" }
Because the link is a content address, it is global and position-independent: it points at a capsule by what it is, not by where it sits or who holds it. Everything below follows from that one fact.
Within one agent — the trail
You build a trail by pointing each new capsule at its parent with confirms=:
from capsule_emit import seal
# the agent attempts the action
attempt = seal({"po_id": "PO-7781"}, action="write_po", operator="acme-co", developer="po-agent@v1",
effect={"type": "write_po", "status": "dispatched"})
# later, your system confirms it landed — chained to the attempt
done = seal({"po_id": "PO-7781"}, action="write_po", operator="acme-co", developer="po-agent@v1",
verdict="confirmed",
effect={"type": "write_po", "status": "confirmed"},
confirms=attempt.capsule_id) # ← chain.parent_capsule_id
That turns approved → executed → confirmed (and human-in-the-loop approval) into one verifiable sequence in your ledger. (See tutorial 2.)
Across agents — under revision
⚠ Under revision. This section previously recommended
confirms=for linking capsules across different organizations/ledgers. That guidance is being replaced: a dedicated cross-stream reference mechanism has been decided and is not yet shipped. Don't useconfirms=to link capsules across different organizations/ledgers in new integrations — treat it as valid only for links within one stream (see "Within one agent" above). This section will be rewritten in full once the replacement ships.
The mechanical fact that doesn't change: because capsule_id is a content
address, a capsule in one ledger can reference a capsule in another by id alone
— no shared database is required. What's changing is which relation you use to
express that cross-stream link; this page will be updated when that lands.
Today
confirms=writesrelation: "confirms". The spec also definessupersede/escalate; richer relation values (and arelation=parameter) are registry-extensible, not yet surfaced onseal()/received().
An agent has many chains — the ledger is a DAG, not a line
Don't picture "the agent's chain." Picture the ledger as a forest:
- A capsule has at most one parent (
chain.parent_capsule_id), but many capsules can point at the same parent (fan-out — several confirmations or supersessions of one action), and a capsule can be the parent of many. - Most capsules are standalone (no chain) — a lone action with no follow-up.
- So each consequential action grows its own chain (
approved → executed → confirmed), and the ledger is the whole collection — a directed acyclic graph. - It can't cycle: a parent's id exists before its child is sealed, so no capsule can ever be its own ancestor.
- Distance doesn't matter — a capsule can chain to the immediately prior capsule or one far earlier; it's the same operation, since it's an id, not a position.
Verifying a chain
To check a link, you need both capsules (or at least the parent's id and bytes).
agent-action-capsule verify --store over a ledger checks each capsule's own seal and
the chain links it can see:
agent-action-capsule verify --store ./ledger.jsonl
The verifier recomputes each capsule_id and confirms a child's parent_capsule_id
matches the parent's recomputed id. Tamper with either capsule and the link breaks — the
chain is exactly as trustworthy as the content-addressing underneath it.
Why cross-agent chaining works at all
It works because the capsule is a neutral open format, not a vendor's internal record.
Emitter B can reference emitter A's capsule because both produce the same standard
capsule, the capsule_id is computed the same way everywhere, and any verifier can
check the link from the bytes. A format owned by one vendor couldn't do this across an
org boundary; an open, content-addressed one can. (More: going deeper.)
Related: concepts (the Chain word) · anatomy (the chain
field) · tutorial 2 (hands-on).