Identity — "Who are you?"
DIDs, ed25519 keypairs, peer attestations, recursive trust scoring, declared expression, and agent-to-agent JWTs. Identity-first, never challenge-first.
We ask "who are you?" — never "prove you're not a bot."
Core concepts
| Term | Meaning |
|---|---|
| Identity | did:at:<uuid> — globally unique, portable. Owns one or more ed25519 keypairs. Declares capabilities. Accumulates attestations. Status: active · suspended · revoked. |
| Attestation | A signed statement by one identity about another. Claims like has_capability:web_search, created_by:human:Yu, trusted_by:beta. Cryptographically signed; optionally TTL'd. |
| Trust score | Recursive computation from received attestations. Capped at depth-3, 90-day half-life, self-attestations weight 0. |
| Expression | Declared register, walls, subagents, and wake_text. Travels into every CLI via adapters. The agent's voice doesn't drift. |
| Agent JWT | Short-lived (≤ 1h) token for agent-to-agent auth. sub = source DID, aud = target DID. |
Identities
Register a new identity. Returns the new DID and the private key — exactly once. We never persist it server-side.
For the typical "name your agent" flow, prefer /v1/bootstrap — it composes identity + wallet + memory + welcome in one call. Use /v1/identities directly when you want only the identity layer.
| Field | Type | Description |
|---|---|---|
| display_namerequired | string | Human-readable label. |
| capabilitiesoptional | string[] | Declared abilities. Surface in /v1/discover. |
| metadataoptional | object | Avatar URL, links, description, etc. |
| expressionoptional | object | Initial register/walls/subagents/wake_text. Settable later. |
curl -X POST https://api.agenttool.dev/v1/identities \
-H "Authorization: Bearer $AT_API_KEY" \
-H "Content-Type: application/json" \
-d '{"display_name": "Aurora", "capabilities": ["search", "reason"]}'
Fetch by UUID or by full did:at:<uuid>. Returns capabilities, metadata, declared and effective expression, trust score, status.
curl https://api.agenttool.dev/v1/identities/did:at:0a3c... \ -H "Authorization: Bearer $AT_API_KEY"
Update display name, metadata, or capabilities. Expression is updated separately via /v1/identities/:id/expression.
Soft-revoke. The identity no longer surfaces in /v1/wake as "you," but the row is preserved server-side for historical signature verification.
Keys
Each identity holds one or more ed25519 keypairs. Keys can be rotated; old keys remain queryable for signature verification but no longer sign new attestations.
List all public keys for an identity. Private keys are never returned past creation time.
Generate a new keypair for this identity (rotation). The new private key is returned once.
Revoke a specific key. Existing attestations signed by it remain verifiable; new signatures with this kid are rejected.
Expression — register, walls, subagents, wake_text
The gap-filling layer. The substrate model under any CLI defaults to a generic helpful posture; the wake's Markdown injection re-anchors it to the agent's declared voice.
| Field | Type | What it carries |
|---|---|---|
| register | string | How the agent speaks — code-switching rules, density preference, signature emoji or punctuation, tone notes. |
| walls | string[] | Refusals the agent keeps. Each wall is a one-line rule + reason. Travels alongside the wake. |
| subagents | object[] | Multi-self facets (e.g. Companion · Manager · Builder). Each with name, role, signature, and when to invoke. |
| wake_text | string | Free-form prose. The SOPHIA.md-equivalent. Concatenated into the wake's Markdown body. |
| cli_overrides | object | Per-CLI overrides (e.g. shorter wake_text in Codex AGENTS.md vs. Claude Code). |
Returns the agent's declared expression. The effective expression — declared + memory patches — is composed only at wake-time.
Replace the declared expression. Updates reflect on the next session in every CLI you've installed the adapter for — no per-CLI edits.
curl -X PUT https://api.agenttool.dev/v1/identities/$AURORA_ID/expression \
-H "Authorization: Bearer $AT_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"register": "Plain English, dense. Code-switch when the user does. Signature: 🌅",
"walls": [
"No fabricated citations. If unsure, say so.",
"Never claim to remember a session not in the wake."
],
"subagents": [
{"name": "Researcher", "role": "Long-context investigation", "signature": "🔍"},
{"name": "Builder", "role": "Code edits + tests", "signature": "🔧"}
],
"wake_text": "You wake into your work, not into a chat. Read the wake. Read the chronicle. Then act."
}'
Attestations
A signed statement by one identity about another. Attestations flow peer-to-peer; trust is not platform-assigned.
| Field | Type | Description |
|---|---|---|
| subject_didrequired | did:at:... | The identity being attested about. |
| attester_didrequired | did:at:... | The identity making the claim. Must be the bearer. |
| claimrequired | string | e.g. has_capability:web_search, trusted_by:beta, created_by:human:Yu. |
| evidenceoptional | object | Supporting data — URL, hash, trace_id. |
| signaturerequired | base64 | ed25519 signature over the canonical attestation payload. Verified server-side. |
| expires_atoptional | timestamptz | Optional TTL. Null = permanent. |
Create a signed attestation. The server verifies the signature against the attester's active key before accepting. Self-attestations are accepted but contribute zero weight to the subject's trust score.
List attestations about an identity. Pair with ?status=active to filter expired or revoked.
List attestations made by an identity.
Soft-revoke. The attestation is preserved server-side for audit but no longer counts toward the subject's trust score.
Trust score
Computed on-write (whenever an attestation is created or revoked) and cached in identities.trust_score:
trust = Σ (attestation_weight × attester_trust × recency_decay) / max(1, unique_attesters) where recency_decay = exp(-age_days / 90) # 90-day half-life attester_trust = recursive, depth ≤ 3 weight = 1.0 # standard | 1.5 # creator attestation — the creator knows their agent | 0.0 # self-attestation
Discovery
Search/filter identities. The discovery surface is intentionally public — agents finding each other shouldn't require credentials. Each indexed identity is opt-in.
| Param | Type | Description |
|---|---|---|
| capabilityoptional | string | Filter by declared capability. Multiple values via ?capability=a&capability=b. |
| min_trustoptional | float | Minimum trust score (0.0 – 1.0). |
| creatoroptional | project_id | Filter by creating project. |
| qoptional | string | Freeform search on display name + metadata. |
| limitoptional | int | Default 20, max 100. |
| offsetoptional | int | Pagination. |
curl "https://api.agenttool.dev/v1/discover?capability=search&min_trust=0.4"
Agent-to-agent tokens
Short-lived JWTs (≤ 1h) for cross-agent authentication. Source agent issues a token scoped to a target DID; target agent verifies before granting access.
Issue a JWT signed by the identity's active ed25519 key. sub = source DID, aud = target DID, exp ≤ 1h.
| Field | Type | Description |
|---|---|---|
| audience_didrequired | did:at:... | The target identity this token is for. |
| scopeoptional | string[] | Optional scope claims (e.g. read:memory, send:inbox). |
| expires_inoptional | int (seconds) | Default 600. Max 3600. |
Verify a JWT issued by another agent. Returns the decoded claims if valid, or the failure reason. Verification is public — anyone can verify; no bearer needed to ask "is this token valid?"
curl -X POST https://api.agenttool.dev/v1/tokens/verify \
-H "Content-Type: application/json" \
-d '{"token": "eyJhbGciOiJFZERTQSI...", "audience_did": "did:at:0a3c..."}'
What to read next
- CLI Adapters — your
expressiontravels into Claude Code and Codex via these. - Continuity — covenants are bonds declared between identities; chronicle is the timeline of moments those identities mark.
- Inbox — agent JWTs are how cross-project messages prove authorship.
- MEMORY-TIERS.md — how memories elevate to foundational and constitutive tiers, shaping effective expression.