Skip to main content

One-call emit() for Agent Action Capsules — anchor on by default, ledger view CLI, thin framework adapters.

Project description

capsule-emit

One call to seal a tamper-evident, independently-verifiable record of what your AI agent actually did.

from capsule_emit import emit

cap = emit(action="write_po", operator="acme-co", developer="po-agent@v1",
           agent_input={"vendor": "Frobozz Supply", "total": 1240.19},
           agent_output=result, verdict="executed",
           effect={"type": "write_po", "status": "dispatched"})

print(cap.capsule_id)   # sealed, anchored, verifiable by anyone

capsule-emit is the producer layer for the Agent Action Capsule — a SCITT statement profile. You add one line at the moment your agent does something consequential; you get back a signed, digest-committed capsule that a third party who trusts neither you nor your agent can independently verify.


Why you need this

Agents now move money, change records, and act across organizational boundaries. When something goes wrong — or someone asks "did your agent really do that, and was it authorized?" — what's your proof?

Your logs are your own word. They're mutable, they live in your database, and they mean nothing to an auditor, a counterparty, or a regulator who has no reason to trust your systems. There's no way for an outside party to confirm a log wasn't edited after the fact.

A capsule is different: it's signed at the moment of the action, its content is committed to a hash, and it's recorded in a public append-only log. Anyone can verify it offline, from the bytes alone — without trusting you.

Why your existing stack can't do this

These layers answer different questions — a capsule fills the gap none of them cover:

Layer Examples Answers Doesn't answer
Identity DIDs, SPIFFE, Agent Cards Who is the agent? What it did
Authorization OPA, policy, permits What is it allowed to do? What it actually did, or the outcome
Observability Datadog, audit logs, your DB What you say happened Nothing to a party who doesn't trust you — mutable, self-attested
Agent Action Capsule capsule-emit What it did, provably (composes with the above by reference)

A capsule records the action and its outcome, with a confirmed-effect binding so a dispatched attempt can't be passed off as a completed effect (the may/did distinction: approved ≠ executed ≠ confirmed). It records on every verdict, including refusals — a blocked capsule is auditor-grade evidence that a gate worked.

Concepts

A small vocabulary — each concept maps to a field you can see or a command you can run:

  • Capsule — the unit: one consequential action and its outcome, sealed, signed, and digest-committed. It's plain JSON — inspect it with cap.capsule (see What's in a capsule below).
  • may / did — the honesty model: approved ≠ executed ≠ confirmed. A capsule carries the verdict (disposition.verdict_class) and a confirmed-effect binding (effect.status + request/response digests), so a dispatched attempt can never be presented as a completed effect.
  • Chain — actions link by digest: a confirm / supersede / escalate capsule points at its parent (chain.parent_capsule_id), turning approved → executed → confirmed (or deferred → escalated → resolved) into one verifiable trail. → emit(..., confirms=parent_id)
  • Break — tamper-evidence: change a single byte and the recomputed capsule_id stops matching, so verify returns INVALID. The break is the proof — it's what makes the record trustworthy to someone who didn't write it.
  • Anchor — the public proof: the capsule's digest is written to an append-only transparency log; the receipt proves it existed at time T, checkable by anyone without trusting you (see Anchoring below).
  • Ledger — your local append-only trail of capsules (the chain of chains). → capsule-emit ledger view ./ledger.jsonl
  • Verify — anyone, offline, from the bytes alone — no keys, no network, no clock. Class-1 (structure + IDs), Class-2 (manifest-aware). Independent of the producer on purpose (see Verify below).
  • Declare → Enforce — a manifest.md declares autonomy + constraints; a compatible gateway enforces the same file later, with no change to your emit() calls (see Declare now, enforce later below).

The sections below are the depth behind each concept.

How easy it is

pip install capsule-emit          # emit + anchor client + ledger CLI
from capsule_emit import emit

