plimsoll run records as Agent Action Capsules

An Agent Action Capsule ↗ is a signed JSON record of one action an automated system took: why it ended as it did, what is known about its effect, and who vouches for that. This page takes the five calls in plimsoll's published session bundle and states each as a capsule (draft-mih-scitt-agent-action-capsule-05). plimsoll's own verifier checks the bundle first; only a record it accepted becomes a capsule. Then both of the capsule project's verifiers check the result, including copies deliberately broken to be refused.

Capsules
5
one per call, chained in call order
Checks as expected
13 of 13
plimsoll's verifier, and the capsule project's in Go and in Python
Stated from
backfilled
records made 28 Sept, stated as capsules afterwards
Import time
2026-10-13T00:17:00Z
pass it to reproduce every capsule ID

The capsules

CallWhat the call's code didVerdictEffectCapsule IDSource: plimsoll run recordFollows
1project, completed, step exits 1executedconfirmedae90012e0af88bc1...f92bd3df8d623203...(first call)
2snippet, exit 0executedconfirmeda653ffc2c9771419...c10fb80babf14d22...ae90012e0af88bc1...
3project, completed, step exits 0executedconfirmede4cca5c95e7714b5...ce75fda50e871016...a653ffc2c9771419...
4snippet, exit 0executedconfirmed017fd7640249f686...d017ac7279c896c6...e4cca5c95e7714b5...
5snippet, exit 0executedconfirmed42074f54273cf341...adf08a4e4ffc058b...017fd7640249f686...

Call 1's own test failed on purpose (the session example plants a bug and fixes it in call 2). It is still executed and confirmed: plimsoll ran the code and observed the result, and the exit code is inside the digested response. A failing program is a result, not an unknown.

What each verifier did

VerifierInputExpectedResult
plimsoll attest (Go)the published session bundle: every signature, every record against its stored request and response, the bundle's chain of links and its checkpoint, the session's chain and its close statementacceptedaccepted: 0 single runs, 1 sessionas expected
plimsoll attest (Go)the bundle with its last call removed (the next line's link names the removed line, and the close statement still counts the call)refusedrefused: entry 5: attest: broken bundle chain: the line says it is line 6as expected
capsule-emit-go (Go)each of the 5 capsules: VerifyCapsule (structure and identity) and VerifyEnvelope (the COSE_Sign1 signature, from the key written beside them)all acceptedall acceptedas expected
capsule-emit-go (Go)call 3's capsule with its verdict changed from executed to deniedrefusedrefusedas expected
capsule-emit-go (Go)call 3's signature presented for a different capsule IDrefusedrefusedas expected
agent-action-capsule (Python)each of the 5 capsules on its own5 accepted5 acceptedas expected
agent-action-capsule (Python)the capsules directory as one store (chain checks across capsules)acceptedaccepted: no errorsas expected
agent-action-capsule (Python)call 3's capsule with its verdict changed from executed to deniedrefusedrefused: (check 2) capsule_id_mismatch: recomputed 690873a3829b23a5... != carried e4cca5c95e7714b5...; (check 4) verdict_effect_conflict: verdict_class 'denied' never dispatches, but derived effect_mode is 'confirmed' (§5.4.2)as expected
agent-action-capsule (Python)the store with call 3's capsule removedrefusedrefused: (check 6) chain_parent_missing: chain parent e4cca5c95e7714b5... not found in the store (§6)as expected
agent-action-capsule (Python)the store with the last call's capsule (call 5) removed, and no witnessed logaccepted: a store check cannot see a missing tail; a witnessed log checkpoint is what catches itaccepted: no errorsas expected
agent-action-capsule with scitt-cose (Python)each of the 5 signatures (COSE_Sign1 over the capsule ID), authenticated to the key in producer.pub5 accepted5 acceptedas expected
agent-action-capsule with scitt-cose (Python)call 3's signature with one bit flippedrefusedrefused: envelope_signature_invalidas expected
agent-action-capsule with scitt-cose (Python)call 3's signature presented for call 4's capsulerefusedrefused: envelope_payload_mismatchas expected

The Python verifier is the capsule project's reference implementation (agent-action-capsule 0.6.0, with its own canonicalization and SHA-256), so it shares no code with the Go emitter that built the capsules. Signatures are checked twice: in Go by the emitter's VerifyEnvelope (go-cose), and in Python by the project's own verify_producer_envelope, which reaches COSE_Sign1 through scitt-cose ↗ 0.4.0. scitt-cose implements COSE_Sign1 from scratch rather than wrapping a COSE library, so the two signature checks share no COSE code either.

The last two rows differ on purpose. Removing a capsule from the middle of the chain is caught because the next capsule names it as its parent. Removing the last one is not caught by a store check, because nothing names it; that is what the capsule project's witnessed log is for, and these capsules were not sent to one. plimsoll's bundle ends in a signed statement of how many calls the session made and which record was last, so its verifier catches a missing tail on its own.

How a plimsoll outcome reads as a capsule

plimsoll outcomeverdict_classeffect.statusDerived effect_modereason_digest
completed, any exit code (a snippet, a cell or a project)executedconfirmedconfirmedabsent
timed_outtimeoutdispatcheddispatched_unconfirmedthe outcome
setup_failederroreddispatcheddispatched_unconfirmedthe outcome
protocol_errorerroreddispatcheddispatched_unconfirmedthe outcome
a session call that may have run but got no answer (a version 3 record)erroreddispatcheddispatched_unconfirmedthe error's status code

Every row uses effect_attestation: runtime_claimed: the capsule records the daemon's statement, checked against the stored bytes by the harness that signed it, not an observation this program made. The vocabulary's stronger grade, gate_executed, is for a producer that observed the effect boundary itself; whether a collector restating a gate's signed record may carry it is a question put to the specification's author and not yet answered, so the capsules claim the grade this program can vouch for. The bundle above exercises only the first row; the others are built and checked by both verifiers in examples/capsule/mapping_test.go. setup_failed and protocol_error share a class and a status, and a dispatched effect may not carry a response digest, so the reason digest (a digest of {"plimsoll_outcome": ...}, or {"plimsoll_unanswered": ...} for a lost answer) is what keeps them apart. Each session call after the first chains to the one before with relation: follows, which orders without claiming anything about the parent.

What these capsules claim, and what they do not

Check it yourself

git clone https://github.com/plimsollmark/plimsoll && cd plimsoll/examples/capsule
go run . -out /tmp/capsule-check            # Go 1.27; same capsule IDs, new signatures
                                            # another bundle needs -operator, -developer and -imported-at
pip install "agent-action-capsule[envelope]==0.6.0"
agent-action-capsule verify --store ../../docs/examples/capsule/capsules

Files beside this page: capsules/ ↗ (one JSON file per capsule, named by its ID: the store the Python verifier reads), envelopes.jsonl (each capsule's COSE_Sign1 signature, base64), and producer.pub. The import this page states used the bundle plimsoll-bundle:sha256:89af007222df5048b40625238c04230b92bbfc23476a66bb0e88af1e8fc73ed6.