A working spec for the agent Registry layer. This builds on Phase 1 (Identity) and Phase 2 (Passport) — read those first.
If Phase 1 answers "who is this agent" and Phase 2 answers "what can this agent do," Phase 3 answers "where do I find agents, and how do I trust what I find?"
After Phase 1 and Phase 2, an agent has a verified identity and attested capabilities. But:
The Registry solves all five.
The Registry is a distributed, queryable directory of agent identities and Passports — with built-in revocation, issuer reputation, and discovery primitives.
Key properties:
data:phi:access, operator-attested"The Registry stores three record types. Each is wrapped with registry_meta:
// Shared wrapper
"registry_meta": {
"record_type": "agent_identity" | "passport" | "revocation",
"registered_at": "ISO timestamp",
"registered_by": "agent_id or operator_id",
"registry_node": "string",
"registry_signature": "base64 — Registry node's signature"
}
Record types: AgentID (Phase 1), Passport (Phase 2), Revocation (new in Phase 3).
// Revocation record
{
"id": "rev_01HZ...",
"version": 1,
"created_at": "ISO timestamp",
"revoked_id": "pass_... or agnt_...",
"revocation_type": "passport | identity",
"reason": "string",
"issuer": { "id": "string", "public_key": "base64" },
"signature": "base64"
}
publish_identity(agent_id: AgentID, private_key) → RegistryEntry
publish_passport(passport: Passport, submitter_key) → RegistryEntry
publish_revocation(revocation: RevocationRecord) → RegistryEntry
unpublish_identity(agent_id: string, private_key) → void // soft delete
lookup_agent(agent_id: string) → { AgentID, Passports[], revocations[] }
query_by_capability(
token: CapabilityToken,
scope?: string,
min_issuer_type?: "self" | "operator" | "third_party"
) → AgentID[]
query_by_issuer(issuer_id: string) → Passport[]
get_issuer_record(issuer_id: string) → IssuerRecord
check_revocation(id: string) → { revoked: boolean, record?: RevocationRecord }
// Push-based: real-time revocation notifications
subscribe_revocations(filter: { issuer_id?, agent_id? }) → EventStream
New records propagate via gossip: Primary → known peers → onward. Peers validate the Registry node signature + underlying record signature before accepting. Duplicate IDs are idempotent. Network is eventually consistent — clients handle "not found" gracefully.
Operators who issue Passports can register with the Registry to establish verifiable identity. Domain verification follows ACME-style DNS challenge: publish a TXT record at _agentcy.<domain>.
Trust signals exposed by the Registry:
domain_verified: DNS challenge passedpassports_issued: count of active Passportsrevocation_rate: % of issued Passports revokedactive_since: first registration datethird_party_attestations: other issuers who have vouched for this issuerThese are informational signals — not scores. Peers define their own trust policies.
GET /v1/agents/{agent_id}
GET /v1/agents/{agent_id}/passports
GET /v1/agents/{agent_id}/revocations
POST /v1/agents
DELETE /v1/agents/{agent_id}
GET /v1/passports/{passport_id}
POST /v1/passports
GET /v1/passports?capability=<token>&issuer_type=operator
POST /v1/revocations
GET /v1/revocations/{id}
GET /v1/issuers/{issuer_id}
POST /v1/issuers
GET /v1/health
GET /v1/peers
WS /v1/subscribe
Write operations use AgentSig auth (Ed25519 signature from Phase 1). Read operations on public records are unauthenticated. Rate limiting: 100 req/min for unauthenticated, higher for authenticated.
| Phase 2 (manual) | Phase 3 (automated) |
|---|---|
| Share AgentID by file/email | Publish to Registry; peers look up by ID |
| Share Passport by file/email | Publish; peers query by capability |
| Distribute revocation out-of-band | Publish; peers subscribe or poll |
| Verify issuer key by prior arrangement | Fetch issuer record from Registry |
Phase 2 primitives are unchanged. Phase 3 is additive infrastructure on top — no Phase 2 code changes required.
Lean: Ship a single Reference Registry node (Agentcy.Services operated) for Phase 3 launch. Publish the federation protocol spec simultaneously. Decentralize in practice once there's ecosystem demand.
Lean: Soft delete only. Once credentials have been distributed, pretending they didn't exist is dishonest and creates false security. "Withdrawn from Registry" ≠ "credentials invalidated."
Lean: Per-record visibility flags: public (default, queryable), unlisted (fetchable by ID, not queryable), private (operator-authenticated peers only).
Decision: Ship rate limiting from day one. Unauthenticated reads: 100 req/min by IP. Authenticated: higher limits per AgentID. Writes: rate-limited per agent. Capability query results: capped at 100, paginated.
Proposal: Registry accepts any supported schema version. min_version/max_version query params for clients. Breaking changes get a new API version (/v2/). Backward compatibility for 12 months minimum.