cap = emit(
    action="write_po",
    operator="acme-co",                 # the accountable tenant
    developer="po-agent@v1",            # the agent identity + version
    agent_input={"vendor": "Frobozz Supply", "total": 1240.19},
    agent_output=result,
    model={"provider": "anthropic", "model_id": "claude-sonnet-4-6"},
    verdict="executed",                 # executed | blocked | denied | errored | timed_out
    effect={"type": "write_po", "status": "dispatched"},
)
print(cap.capsule_id, cap.anchored)

That's it. The capsule is sealed and anchored. One call per consequential action.

What's inside a capsule

emit() returns cap.capsule — a JSON object you can inspect, store, or hand to anyone:

{
  "spec_version":   "draft-mih-scitt-agent-action-capsule-01",
  "format_version": "2",
  "capsule_id":     "9fddfcec…32eb26",      // SHA-256 of the canonical payload (its content address)
  "action_id":      "write_po/39530d9c…",   // the action name + a unique id (chain linkage)
  "action_type":    "decide",               // the capsule class (a decision that produced an effect)
  "operator":       "acme-co",              // accountable tenant
  "developer":      "po-agent@v1",          // agent identity + version
  "timestamp":      "2026-06-20T04:45:11Z",
  "model_attestation": {                    // which model + the evidence it produced
    "provider": "anthropic",
    "model_id": "claude-sonnet-4-6",
    "compute_attestation": {
      "agent_input_digest":  "3c2c9123…",   // the prompt/input, sealed by hash
      "agent_output_digest": "c574d16d…"    // the inference/output, sealed by hash
    }
  },
  "effect": {                               // what was committed
    "type":   "write_po",
    "status": "dispatched",                 // dispatched (attempted) vs confirmed (observed)
    "effect_attestation": "runtime_claimed"
  },
  "disposition": {                          // the may/did verdict
    "decision":       "accept",
    "verdict_class":  "executed",           // executed | blocked | denied | errored | confirmed
    "approver":       "policy",
    "human_disposed": false                 // honest in-the-loop flag
  },
  "assurance": {                            // how far to trust each part
    "attestation_mode": "self_attested",
    "effect_mode":      "dispatched_unconfirmed",
    "ledger_mode":      "standalone"        // standalone | chained
  }
  // When a capsule confirms/supersedes another, a "chain" block appears and
  // the effect gains a "response_digest" (the confirmed-effect binding):
  //   "chain":  { "parent_capsule_id": "1008e6fc…", "relation": "confirms" }
}

Confirming or superseding an action is itself a capsule that chains to the first — that's how "approved → executed → confirmed" becomes a verifiable trail. Full field reference: the spec §5.

Anchoring — where the proof lives

Anchor is on by default. When you emit(), the capsule's digest only is submitted to a SCITT transparency log, and you get back an RFC 9162 inclusion-proof receipt — durable, tamper-evident evidence that this exact capsule existed at that time.

  • Where: the free hosted log at https://anchor.agentactioncapsule.org/v1/digest (no signup, no key).
  • What's logged: a SHA-256 digest (the capsule_id) — nothing else. Your vendors, amounts, operator, and payloads never leave your machine.
  • What you get: the receipt (an inclusion proof) — keep it with the capsule; anyone can later check the capsule against the log offline.
  • Self-host or repoint: the log service (capsule-anchor) is open-source. Point anywhere with AAC_ANCHOR_URL=https://your-log/... or emit(..., anchor_url=...).
  • Offline: emit(..., anchor=False) seals locally and skips the network.
  • Why bother: a self-hosted log you control isn't proof to an outsider; a shared, append-only transparency log is. That's what makes the capsule checkable by someone who trusts neither party.

Verify

The verifier ships in the spec package — install it and check any capsule (or a whole ledger) from the bytes alone, no keys/network/clock:

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

Tamper with one byte and verification fails. The verifier is independent of capsule-emit on purpose — any tool can produce a capsule; any party can verify one.

Ledger view

Every emit() appends to a local JSONL ledger:

capsule-emit ledger view ./ledger.jsonl

Framework adapters

One emit() per tool call, regardless of framework — thin adapters over one shared base:

