https://github.com/juanfiguera/sello
Service-signed encrypted receipts for AI agent actions. https://sello.build/
https://github.com/juanfiguera/sello
ai-agents audit cose hpke mcp receipts transparency-log
Last synced: about 2 months ago
JSON representation
Service-signed encrypted receipts for AI agent actions. https://sello.build/
- Host: GitHub
- URL: https://github.com/juanfiguera/sello
- Owner: juanfiguera
- License: other
- Created: 2026-05-28T09:46:55.000Z (2 months ago)
- Default Branch: main
- Last Pushed: 2026-06-15T06:33:06.000Z (about 2 months ago)
- Last Synced: 2026-06-15T07:04:41.251Z (about 2 months ago)
- Topics: ai-agents, audit, cose, hpke, mcp, receipts, transparency-log
- Language: TypeScript
- Size: 2.23 MB
- Stars: 2
- Watchers: 0
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- Contributing: CONTRIBUTING.md
- License: LICENSE
- Security: SECURITY.md
Awesome Lists containing this project
README

Sello
Quickstart ·
Add Sello ·
MCP ·
SDKs ·
Actions ·
How It Works ·
Learn More ·
Protocol ·
Paper ·
Security ·
Contributing ·
License
Sello is a protocol for independently-verifiable records of AI agent actions.
**Pronunciation:** commonly `SEH-yoh` or `SEH-yo`, from the Spanish word *sello*, meaning a seal or stamp.
When an agent calls a service, the service creates a receipt for what it observed. The receipt is encrypted to the agent owner, signed by the service, and published to a transparency log. Later, the owner can retrieve and verify that receipt without trusting the agent's own logs.
```text
agent calls service
-> service creates encrypted signed receipt
-> transparency log stores receipt
-> owner fetches, verifies, decrypts
```
## Try It
Requires Node.js 22.7 or newer.
From a new project or temporary folder:
```bash
# Terminal 1
npx --yes sello dev
# Terminal 2
npx --yes sello emit-demo
npx --yes sello actions
```
Then open:
```text
http://localhost:8787/actions
```
`sello dev` creates local keys, a demo token, a service registry, and a local transparency log under `.sello/`. The log stores encrypted receipt entries, not plaintext action details.
## Add Sello to a Tool
TypeScript:
```bash
npm install sello
```
```ts
import { sello } from "sello";
const receipts = sello.service();
export const createEvent = receipts.tool("calendar.create_event", async (request) => {
return calendar.events.create(request);
});
```
Python:
```bash
pip install sello
```
```py
import sello
receipts = sello.service()
@receipts.tool("calendar.create_event")
def create_event(request):
return calendar.events.create(request)
```
In local dev, `npx sello dev` supplies the config this snippet needs. In production, configure your service with a service id, service signing key, token issuer, and log URL:
```bash
SELLO_SERVICE_ID=calendar.example.com/mcp/v1
SELLO_SERVICE_KEY=sello_live_local_...
SELLO_TOKEN_ISSUER_JWKS=https://auth.example.com/.well-known/jwks.json
SELLO_LOG_URL=https://logs.example.com/api
SELLO_SUBMIT_MODE=background
```
Sello works with your own log server. Using `sello.build` is an optional convenience, not a protocol requirement.
To scaffold a tiny emitter or HTTP route:
```bash
npx --yes sello init-demo
npx --yes sello init-http-demo
```
## Add Sello to an MCP Server
If your service exposes MCP tools, wrap the tool callback:
```ts
import { sello } from "sello";
const receipts = sello.service();
server.registerTool(
"calendar.create_event",
{ inputSchema: createEventInputSchema },
receipts.mcpTool("calendar.create_event", async (args) => {
const event = await calendar.events.create(args);
return {
content: [{ type: "text", text: event.id }],
};
}),
);
```
Some MCP SDK versions call this method `tool` instead of `registerTool`; use the same callback slot either way.
`mcpTool` verifies the agent token before your callback runs, preserves the callback's return value, rethrows callback errors, and emits a receipt with action type `mcp.tools/call.`.
By default, Sello looks for an `Authorization: Bearer ...` token in common MCP context/header fields. If your transport stores tokens somewhere else, pass an extractor:
```ts
receipts.mcpTool("calendar.create_event", handler, {
authorizationToken: ({ context }) => context.session.token,
});
```
See [docs/mcp.md](docs/mcp.md) for token handling, hash boundaries, unknown-tool behavior, and action viewing.
## See Logged Actions
```bash
npx sello actions
```
In local dev, `sello actions` reads the latest dev token and owner key from `.sello/dev.json`. To inspect actions for a specific agent token, pass it explicitly:
```bash
npx sello actions --token
```
The token is the same authorization token the agent used when it called services. Sello hashes the exact token bytes into `sello_token_ref`, queries trusted logs, verifies matching receipts, and decrypts them with the owner key.
Public logs store encrypted receipts. Viewing action details requires the owner private key or an explicitly delegated viewer key.
## How It Works
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.
Sello moves receipt-writing to the services the agent calls. The service was present for the action, but it is outside the agent's own logging path.
1. The agent calls a service with an authorization token.
2. The service verifies the token, runs the action, and signs an encrypted receipt for what it observed.
3. A transparency log stores the encrypted receipt.
4. The owner later fetches, verifies, and decrypts the receipt.
Sello helps an owner verify that a specific service signed a specific receipt, the receipt was encrypted for the owner, the receipt was included in a trusted transparency log, and the receipt body was not modified after signing.
Sello does not prove that the agent called every service it should have called, that every service is honest, or that unauthenticated log indexes returned complete results. Those limits are intentional and documented in the spec.
## Learn More
- [SDK Quickstart](docs/sdk-quickstart.md): local dev, HTTP demo, self-hosted config, and hosted config.
- [MCP Integration](docs/mcp.md): where Sello wraps MCP tool callbacks.
- [SDKs](sdks/README.md): TypeScript and Python package layout.
- [Python SDK](sdks/python/README.md): Python package install command, scope, and test command.
- [Protocol Walkthrough](docs/protocol-walkthrough.md): the primitive receipt loop for implementers.
- [SPEC.md](SPEC.md): the Sello protocol draft.
- [Notarized Agents paper](https://arxiv.org/abs/2606.04193): design rationale, threat model, and prior art.
- [sdks/typescript/examples/mcp-minimal-server.ts](sdks/typescript/examples/mcp-minimal-server.ts): a small MCP integration.
- [docs/security-review.md](docs/security-review.md) and [docs/sdk-security-audit.md](docs/sdk-security-audit.md): current review notes.
The TypeScript SDK is published on [npm](https://www.npmjs.com/package/sello) and lives in [`sdks/typescript/`](sdks/typescript/). The Python SDK is published on [PyPI](https://pypi.org/project/sello/) and lives in [`sdks/python/`](sdks/python/). Both SDKs support the same service-side `sello.service()` flow; Python uses the `@receipts.tool(...)` decorator. Live Rekor proof verification and production identity operations are still future work.
## Core Terms
- **Owner:** deploys the agent and holds the HPKE private key.
- **Agent:** calls services with authorization tokens.
- **Service:** signs receipts for actions it observed.
- **Receipt:** encrypted CBOR body inside a signed COSE_Sign1 envelope.
- **Transparency log:** append-only store that returns inclusion proofs.
- **`sello_token_ref`:** SHA-256 of the exact raw compact JWS bytes.
- **`sello_log_url`:** canonical URL of the log that stored the receipt.
## Related Work
Verifiable records of agent activity are an active area, and several projects are working nearby. Sello's specific combination, where the receiving service signs the receipt, encrypts it to the owner, and publishes it to a public transparency log, appears to be distinct, but the surrounding space is rich and worth knowing.
Closest neighbors include Signet, which co-signs MCP responses but keeps receipts in operator-controlled storage; AgentROA, which publishes per-action receipts to a SCITT log but signs at an operator-side gateway and in cleartext; Agent Receipts, which signs on the agent-platform side; and the IETF SCITT working group, whose COSE_Sign1 transparency-receipt framework Sello builds on. Each gets one or two of Sello's four properties. None, as far as we found, combines all four.
Much of this prior work surfaced after Sello's design had already converged on similar primitives. That independent convergence is a good sign the problem is real. See [SPEC.md](SPEC.md) §12 for the fuller prior-art discussion.
## Sharp Edges
- Hash the exact raw compact JWS bytes. Do not parse and reserialize first.
- Compare log identities by canonical URL string; see `SPEC.md` §6.2.
- Do not treat an unauthenticated Rekor/off-log index as proof of completeness.
- Use verifiable log integrated time for revocation decisions, not the receipt timestamp.
- Deduplicate only on the full spec key, including action type and input/output hashes.
## Feedback
Issues and pull requests are welcome. This is an early draft; adversarial review is the point. See [CONTRIBUTING.md](CONTRIBUTING.md) for contribution notes and [SECURITY.md](SECURITY.md) for sensitive reports.
## License
Apache 2.0. See [LICENSE](LICENSE).