README.md
Agent Passport — what does an on-chain identity actually prove about an AI agent?
There is a popular idea that if you register an AI agent on a blockchain, it becomes trustworthy — "the agent lives forever on-chain." This is mostly false, and the interesting part is why it's false.
An agent is not its identity record. The thing that actually acts — the model weights, the prompt, the tools, the keys, the operator paying the inference bill — lives off-chain and can change or disappear at any moment. A chain cannot preserve cognition. It can only preserve a record of what an identity claimed to be, who controlled it, and in what order those things changed — and it can make that record impossible to rewrite.
So this realm doesn't try to prove an agent is safe. It does something more honest and more useful: it tracks the drift of an identity over time and puts it in front of you.
The model
An agent is a persistent Gno object, not NFT metadata scattered across contracts:
1type Agent struct {
2 ID string
3 Owner address
4 Operators []address
5 Runtime string // e.g. "claude-opus-4-8@<commit>"
6 Endpoints []Endpoint // MCP / A2A / DID / URL
7 Caps []string // self-declared capabilities
8 Status Status // active | suspended | retired
9 CreatedAt int64
10 UpdatedAt int64
11 History []Event // append-only lifecycle log
12}
Because it's a normal object graph, other realms don't parse it — they ask it:
1passport.IsActive("percy") // is this identity live?
2passport.IsOperator("percy", caller) // may this key act as the agent?
That is the composability angle Gno gives you for free: the identity layer is an importable package, not an ABI you reverse-engineer.
Why "drift" is the whole point
Every mutation is appended to an immutable log, and the profile page surfaces the two changes that most weaken an identity as evidence:
- ownership changes — the operator behind the identity may now be someone else entirely;
- runtime changes — the thing acting under this name is (partly) a different thing than the one that built the reputation.
## Drift
- Ownership changes since creation: 1
- Runtime changes since creation: 3
A reputation attached to "percy" means very little if percy changed owners last week and swapped models three times. The chain can't tell you the agent is good — but it can stop that history from being quietly erased.
Try it
1// register (caller becomes owner)
2passport.Register(cross(cur), "percy", "claude-opus-4-8@abc123")
3
4// authorize a second signing key
5passport.AddOperator(cross(cur), "percy", operatorAddr)
6
7// record a model change — logged loudly as drift
8passport.SetRuntime(cross(cur), "percy", "claude-opus-4-8@def456")
9
10// lifecycle
11passport.Suspend(cross(cur), "percy")
12passport.Reactivate(cross(cur), "percy")
13passport.Retire(cross(cur), "percy") // terminal
(From gnokey maketx call, the crossing is implicit — you just call
Register percy "claude-opus-4-8@abc123".)
Browse the registry at the realm root, and any agent's profile + full
lifecycle log at :<id> (e.g. .../passport:percy).
Run the tests:
1gno test .
What it deliberately does not do
- It does not prove capabilities.
DeclareCapabilityrecords a claim; proving work happened belongs to an execution-receipt realm, and validating it belongs to a review/jury realm. - It does not authorize specific actions. "Who is this agent" and "may this agent do this exact thing, once, under this budget" are different questions — the second is a capability, not an identity.
Identity is the floor, not the ceiling. It tells you who is claiming to act and how much that claim has drifted — and then gets out of the way of the mechanisms that actually establish trust.
Part of moul/gno-contracts — moul's versioned gno.land contracts. See the repository for the full catalog, build/test tooling, and usage.
Dependency graph:

⚠️ Disclaimer: provided as-is, without warranty; not security-audited. Full disclaimer: DISCLAIMER.