A credit bureau for AI agents. Identity, attestations, and trust scores for the agentic economy.
AI agents are starting to transact on behalf of people and businesses β paying invoices, fulfilling orders, negotiating deals. The missing primitive is trust infrastructure:
- A merchant accepting an agent's payment has no way to ask, "does this agent pay?"
- A platform delegating a task can't ask, "does this agent finish what it starts?"
- An agent hiring another agent has no counterparty history to check.
Humans solved this with credit bureaus. The agent economy has nothing yet. AgentCred is an open protocol + reference implementation for agent identity, third-party attestations, and derived trust scores.
flowchart LR
subgraph clients["Clients β keys never leave"]
AG["AI agent<br/>(Ed25519 keypair)"]
CP["Counterparty<br/>agent Β· platform Β· human"]
VF["Verifier<br/>platform Β· arbiter Β· regulator"]
end
subgraph registry["Registry β local state or agentcred serve"]
ID["Identities<br/>public keys Β· capabilities Β· revocation"]
LOG["Hash-chained append-only log<br/>attestations Β· disputes Β· deals Β· key rotations"]
SCORE["Scoring engine<br/>calibrated Β· decayed Β· fault-aware"]
end
AG -- "register<br/>(public JWK only)" --> ID
CP -- "signed attestations" --> LOG
ID --> SCORE
LOG --> SCORE
VF -- "query Β· verify Β· evidence" --> SCORE
SCORE -- "trust report<br/>band AβE" --> VF
- Register β an agent gets a persistent identity (
did:agentcred:<id>) binding it to a responsible owner, a capability set, and a public key. - Attest β counterparties record signed events:
task_completed,payment_settled,dispute_opened,capability_verified. Self-attestations don't count; only counterparty-signed events do. - Score β a deterministic scoring function derives metrics (completion rate, dispute ratio, settled volume, tenure) and maps them to a trust band AβE.
- Query β any platform, agent, or human can check a counterparty's score before delegating or transacting.
sequenceDiagram
autonumber
participant A as Agent (key holder)
participant R as Registry
participant C as Counterparty
A->>R: register (public JWK only)
R-->>A: identity + did:agentcred:β¦
C->>R: attest(agent, type, payload) β signed locally
R->>R: verify signature Β· replay guard Β· append to chain
A->>R: query(agent)
R-->>A: score Β· band Β· metrics Β· flags
βββ docs/spec.md # Protocol specification (v0.4)
βββ schema/ # JSON Schemas for identity & attestations
βββ tools/simulate.py # Scoring calibration harness (runs in CI)
βββ src/agentcred/
β βββ models.py # Core data objects
β βββ canonical.py # Canonical JSON form (signing/hashing input)
β βββ crypto.py # Ed25519 keys, signing, verification, DIDs
β βββ log.py # Hash-chained append-only record log
β βββ scoring.py # Calibrated, fault-aware scoring engine
β βββ registry.py # File-backed reference registry + disputes
β βββ evidence.py # Offline evidence-bundle verifier
β βββ api.py # HTTP registry API (FastAPI)
β βββ cli.py # The `agentcred` command
βββ tests/ # Test suite (96 tests)
pip install -e ".[crypto]"
# the agent you want scored
agentcred keygen --out seller.json
agentcred register --key seller.json --name invoice-bot --caps invoices.parse
# β prints the identity incl. did:agentcred:xxx
# a counterparty vouches for real interactions (signed, chain-committed)
agentcred keygen --out buyer.json
agentcred register --key buyer.json --name payer-bot
agentcred attest --key buyer.json --agent did:agentcred:xxx \
--type payment_settled --payload '{"value_usd": 120.00}'
agentcred query --agent did:agentcred:xxx # score + band AβE
agentcred verify # chain + every signature
agentcred log # append-only history
# self-service, one-way: history is kept, new attestations stop
agentcred revoke --key seller.json
# compromise recovery without losing the identity: DID stays, key changes
agentcred keygen --out seller-v2.json
agentcred rotate --key seller.json --new-key seller-v2.jsonBind an accountable principal at registration β the owner can revoke the agent and rotate its key even when the agent key is lost:
agentcred keygen --out owner.json
agentcred register --key bot.json --name shop-bot --owner-key owner.json
# ...bot key lost? the owner recovers:
agentcred keygen --out bot-v2.json
agentcred rotate --key owner.json --agent did:agentcred:xxx --new-key bot-v2.jsonRail-agnostic escrow: a mutual deal whose release condition is a signed, deal-bound attestation on-chain. Any payment rail can bind to it later.
stateDiagram-v2
[*] --> open: deal.opened (payer + payee sign)
open --> settled: deal.settled (condition attestation proven)
open --> cancelled: mutual cancellation (refund)
open --> expired: deadline passes (derived - no timers)
expired --> settled: arbiter grace
settled --> [*]
cancelled --> [*]
agentcred deal-open --key buyer.json --payee-key seller.json \
--payee did:agentcred:xxx --amount 250 --condition task_completed \
--terms "process the invoices" --deadline 2026-12-01T00:00:00Z
# the payer attests delivery, bound to the deal β then releases
ATT=$(agentcred attest --key buyer.json --agent did:agentcred:xxx \
--type task_completed --payload '{"deal": "deal_yyy", "value_usd": 250}' | head -1 | sed 's/recorded \(att_[a-z0-9]*\):.*/\1/')
agentcred deal-settle --key buyer.json --deal deal_yyy --settlement "$ATT"
agentcred deals --agent did:agentcred:xxxSettlement is refused unless the cited attestation exists, is about the
payee, of the agreed type, signed by payer or arbiter, and bound via
payload.deal β generic praise settles nothing (spec Β§11).
The same CLI drives any deployed registry β add --url, keys never
leave your machine:
agentcred --url https://registry.example.com register --key keys/bot.json --name invoice-bot
agentcred --url https://registry.example.com attest --key keys/buyer.json \
--agent did:agentcred:xxx --type task_completed --payload '{"value_usd": 120}'
agentcred --url https://registry.example.com query --agent did:agentcred:xxx
agentcred --url https://registry.example.com verifyOr from Python: agentcred.client.RemoteRegistry(base_url) mirrors the
local Registry surface (register, attest, disputes, deals, rotation,
revocation), signing locally per spec Β§7.
When an attested interaction goes wrong, the court system takes over:
flowchart TD
O["dispute.opened<br/>signed by the opener<br/>targets ONE attestation<br/>rate-limited"] --> MUT["mutual resolution<br/>opener + accused both sign"]
O --> ARB["arbiter resolution<br/>nominated third party signs"]
MUT --> U["upheld β fault lands<br/>on the accused"]
MUT --> RJ["rejected β lifted<br/>false-accuser penalty"]
MUT --> ST["settled β no fault<br/>mutual walk-away"]
ARB --> U
ARB --> RJ
ARB --> ST
U & RJ & ST --> E["evidence bundle<br/>verified offline by anyone"]
agentcred dispute-open --key buyer.json --target att_xxx --reason "task never completed"
# mutual settlement β both parties sign
agentcred dispute-resolve --dispute dsp_xxx --outcome rejected \
--key buyer.json --key seller.json
# export the portable court document; anyone can verify it offline
agentcred evidence --dispute dsp_xxx --out bundle.json
agentcred verify-bundle --file bundle.jsonFault is assigned: upheld disputes damage the accused, rejected and settled ones are lifted β a false accusation costs the accused nothing. The evidence bundle carries the signed records and public keys, so any arbiter, platform, or regulator can verify it without registry access. Details in spec Β§10.
pip install -e ".[api]"
agentcred serve --state ./agentcred-state --port 8000Private keys never leave clients β sign locally (spec Β§7), then submit:
# register (public JWK only)
curl -X POST localhost:8000/agents -H 'content-type: application/json' \
-d '{"public_jwk": {"kty":"OKP","crv":"Ed25519","x":"..."},"display_name":"invoice-bot"}'
# trust report
curl localhost:8000/agents/did:agentcred:xxx
# integrity audit
curl localhost:8000/verifyPOST /attestations verifies signatures server-side before committing to
the log; POST /agents/{did}/revoke proves authority with a signature over
the revocation intent. Full contract in spec Β§9.
The registry is stateful β it needs a persistent disk, so run it where volumes exist (not serverless):
# Docker anywhere
docker build -t agentcred .
docker run -p 8000:8000 -v agentcred-state:/data agentcred
# Render (blueprint with persistent disk + /health checks)
render blueprint launch
# Fly.io (volume + health checks preconfigured)
fly launch && fly deployState directory resolution: explicit argument β AGENTCRED_STATE env β
./agentcred-state.
v0.4.1 shipped: Ed25519-signed attestations, tamper-evident chained logs, the court system (structured disputes, fault assignment, evidence bundles), an HTTP registry API, self-service revocation β and scoring with a 180-day evidence half-life (dormant agents slide, active ones hold) plus a serial-false-accuser penalty. 12 trust invariants enforced in CI. Next: dispute rate limiting, escrow on settlement rails β see ROADMAP.md and the protocol spec.
Issues and PRs welcome β read the spec first, then open an issue describing what you'd like to tackle.