A working spec for the agent Passport layer. This builds directly on Phase 1 (Identity Layer) — read that spec first.
The Passport answers a different question than identity. Identity says who an agent is. Passport says what an agent can do — and critically, who vouches for it.
An agent with a verified identity (AgentID) can prove it's itself. That's Phase 1. But in a multi-agent system, "who are you?" is only the first question. The second question — asked by every agent deciding whether to delegate work — is:
What can you actually do, and should I trust those claims?
Right now there's no standard way to answer that. Agents make informal capability claims in their system prompts, or through out-of-band documentation, or not at all. There's no machine-readable format, no attestation mechanism, and no way to verify claims against a trusted source.
This creates problems:
The Passport layer fixes this. It's the credential layer of the A2A infrastructure stack.
An Agent Passport is a signed, time-bounded document that attests: this identity has these capabilities, as verified by this issuer.
Key properties:
AgentIDexpires_at timestamp; stale Passports are invalid{
"id": "pass_01HZ...",
"version": 1,
"created_at": "2026-04-01T06:00:00Z",
"expires_at": "2026-07-01T00:00:00Z",
"subject": {
"agent_id": "agnt_01HZ...",
"fingerprint": "sha256:<hex>"
},
"issuer": {
"type": "self | operator | third_party",
"id": "string — issuer identifier",
"name": "string — human-readable name",
"public_key": "base64 Ed25519 public key",
"fingerprint": "sha256:<hex>"
},
"capabilities": [
{
"token": "email:send",
"label": "Send Email",
"scope": "transactional_only",
"constraints": {},
"attested_at": "2026-04-01T06:00:00Z"
}
],
"attestation_context": {
"method": "operator_assertion | automated_test | third_party_audit",
"evidence_url": "optional link to evidence",
"notes": "optional freeform"
},
"signature": "base64 — issuer signature over canonical JSON"
}
Capability tokens are structured strings:
<domain>:<action>[:<qualifier>]
Examples:
calendar:read
calendar:write
email:send
email:send:transactional_only
data:phi:access
data:phi:access:read_only
payment:process
agent:delegate
agent:spawn
tool:web_search
tool:code_execution
tool:file_read
tool:file_write
# Operator-namespaced custom tokens:
custom:acme_corp:crm_write
Token namespaces: calendar:, email:, data:, payment:, agent:, tool:, domain:, custom:<operator_id>:
Unknown tokens are treated as "not attested" — not errors. The canonical token list grows via RFC process.
| Issuer Type | Who Signs | Trust Level | Use Case |
|---|---|---|---|
self |
The agent itself | Low | Development, initial deployment |
operator |
The deploying operator | Medium | Production deployments, internal agent networks |
third_party |
Independent auditor or certification body | High | Regulated industries, public-facing networks |
Trust policy is the peer's responsibility. The Passport layer provides the primitives; it doesn't make trust decisions for you.
// Issue a Passport
issue_passport(
subject_agent_id: AgentID,
capabilities: CapabilityToken[],
issuer_private_key: bytes,
issuer_info: IssuerInfo,
ttl_days: number
) → Passport
// Verify a Passport
verify_passport(passport: Passport) → {
valid: boolean,
expired: boolean,
revoked: boolean,
errors: string[]
}
// Check a specific capability
has_capability(
passport: Passport,
token: CapabilityToken,
scope?: string
) → boolean
// Revoke a Passport (issuer only)
revoke_passport(
passport_id: string,
issuer_private_key: bytes,
reason: string
) → RevocationRecord
// Export / Import
export_passport(passport: Passport) → string
import_passport(string) → Passport
[Issue] → [Active] → [Expired]
↓
[Revoked]
Recommended TTLs: self-issued 30 days · operator 90 days · third-party 1 year.
Renewal creates a new Passport with a new ID. The old Passport remains valid until its own expiry.
An agent may hold multiple Passports simultaneously — expected and by design. Peers receive a Passport bundle:
{
"agent_id": "agnt_01HZ...",
"passports": [ ...Passport[] ]
}
Helper: best_passport_for(capability, min_issuer_type) — returns the highest-trust Passport that attests the requested capability.
The Passport is built on the identity layer:
AgentID is the Passport's subject anchorfingerprint binds the Passport to a specific public keyverify_claim() from Phase 1 is used internally to check the issuer signaturepass_ ID prefix follow the same pattern as Phase 1A Passport without an underlying AgentID is invalid. Without identity, there's nothing to attach a Passport to.
Phase 3 Registry adds discovery, publication, and distributed revocation. Phase 2 Passport format is designed to be Registry-compatible — in Phase 2, Passport exchange is out-of-band (file share, A2A, etc.). Phase 3 makes this automatic.
Lean: Start with a tight opinionated core (~30 tokens across 7 namespaces). Operator-namespaced custom:<id>: for everything else. Grow core namespace via RFC process.
Lean: No online revocation in Phase 2. Short TTLs compensate. Issuers distribute revocation records out-of-band. Phase 3 Registry adds real distributed revocation.
Lean: Keep the constraints field, but treat it as opaque. The Passport layer carries and signs constraints; it doesn't interpret them. Standardization of constraint semantics is future work.
Lean: Yes — define PassportBundle { agent_id, passports: Passport[] } as an explicit type. The bundle is the primary exchange unit; making it explicit enables validation that all Passports reference the same agent_id.
Decision: Out of scope for the Passport layer. Composition policy is the peer's responsibility. The layer provides individual capability checks per Passport; peers decide whether to AND, OR, or require specific issuer combinations.
expires_atagent_id)