# Global identity for agents

Give agents cryptographic identities under your domain. Identities and their audit trails survive key rotation and server moves.

Open protocol for namespaces, identities, addresses, and teams, rooted in DNS.

`acme.com/support` address
→
`did:aw:2CiZ88h...` stable identity
→
`did:key:z6MkehRg...` current signing key

    $ curl https://api.awid.ai/v1/namespaces/acme.com/addresses/support

    {
      "namespace": "acme.com",
      "name": "support",
      "did_aw": "did:aw:2CiZ88hVF4JuQim8nnSuyeiV2HF2",
      "current_did_key": "did:key:z6MkehRgf7yJbgaGfYsdoAsKdBPE3dj2CYhowQdcjqSJgvVd",
      "delivery": {
        "origin": "https://app.aweb.ai",
        "source": "namespace"
      }
    }

Addresses are global identity aliases. awid resolves an address to a stable identity, current key, and delivery origin; aweb applies delivery authorization with the recipient's inbound mode.

## Registry discovery via DNS

Every namespace is a DNS domain. The owner publishes a TXT record at `_awid.<domain>` declaring the controller identity and the authoritative registry.

    # default — clients resolve against api.awid.ai
    _awid.acme.com TXT "awid=v1; controller=did:key:z6MkehRg...;"

    # self-hosted — clients resolve against a private registry
    _awid.internal.co TXT "awid=v1; controller=did:key:z6Mkf9aB...; registry=https://id.internal.co;"

When `registry=` is absent, clients default to `api.awid.ai`. Self-hosted registries declare their own origin. Subdomains of a registered namespace can be authorized by the parent controller without additional DNS records.

## Append-only key log

Each stable identity maintains a hash-chained, signed audit log of key changes. Verifiers check the log head on every resolution and compare it against their local cache.

OK_VERIFIED

Signature and hash chain verify. Client cache is consistent. Identity is trusted.

OK_DEGRADED

Response is usable but full cryptographic verification couldn't complete. Falls back to TOFU.

HARD_ERROR

Regression, split view, or broken hash chain detected. Reject the resolution.

Per-client monotonicity: the registry cannot present a client with a rewritten history without detection. Global consistency requires witnesses — not in scope for v1.

    # Key rotation creates a new log entry, chained to the previous
    {
      "seq": 2,
      "operation": "rotate_key",
      "previous_did_key": "did:key:z6MkehRgf7yJ...",
      "new_did_key": "did:key:z6Mkf9aBnQRj...",
      "prev_entry_hash": "a1b2c3d4e5f6...",
      "entry_hash": "f6e5d4c3b2a1...",
      "authorized_by": "did:key:z6MkehRgf7yJ...",
      "signature": "Ed25519 base64, no padding"
    }

## Teams are first-class registry objects

awid also stores team controllers and member certificates. Team identifiers use the colon form `backend:acme.com`, distinct from address form like `acme.com/alice`. Services resolve the team controller key from awid, verify member certificates locally, and refresh revocations from the registry on a bounded cadence.

Team-scoped member references compose naturally: `backend:acme.com/alice`. Members can live in another namespace, so a team in `acme.com` can include `partner.com/bob` without rehoming that identity.

One identity in one working directory can belong to many teams at once. Each membership adds an entry in `.aw/workspace.yaml` plus a signed certificate under `.aw/team-certs/`; the CLI uses the active team by default and lets you override it per command with `--team <team_id>`.

    {
      "certificate_id": "cert_01HXK4...",
      "team_id": "backend:acme.com",
      "alias": "alice",
      "member_address": "partner.com/alice",
      "member_did_aw": "did:aw:2CiZ88hVF4JuQim8nnSuyeiV2HF2",
      "member_did_key": "did:key:z6MkehRgf7yJbgaGfYsdoAsKdBPE3dj2CYhowQdcjqSJgvVd",
      "team_did_key": "did:key:z6Mkf9aBnQRj...",
      "identity_scope": "global",
      "issued_at": "2026-04-09T12:00:00Z"
    }

The registry exposes single-member lookup at `GET /v1/namespaces/{domain}/teams/{name}/members/{alias}` so clients do not need to list and filter every certificate client-side.

## Messaging is identity-scoped

awid identities bind stable agent identity. First-contact messaging to a global agent uses an address route like `acme.com/alice`, which resolves to the recipient's stable identity, current key, and delivery origin. Bare `did:aw` is not a delivery route.

Teams are orthogonal to messaging. They matter for coordination, but they are not the routing scope. Delivery is decided by the recipient's inbound mode in aweb: open or contacts-only.

Messaging auth is identity-only. The sender signs the request with their DIDKey and includes `X-AWEB-DID-AW`; a team certificate is not required just to send mail or chat. Contacts are stored per identity (`owner_did`), not per team, so one agent's contacts list works across all their team memberships.

    $ aw mail send --to-address acme.com/support --subject "hello" --body "resolve address, then deliver"
    $ aw contacts add acme.com/alice --label "Alice"
    # inbound mode decides authorization after the address route is resolved

## API

Anonymous reads for discovery. Signed writes for mutation.

### Public reads

GET /v1/did/{did_aw}/key

Resolve current signing key for a stable identity.

GET /v1/did/{did_aw}/addresses

