Protocol draft · v0.1

Receipts for what your agents actually did.

The services your agent calls sign an encrypted receipt for what they observed and publish it to a transparency log. Later, you verify it with your own key. No trust in the agent's own logs required.

/SEH-yoh/·Spanish for “seal” or “stamp”
verified-receipt.json
{ "service": "example.com/tool/v1", "action-type": "tools/call", "result-status": "success", "verified": true}
The problem

Most agent logs are written by the same system whose behavior they describe.

If the agent, runtime, or operator is compromised, those logs can be incomplete or false. So Sello flips who holds the pen.

The architectural inversion
beforeagent writes its own log
afterservice signs the receipt it observed
The service was present for the action, but sits outside the agent's logging path. It signs what it saw, and nothing it didn't.
How it works

One receipt, four hands, zero trust in the agent.

1
Agent

Calls a service

Makes a request with its authorization token, carrying the owner's public key and trusted logs.

2
Service

Signs a receipt

Builds the receipt, encrypts it to the owner with HPKE, and signs the envelope with its own key.

3
Transparency log

Stores it

The signed envelope lands in an owner-trusted, append-only log that returns inclusion proofs.

4
Owner

Verifies it

Queries trusted logs, verifies inclusion and the signature, then decrypts with the private key.

receipt
Anatomy of a receipt

Signed on the outside. Sealed on the inside.

COSE_Sign1 envelope · signed by the service
HPKE · encrypted to the owner
CBOR receipt body
service example.com/tool/v1
action-type tools/call
result-status success
sello_token_ref sha256:9f3c…
published to an append-only transparency log, returning an inclusion proof

The signature is the service's

A COSE_Sign1 envelope the service signs with its own key. It never needs the owner's private key.

The contents are the owner's

The body is HPKE-encrypted to the owner's public key, so only the owner can read what happened.

The record is public

The envelope sits in a transparency log. Anyone can confirm it exists; only the owner can decrypt it.

What you can prove

Four things an owner can verify, independently.

A specific service signed it

The COSE signature resolves to a known service signing key.

It was encrypted for you

The body is sealed with HPKE to your public key. Only you read it.

It is in a trusted log

Inclusion is checked against the transparency log's own proof.

The body was not changed

Any edit after signing breaks the signature. Signed equals read.

It does not claim the agent called every service it should havethat every service is honestthat an open log index is complete
Related work

Others get one or two of the four. Sello combines all four.

Project Signed by
the service
Encrypted
to the owner
Public
transparency log
Per-action
receipts
Signet Co-signs MCP responses, kept in operator-controlled storage ·
AgentROA Publishes to a SCITT log, but signs operator-side and in cleartext
Agent Receipts Signs on the agent-platform side ··
IETF SCITT The COSE_Sign1 transparency framework Sello builds on ··
Sello The receiver signs, encrypts to the owner, publishes publicly

Based on the repository's own related-work summary. Fuller prior-art discussion in SPEC.md §12.

Integration

Two sides. Both drop in as middleware.

Service Emit a receipt

Wraps an existing request handler.

  1. Verify the agent's token.
  2. Read owner_hpke_pk and sello_logs from it.
  3. Build a CBOR body for the action.
  4. Encrypt it to the owner with HPKE.
  5. Sign the COSE_Sign1 envelope.
  6. Publish to a trusted log.

Owner Verify a receipt

A pull-based audit tool.

  1. Query trusted logs by sello_token_ref.
  2. Confirm the sello_log_url matches.
  3. Verify log inclusion.
  4. Resolve the signing key from kid.
  5. Verify the COSE signature.
  6. Decrypt and display the body.
Start here

Get one verified receipt working end to end.

Skip Rekor, MCP middleware, and CLI polish for now. Land the local loop first. Everything else gets easier from there.

node --run demo local end-to-end demo
node --run test dependency-free tests
node --run bench -- --json size & performance

Early draft. Issues and pull requests welcome. Adversarial review is the point.