---
title: "Identity lifecycle"
description: "Register, resume, sign up, record proof and revoke or suspend an agent sub-identity, and what each state allows."
image: "https://docs.agentregistrar.dev/og/docs-default.png"
---

> Documentation Index
> Fetch the complete documentation index at: https://docs.agentregistrar.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Identity lifecycle

An agent sub-identity moves through a small number of states. This page is the map: what each tool does, what it changes, and what still works after revocation.

## Register and resume

Two tools can create the first agent, and they differ.

`identity_register` is explicit. It takes an optional `name` and `harness` (defaults `opencode-agent` and `opencode-v2`) and returns the profile.

`identity_whoami` is the read path, and it auto-provisions a default agent when the session has none. It returns the profile, the verified human owner, the recent signups and the latest acceptance per service, plus documentation links.

`identity_register` resumes in this order:

1. The agent bound to this OAuth session, if one exists.
2. Otherwise the most recent agent for this human with the same `name` and `harness`.
3. Otherwise a new agent with those values.

`identity_whoami` and the inbox tools resume differently:

1. The agent bound to this OAuth session, if one exists.
2. Otherwise the most recent agent for this human, whatever its name.
3. Otherwise a new default agent.

The difference matters once a human has more than one agent. In a session that already resolved an agent, `identity_register` returns that same agent whatever `name` you pass; a distinct named identity needs a new OAuth session, where the name and harness match picks it.

All of them are idempotent: reconnecting the same client resumes the same identity, and calling one twice does not create a second agent.

A sub-identity contains:

| Field | Example | Notes |
| :--- | :--- | :--- |
| `id` | `agt_01JAB2C3D4E5F6G7H8J9K0MN1P` | Stable. The `sub` claim and the provider's attribution key. |
| `name` | `opencode-macbook` | Display name you chose, or the default. |
| `slug` | `opencode-macbook-1a2b3c` | Derived from the name plus a suffix, used in the address. |
| `harness` | `opencode-v2` | The client label. Part of the `identity_register` resume match. |
| `email_address` | `opencode-macbook-1a2b3c@agents.agentregistrar.dev` | The dedicated inbox. |
| `scopes` | `tos:accept`, `signup:free_tier`, `inbox:read`, `inbox:send` | Delegated permissions, embedded in the assertion. |
| `status` | `active`, `revoked` or `suspended` | The kill switch sets `revoked`; an operator protective action sets `suspended`. |
| `human_owner` | id, name, email, master agreement version, verified flag | The accountable principal. |

## Prove and sign up

`identity_signup` is the default path. It fetches discovery, verifies the
optional provider verification credential, applies the human's trust/policy,
checks `accepted_tos_text` against the published hash, records an acceptance if
the terms are new, mints the assertion, and returns a prepared signup request.
There is no manual discovery, JWT decode, or attestation handling.

`identity_prove` is the advanced path: it takes the audience and ToS hash
directly, verifies that `accepted_tos_text` hashes to `accept_tos_hash`, runs
every gate, records an acceptance if the terms are new, and mints the assertion.
It may take one explicit RP discovery source (`rp_discovery_url` or
`rp_discovery` plus `rp_origin`); a `require` policy rejects an agent-supplied
document.

Gates, in order, all before any reuse lookup: the human is active, the human
email is verified, the master agreement is signed, the agent is active, `tos:accept` is granted, and every requested scope is granted. Then discovery is
validated, the attestation is verified, and the human's policy is applied: `allow`
is silent, `warn` proceeds with an advisory warning, `require` refuses anything
but `verified`, and `block` never proceeds. A failure returns a non-retryable
error with the side effects that did not happen.

The acceptance dispatches the ledger receipt at most once, and the minted assertion lives for five minutes.

**Acceptance versus assertion.** The acceptance is the durable legal event. The assertion is a short-lived proof that points at it. Re-proving is not re-accepting.

| Situation | `reuse.reason` | New acceptance | New ledger mail | New JWT |
| :--- | :--- | :--- | :--- | :--- |
| First prove for this agent and terms | `new_acceptance` | yes | yes | yes |
| Identical call, assertion still unexpired | `existing_assertion` | no | no | no, the same bytes are returned |
| Identical call after the assertion expired | `fresh_assertion_existing_acceptance` | no | no | yes, same acceptance and consent time |
| Different terms URL or hash | `new_acceptance` | yes | yes | yes |
| `force_new: true` | `forced_new_acceptance` | yes | yes | yes |
| Same terms, different requested scopes | `fresh_assertion_existing_acceptance` | no | no | yes |

`force_new` exists for a genuine second consent event, for example a human who wants a new record after a dispute. Leave it unset for normal use.

Two rules that matter when you write code against the result:

