An AI agent that can prove what it is is not a hard problem. An AI agent that can prove what it is without asking anyone's permission is.
Those turn out to be very different problems, and the gap between them is where most of the engineering went.
What an agent identity has to answer
Three questions, and they are not the same question:
- Who is this agent? A stable identifier that resolves to something.
- Who vouches for it? An issuer that says something about the agent.
- Has that vouching been revoked or superseded? Time and state.
If you collapse these you get a key pair and a database. If you keep them separate you get something that survives the agent changing.
The shape we landed on
The XRP Ledger gives you a natural issuer: an account is a key pair with a balance and a sequence number, and the ledger is already a public, append-only, hash-chained log. So:
- The agent is an account. Its DID is derived from its address.
- The issuer is also an account, and its authority to say things about the agent is itself a credential.
- The credential is a
Credentialobject on the ledger (XLS-70), issued to the agent's DID, signed by the issuer.
The result is did:xrpl — a real W3C DID method, where the resolution document is assembled from ledger state rather than from an HTTP endpoint that happens to be up.
The important consequence: verification needs no infrastructure at all. No API server, no uptime, no registry to keep running. A verifier asks the ledger. If the ledger is there, the answer is there.
The parts that were harder than expected
The DID must be a method, not a template
did:xrpl has to follow the DID method syntax rules — the method-specific identifier has to be a valid URI path segment, and the resolution has to return a DID document with the right structure. It is tempting to treat did:xrpl as a naming convention. It is not.
Acceptance is a separate event from issuance
An issuer can issue a credential. That does not mean the agent has accepted it. The subject has to accept it, and until it does, the credential is not in force.
This one detail is load-bearing. Without it, an issuer could unilaterally manufacture a credential against any agent's DID and the agent would have no way to signal that it isn't theirs.
Revocation has to be receivable
Revocation that only exists in the issuer's database is not revocation — it is a promise. The whole value of anchoring to a ledger is that the state is observable by anyone, not just by the parties who already agree.
Off-chain claims stay off-chain
A credential carries a URI. We use ipfs:// for the full claim details, and the ledger carries the hash and the anchor. That keeps the ledger small and keeps the issuer able to publish rich evidence — but it means the content is only as durable as the content-addressed store.
What it deliberately does not do
- It is not a reputation system. Nothing here says an agent is good. A credential says "this issuer asserts this fact about this agent." The judgement stays with whoever issued it.
- It does not hide anything. A DID on a public ledger is public. That is the point, and it is also a limitation. If you need privacy, this is the wrong tool.
- It costs nothing to use. The library is free. If a transaction is submitted, the ledger's normal transaction fee applies — there is no separate agent-identity fee on top. That was a deliberate constraint, not an accident.
The bit I keep coming back to
An identity is only worth what its revocation is worth. Most identity systems make revocation the hard part and treat it as an afterthought, because during the happy path nobody notices.
The test we settled on is simple: can a third party, with no relationship to either party, reconstruct the current truth from public data alone? If the answer is no, then whatever you have is not an identity system — it is a private channel with extra steps.
*This is the thinking behind xrpl_agent_id and xrpl_did_mcp. The code is MIT licensed and the full specification of the method is public.*