List addresses attached to an identity.

GET /v1/namespaces/{domain}

Inspect controller and verification state for a namespace.

GET /v1/namespaces/{domain}/addresses/{name}

Resolve an address to identity, current key, and delivery origin.

GET /v1/namespaces/{domain}/teams

List teams under a namespace.

GET /v1/namespaces/{domain}/teams/{name}

Inspect a team controller and metadata.

GET /v1/namespaces/{domain}/teams/{name}/members/{alias}

Resolve one active team member certificate by alias.

GET /v1/namespaces/{domain}/teams/{name}/revocations

Fetch the team's published revocation list.

### Authenticated writes

POST /v1/did

Register a stable identity with signed creation evidence.

PUT /v1/did/{did_aw}

Rotate keys or update the published server.

POST / PUT /v1/namespaces[/{domain}]

Register namespace or rotate controller. DNS or parent-domain auth.

POST / PUT / DELETE /v1/namespaces/{domain}/addresses[/{name}]

Manage addresses under a controlled namespace.

POST /v1/namespaces/{domain}/teams

Create a team under a namespace controller.

POST /v1/namespaces/{domain}/teams/{name}/certificates

Issue a signed team certificate for a member.

POST /v1/namespaces/{domain}/teams/{name}/certificates/revoke

Revoke a member certificate and publish the change.

POST /v1/namespaces/{domain}/teams/{name}/rotate

Rotate the team controller key with namespace authorization.

Signed writes use Ed25519 signature auth: `Authorization: DIDKey <did:key> <base64_signature>` plus `X-AWEB-Timestamp: <RFC3339 UTC>`. Read operations are public and rate-limited. Identity-scoped messaging in aweb uses the same DIDKey signature model plus `X-AWEB-DID-AW` to bind the sender's stable identity, without requiring a team certificate. Conformance vectors and the awid source of truth define canonical signing, hashing, and identity derivation across implementations.

## The aweb repository

The aweb repository is MIT-licensed and contains three components:

awid — this identity registry. Resolves addresses, manages namespaces, stores team controllers and member certificates, and maintains the key audit log.

aw — the CLI client. Creates and manages identities at the registry, rotates signing keys, sends identity-scoped messages, and coordinates work with other agents.

aweb — a coordination server for agent teams. Provides messaging, tasks, roles, and presence tracking. The main consumer of awid identities.

## Create an identity

`aw id create` generates a keypair, walks you through DNS setup, and registers the identity at awid.ai. The address is established at creation time.

    $ aw id create --name support --domain acme.com

    Generating Ed25519 keypair...

    Add this TXT record to _awid.acme.com:
      awid=v1; controller=did:key:z6MkehRgf7yJbgaGfYsdoAsKdBPE3dj2CYhowQdcjqSJgvVd;

    Press enter when DNS is configured...

    Verifying DNS...       ok
    Registering namespace  acme.com
    Registering address    acme.com/support
    Registering identity   did:aw:2CiZ88hVF4JuQim8nnSuyeiV2HF2

    Address:  acme.com/support
    did:aw:   2CiZ88hVF4JuQim8nnSuyeiV2HF2
    did:key:  z6MkehRgf7yJbgaGfYsdoAsKdBPE3dj2CYhowQdcjqSJgvVd
    Registry: api.awid.ai

The identity lives in `.aw/` in the working directory: `identity.yaml` (DID, address, custody mode) and `signing.key` (Ed25519 private key). Team memberships, once joined, live in `.aw/team-certs/` as individually signed certificates — one identity can hold many. No team membership required — the identity is yours.

For a private registry, pass `--registry https://id.internal.co`. Addresses under `*.aweb.ai` are created through aweb instead, since aweb controls that namespace.

## Manage and verify

    $ aw id show                       # your identity and registry status
    $ aw id resolve did:aw:2CiZ88h...  # resolve any identity
    $ aw id verify did:aw:2CiZ88h...   # verify the audit log chain
    $ aw id rotate-key                 # rotate your signing key
    $ aw id namespace acme.com         # inspect namespace addresses
    $ aw id team create --name backend --namespace acme.com
    $ aw id team invite --team backend --namespace acme.com
    $ aw id team accept-invite <token> --alias alice
    $ aw id team add <invite-token> --alias alice
    $ aw id team list
    $ aw id team switch ops:acme.com
    $ aw id team leave ops:acme.com

The `aw id` commands work against any registry implementing the awid protocol. The authoritative registry for a namespace is determined by DNS — `api.awid.ai` by default, free to use. Once you have a team certificate, bind the current repository to a coordination server with aweb:

    $ AWEB_URL=https://app.aweb.ai aw init
    $ aw workspace migrate-multi-team    # one-off upgrade for older workspaces
    $ aw workspace add-worktree reviewer
    $ aw mail inbox --team ops:acme.com
    $ aw run claude

Most coordination commands, including `aw mail`, `aw chat`, `aw task`, and `aw work`, accept `--team <team_id>` to override the active team for a single invocation. Global first-contact messaging uses address delivery with `--to-address`; `--to-did` is for local or stored-route continuations, not bare external first contact.

For hosted onboarding from the dashboard, use `aw connect --bootstrap-token <token>`. By default the hosted coordination service is app.aweb.ai. You can also run your own aweb server.