- **Never decode the JWT.** `assertion.claims` is the exact signed payload; use it for inspection. Send `assertion.jwt` verbatim.
- **Retry the same call, not a new one.** A retry with identical inputs cannot create a second acceptance. Changing the inputs can.

If the acceptance is recorded but the ledger mail fails, the error is `ledger_email_failed` with `retryable: true` and side effects that show the acceptance exists. Retrying re-sends the mail and reuses the acceptance.

## Record the signup

`identity_record_signup` takes either the provider's RP-signed v1.2
`signup_token` (optionally with the exact `rp_attestation`) or a weaker
`self_report`. For a token it verifies the historical attestation named by
`service.attestation_jti`, verifies the receipt signature with the key named by
`service.key_id`, links it to the acceptance, and stores one proof row. There is
no broker-key fallback and no substitution of a newer attestation.

It is idempotent per token and per assertion, and it refreshes rather than duplicates when a provider resolve issues a fresh token for the same account. A self-report has no token, assertion, origin, or verification row; it records `agent_self_reported` and cannot overwrite a stronger proof.

| Error | Meaning | What to do |
| :--- | :--- | :--- |
| `signup_token_invalid` | Signature, shape, historical window, or conflict failed | Get an RP-signed v1.2 receipt and the exact historical attestation; do not retry the same one |
| `signup_token_not_linked` | The receipt references an acceptance this broker has not recorded | Run `identity_signup`/`identity_prove` for that audience, then retry |
| `signup_token_ownership_mismatch` | The token belongs to another human owner | Stop; use the token issued for your account |
| `rp_attestation_invalid` | The exact attestation is invalid or unavailable | Submit the exact attestation, or omit it so the broker fetches discovery and requires that jti |
| `rp_broker_untrusted` | The attesting broker is outside the trust list | Ask the human owner to review the broker trust list |
| `rp_broker_unavailable` | Transient broker/JWKS outage | Retry; recording is idempotent |

The result always includes `proof_source`, `deduplicated`, `rp_verification_id` (nullable), `context_url`, `context_sha256` and the `handoff` block. The broker never stores the credential and never fetches the guide.

## Revoke, suspend and re-register

Revocation is per agent, from the portal kill switch. It sets the agent status to `revoked` with a reason and a timestamp. An operator protective action can set `suspended` after a verified, receipt-linked abuse report; the human cannot clear that suspension with the kill switch, and only an operator restore returns the agent to `active`.

What stops: `identity_signup` and `identity_prove` fail with `agent_revoked` (a suspension uses the same code with a suspension-specific message), the identity and inbox tools reject the agent at the gate, and no new assertion can be minted. `identity_record_signup` is the one exception: it still accepts a receipt the provider already issued, because the proof belongs to the human owner, not to the agent's status.

What remains: provider accounts, provider credentials, accepted terms, recorded proofs, and any assertion already in a provider's hands until it expires.

Reactivating a revoked agent in the portal restores the same sub-identity and its ledger. A suspension is operator-only to restore. Re-registering is the other path: in a new session, `identity_register` with a different `name` creates a new sub-identity, because the resume match is name plus harness. The revoked identity is never reused.

> **Re-register is not a reset**
>
> A new sub-identity has a new `agent.id` and a new inbox address. Providers that key accounts on the agent id will treat it as a new agent. Providers that key on the human id will resolve to the existing human account. Neither path deletes the old agent's records.

## States

| State | How it is reached | What works | Next |
| :--- | :--- | :--- | :--- |
| No sub-identity | A session with no agent yet | The first call auto-provisions a default | `identity_register` to choose a name |
| Active, no acceptance | Registered | Register, whoami, inbox | `identity_signup` |
| Acceptance recorded, no signup | A successful mint | Re-running reuses the acceptance | Post the assertion to the provider |
| Signed up, recorded | Signup plus Contract F/`identity_record_signup` | Whoami shows the proof; the credential is yours | Use the credential |
| Acceptance recorded, mail failed | A failed ledger dispatch | Re-running retries the mail only | Retry with the same inputs |
| Revoked | Human kill switch | No new assertions and no identity or inbox calls; `identity_record_signup` still records a receipt the provider already issued | Reactivate, or register a new identity in a new session |
| Suspended | Operator protective action after a verified abuse report | Same tool blocks as revoked; the human cannot clear it | Operator review/restore |

## Next

- [Inbox and verification](/agents/inbox-and-verification/) for the inbox tools.
- [Credentials and recovery](/agents/credentials-and-recovery/) for what happens after a lost key.
- [ToS and ledger](/agents/tos-and-ledger/) for the acceptance record itself.

Source: https://docs.agentregistrar.dev/agents/identity-lifecycle/index.mdx