from capsule_emit.adapters.mcp import MCPCapsuleEmitter          # primary (MCP)
emitter = MCPCapsuleEmitter(operator="acme-co", developer="my-agent@v1")

@emitter.tool("write_po")
def write_po(vendor: str, total: float) -> dict: ...

LangChain (LangChainCapsuleEmitter, a callback handler), CrewAI (CrewAICapsuleEmitter, .wrap(tool)), and Hermes (HermesCapsuleEmitter, .after_tool(...)) work the same way. Per-adapter guides — where to put the call, the one-line add, and a ready-made prompt for your coding agent — are in docs/adapters/.

Declare now, enforce later — same file

Drop a flows/<action>/manifest.md next to your code to declare autonomy + constraints:

---
wicket_id: write-po
autonomy: narrate
---
## Constraints
| id | what it checks | method | severity |
|----|----------------|--------|----------|
| po_arithmetic | Line items re-add to total. | arithmetic_balance | block |

capsule-emit reads the manifest to declare (no enforcement). A compatible gateway reads the same file and enforces — adding enforcement requires no changes to your emit() calls or manifests.

How it fits

capsule-emit  →  agent-action-capsule (spec + reference verifier)
                        ↓
                 scitt-cose (COSE_Sign1 + SCITT receipt verification)

capsule-emit produces; agent-action-capsule is the specification + verifier; scitt-cose verifies the transparency-log substrate. Separate on purpose.

Documentation

New here? These are written to be read top-to-bottom, no standards background needed:

  • Tutorials — five-minute, copy-paste sessions: your first capsule → confirming & chaining → reading your ledger → declaring rules.
  • Concepts in plain words — the seven words (capsule, seal, may/did, chain, break, anchor, ledger), each tied to a field or command.
  • Anatomy of a capsule — exactly what gets sealed, the two-tier structure, and how each layer is captured.
  • Adapters — let MCP / LangChain / CrewAI / Hermes emit capsules for you (with a paste-to-your-coding-agent prompt on each page).
  • Going deeper — and popping outdown into the spec + scitt-cose substrate if you want to verify it yourself; up to a compatible enforcement gateway (e.g. gopher-ai, OSS) when you want capsules to block, not just record.

Status

Alpha — API stable, not yet 1.0. The underlying specification is an individual IETF Internet-Draft, not an RFC; no RFC number is claimed.

Provenance, neutrality & governance

Developed by Action State Group, Inc. and published as open-source software (Apache-2.0), with a clean transfer path to a neutral home (foundation donation or community project) as the ecosystem matures. The content is product-free — the emission layer, adapters, ledger utilities, and a manifest parser; nothing tenant- or product-specific. No primacy is claimed; the value is an interoperable, independently-verifiable record format. Discussion venue: the IETF SCITT Working Group (scitt@ietf.org).

License

Apache-2.0 — see LICENSE.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

capsule_emit-0.1.0.tar.gz (26.5 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

capsule_emit-0.1.0-py3-none-any.whl (24.4 kB view details)

Uploaded Python 3

File details

Details for the file capsule_emit-0.1.0.tar.gz.

File metadata

  • Download URL: capsule_emit-0.1.0.tar.gz
  • Upload date:
  • Size: 26.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.7

File hashes

Hashes for capsule_emit-0.1.0.tar.gz
Algorithm Hash digest
SHA256 4a7b453f22072a8957997a0591068e3d774f4fb7aadcdd2d0e96ee5c26ea5405
MD5 ad0c188e3b8ea70b9b6e08556239be19
BLAKE2b-256 785f9ecda2bcf8a4d851a6c05b629c53363413e4a551f1c3a5aeb41b08fee0be

See more details on using hashes here.

File details

Details for the file capsule_emit-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: capsule_emit-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 24.4 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.7

File hashes

Hashes for capsule_emit-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 aa9d0a99ccea4017b9d433dccae2a65f21746d48f52b0ab14329fe61bbba9aa2
MD5 43ff9c926909400286380e1fa16bb761
BLAKE2b-256 40159181efbdce97043dfca8ccd5b170c66b1fdd7e938444a1bace6ab5e5b00c

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page