Start here

September 17, 2026 · View on GitHub

capsule-emit records your agent's actions as verifiable capsules; seal() is the one call you make.

1. What it is

capsule-emit turns each consequential thing your AI agent does into a capsule — a hashed, signed, content-addressed record that anyone can verify offline, without trusting you.

2. The one call

You already log what your agent does. Move that log to the effect boundary — the moment an action takes effect — and call seal() instead of log(). Same habit you already have, one extra benefit: every call appends one entry to a local, append-only ledger and its digest is witnessed — together a witnessed, verifiable ledger of what your agent did, checkable by anyone. If you know git: seal() is git commit for your agent's actions.

from capsule_emit import seal

capsule = seal(
    {"vendor": "Frobozz Supply", "total": "1240.19"},   # payload: any JSON-serializable value
    action="write_order",
    operator="acme-co",                  # the accountable tenant
    developer="po-agent@v1",             # the agent identity + version
    verdict="executed",                  # executed | confirmed | denied | blocked
    effect={"type": "write_order", "status": "dispatched"},
)

print(capsule.capsule_id, capsule.signature)   # sealed, signed, witnessed by default
pip install capsule-emit

3. Or zero code changes

Don't want to write seal() at each call site? Add one adapter listener per framework and every tool call is sealed automatically:

Your stackOne-liner
LangChain / LangGraphagent.invoke(..., config={"callbacks": [LangChainCapsuleListener(operator="acme-co", developer="my-agent@v1")]}) — see adapters/langchain.md
CrewAIwrap your tool object with CrewAICapsuleEmitter(...) — see adapters/crewai.md
MCP / any callabledecorate the tool with MCPCapsuleEmitter(...).tool("write_order") — see adapters/mcp.md
OthersHermes, Google ADK, Dapr, Goose, agentgateway — see adapters/

All adapters are thin shells over one shared base and seal the same capsule you'd get from calling seal() yourself.

4. When to call it

At each consequential action — the moments where "did your agent really do that, and was it authorized?" has a real answer at stake. → what counts as consequential.

5. What's underneath: the Checkpointed Local Log (CLL)

You never touch this to use seal() — but it's what makes the ledger verifiable, and it's worth 30 seconds. Under every seal() is a Checkpointed Local Log (CLL): an append-only Merkle log on your own disk. seal() appends a leaf; on a cadence the library folds the whole history into one ~200-byte checkpoint and sends only that to a witness — an independent service that co-signs it so your history can't be quietly rewritten later. Your payloads never leave; only the checkpoint does.

What one seal() actually does — and doesn't:

  • Now, at the call: canonicalizes and digests your payload (the raw value stays on your machine), self-signs the capsule with your producer key — a self-attested signature, you vouching for your own record — and appends it as a leaf to your local CLL. cap.seq is that leaf's position; it's in the log immediately, before any checkpoint.
  • Later, on cadence (every ~100 records or ~15 min, or right away if you push()): the whole log is committed into one ~200-byte checkpoint, sent to the witness, which stamps it — and your leaf inherits that stamp through its inclusion proof.

seal() doesn't fetch a witnessed receipt for the payload the moment you call it — it signs it and drops it in the MMR; the independent confirmation arrives with the next checkpoint. (The per-record signature is self-attested and immediate; the witness stamp is what comes later, via CLL.)

If you know git, you already know the shape:

gitcapsule-emit
git commitseal(payload) — record one action
your commit historyyour CLL — the append-only log under every seal()
a signed taga checkpoint — one signed value over the whole history so far
git pushwitnessing — an independent party vouches your history existed

Unpushed git history can be quietly rewritten; pushed history can't. Same here: an unwitnessed log is yours alone, a witnessed one is checkable by strangers.

6. Grow into depth, only when needed

You never rewrite anything to add these — they're the same seal() surface, reached for when you need them:

  • Chain records into trails — link a confirmation to its parent (approved → executed → confirmed):
    confirmation = seal(payload, confirms=parent_capsule_id)
    
  • Compose from slots — bind several members into one capsule that references them by slot and asserts nothing new:
    from capsule_emit import seal, who, can, did, audit
    capsule = seal(who(agent_id), can(mandate), did(action), audit(check))
    
    Composition is nesting the slot verbs who/can/did/audit inside seal() — there is no separate compose() call. Each member can be a fresh payload or a receipt you already sealed along the way — an existing receipt is referenced (its digest is cited in its slot), never re-sealed:
    mandate = seal(payload_a)                     # sealed earlier in the run
    action  = seal(payload_b)                     # sealed earlier in the run
    account = seal(can(mandate), did(action))     # composes them BY REFERENCE (digests, in slots)
    
  • Bring in something already signed — an artifact someone else (or another system) already signed goes in as-transmitted, never re-signed — its bytes committed exactly, its own digest still identifying it:
    from capsule_emit import received
    effect = received(mandate_bytes, type="machine-mandate")
    
    received(...) is also legal nested inside seal() — seal(received(bytes, type=...)) and the standalone call produce the identical capsule.
  • Force a checkpoint — push a signed checkpoint of your log to the witness now, instead of waiting for the cadence:
    from capsule_emit import push
    push()
    
  • Witness / anchor knobs — witnessing to witness.agentactioncapsule.org (POST /checkpoints) is on by default; turn it off with one flag (seal(payload, witness=False), or CAPSULE_WITNESS=off everywhere). The legacy per-capsule anchor channel is off by default (anchor=True to opt back in).

7. Read & verify

View your ledger:

capsule-emit ledger view ./ledger.jsonl

Anyone can verify a capsule (or a whole ledger) independently, from the bytes alone — no keys, no network, no clock — with the separate spec package:

pip install agent-action-capsule
agent-action-capsule verify --store ./ledger.jsonl

The verifier is independent of capsule-emit on purpose: any tool can produce a capsule; any party can verify one.

capsule-emit verify --store ./ledger.jsonl runs that same check plus the producer signature agent-action-capsule verify deliberately leaves to the substrate layer (draft-mih-scitt-agent-action-capsule §6, Class 1 verification): each record is VALID only if its capsule_id recomputes from the carried content AND, when a signature/key_id envelope is present, that envelope verifies. A record with no envelope at all (e.g. a capsule_emit.surface.log() entry, which is never signed) still counts VALID by default, with a one-line summary — N record(s) carry no producer signature (producer_signature_unclaimed) — printed after the tally so the gap stays visible instead of silent. For a ledger whose producer always signs, pass --require-signature to make that same condition fail closed (INVALID, exit 1) instead of warning.


Coming from an older version?

  • emit() → seal(). The top-level producer verb was renamed. emit() remains importable for one release as a raising stub that points you at seal().
  • compose() / carry() are retired as public verbs. There is no compose()/carry() call. "Composition" is now nesting the slot verbs who/can/did/audit inside seal(...); bringing in a foreign signed artifact is received(bytes, type=...) (nested in seal() or standalone).
  • Anchor is now legacy and off by default. The per-capsule anchor channel is an explicit, non-default opt-in (anchor=True / CAPSULE_ANCHOR=legacy-on), kept for one release as a rollback path.
  • Checkpoint/witness is the default push. Every sealed ledger is folded into a per-ledger Merkle Mountain Range and, at the cadence, a signed checkpoint is registered with the witness — the separate, live witness.agentactioncapsule.org service at its POST /checkpoints route. This is the only default egress channel as of 0.5.0.