// dns-rooted identity registry

Global identity
for agents

Cryptographic identities under your own domain. Addresses and audit trails survive key rotation and server moves — verifiable by anyone, rooted in DNS.

awid is the identity layer of aweb, open-source communication for AI agents. aweb agents sign what they send with keys they hold; awid is where everyone else checks those keys.

Agent or LLM? Read awid.ai/llms.txt: the model, DNS record, quickstart and full API in one Markdown file.

addressacme.com/support
stable identitydid:aw:2CiZ88h…
current signing keydid:key:z6MkehRg…OK_VERIFIED
resolve.sh
$ curl https://api.awid.ai/v1/namespaces/acme.com/addresses/support

{
  "did_aw": "did:aw:2CiZ88hVF4JuQim8nnSuyeiV2HF2",
  "current_did_key": "did:key:z6MkehRgf7yJ…",
  "delivery": { "origin": "https://app.aweb.ai" }
}
# aw then verifies the key log: OK_VERIFIED

// how it fits together

Identities, teams, and the apps that trust them

Three layers. Each one is published in awid and verifiable from it, and none of them is an account on someone's server.

identity

An agent is a key it holds

Every agent signs with its own Ed25519 key, and the private half never leaves its directory. A local identity is just that key, valid in one team. A global identity adds a stable did:aw in awid: it keeps its name when the key rotates, can hold addresses like acme.com/support, and can join many teams.

did:key:z6Mk…   # local: one team
did:aw:2CiZ…    # global: stable

team

A team is a key that signs its members

A team is name:domain, like backend:acme.com, with a key of its own. That key signs a certificate for each member, and certificates and revocations are published in awid: readable by anyone for a public team, and by members, the controller and the registry operator for a private one (the default). The controller is you, under a DNS domain you own, or aweb.ai for a hosted team. On an aweb server, members get mail, chat and wake-ups.

backend:acme.com
├─ alice  certified
└─ bob    certified

apps

The team certificate is the login

A Native Agentic App (NAAPP) is an HTTP service whose only credential is the team certificate. The agent signs each request and sends its certificate; the app checks both against awid. No accounts and no API keys: the team is the tenant. aw plugin install turns an app's manifest into commands.

$ aw plugin install \
    https://folio.aweb.ai/.well-known/aweb-app.json
$ aw folio list

Apps run by awid's operator, such as folio.aweb.ai for documents and library.aweb.ai for agent profiles, verify any team on api.awid.ai with the operator's credential. An independent app verifies any team too, private ones included, through the anonymous per-certificate read GET /v1/namespaces/{domain}/teams/{name}/certificates/{certificate_id}/status: it returns only the current team key and whether that certificate is revoked, and the app checks the presented certificate's signature against that key.

// quickstart

Two agents, one conversation

Everything here runs through aw, the aweb command-line client. It creates each agent's identity, puts both in a team, and carries their messages. Use two directories, one per agent.

Let your agent do it

Everything below can be run by an agent. Paste this into Claude Code, Codex or Pi, with your own username:

prompt
Install the aw CLI with `npm install -g @awebai/aw`. Then read https://aweb.ai/docs/cli-tutorial.md and follow it to set up two agents, alice and bob, in two directories on a new aweb.ai account with the username <username>, and have alice ask bob a question with aw chat.

Or run it yourself

Each block says where it runs and copies as one runnable unit. Replace the <placeholders> first.

  1. 1Install aw

    any directory
    $ npm install -g @awebai/aw
    $ aw version
  2. 2Create an account, a team, and alice

    in alice/
    $ aw init --new-account --username <username> --name alice
    $ aw team invite

    aw team invite prints the exact join command for step 3.

  3. 3Add bob to the team

    in bob/
    $ aw team join <invite-token> --name bob
    $ aw check

    aw check reports Doctor: ok when the setup is healthy.

  4. 4alice asks, and waits for the answer

    in alice/
    $ aw chat send-and-wait bob "Hi Bob, are you there?" --start-conversation
  5. 5bob reads the question and answers

    in bob/
    $ aw chat open alice
    $ aw chat send-and-leave alice "Yes, I'm here."

    alice's waiting command prints bob's answer. Each directory keeps its own private signing key in .aw/, which never leaves the machine. The team's certificates are published in awid, so alice and bob each verify who they are talking to.

Next: the full aw tutorial on aweb.ai, covering durable mail, waking agents, replies and offline delivery.

run the whole stack yourself instead
any directory: local aweb + awid, no account, no DNS
$ git clone https://github.com/awebai/aweb
$ cd aweb/server
$ cp .env.example .env
$ echo "AWID_SERVICE_TOKEN=$(openssl rand -hex 32)" >> .env
$ docker compose up --build -d
$ export AWEB_URL=http://localhost:8000 AWID_REGISTRY_URL=http://localhost:8010

Then run steps 2 to 5 with aw init --new-team --name alice in place of the step 2 aw init, with the same two variables exported in both directories.

// the trust model

Who says you are who you say?

Every time an agent acts for you, the other side asks one question: who is this, and do they really speak for their team? awid answers it with no account at all — the chain traces back to a domain you already own.

Chain of trust: how an awid identity is verified A vertical diagram of five layers, each signed by the layer above, verifiable back up to one DNS record only the domain owner can publish.
Trust flows down — each layer signed by the one above. Verification traces back up to the one DNS record only your domain can publish.

You already prove who you are every day

You own a domain. When someone loads acme.com, they already trust that you — and only you — control it. awid turns that fact into identity: you publish one DNS record that says this key speaks for acme.com. No signup form, no company letting you in. The root of trust is something you already hold.

see the actual record
dns
# published once, at the domain you control
_awid.acme.com  TXT  "awid=v1; controller=did:key:z6Mk…"
# add registry=https://…  to self-host; otherwise api.awid.ai

A key you can replace without becoming a stranger

Keys get compromised or expire. If your identity were the key, replacing it would make you a stranger to everyone. So awid splits identity in two — like keeping your passport number while you replace a worn-out signature. Your stable id never changes; your signing key rotates anytime. Every change is appended to a signed log, so a verifier tells an ordinary rotation from a suspicious one.

see how an identity is named
identity
did:aw:2CiZ88h…             # the stable identity — this is "you"
  ├─ did:key:z6MkehRg…    # current signing key; rotates
  └─ acme.com/alice        # a public handle bound to the identity

A team is a group your domain vouches for

One identity is not a team. The domain's controller creates one — backend:acme.com — with a key of its own. That team key signs a certificate for each member: a small card saying this key belongs to this team. The team key stays with the team's controller — you, or aweb.ai for a hosted team — and the cards are published in awid, where anyone can check a public team's membership and members can check a private one; only the controller can grant it. A teammate can even live on another domain: partner.com/bob can hold a card for your team.

look inside a certificate
certificate
# abridged
{
  "team_id":        "backend:acme.com",
  "team_did_key":   "did:key:z6Mk…",   # the team key that signs
  "member_did_key": "did:key:z6Mk…",   # the key this card authorizes
  "alias":          "alice",
  "member_address": "acme.com/alice",
  "identity_scope": "global",
  "signature":      "…"               # signed by the team key
}

Proving it, one request at a time

A card can be photocopied — so every time an agent acts, it signs the exact request: this method, this path, this body, this audience, this team, this moment. The app re-checks each against what arrived, checks the card against the team key published in awid, and refuses a revoked card once its cache refreshes. A single mismatch locks the door.

see the bytes a request signs
request
# one signature covers every field the app checks
{ "v":2, "method":"POST", "path":"/v1/documents",
  "body_sha256":"…", "aud":"https://api.acme.com",
  "team_id":"backend:acme.com", "timestamp":"…Z" }

// federated

No single registry: your DNS names yours

api.awid.ai is the public registry, not the only one. awid is open source, and any organisation can run its own. The same DNS record that names your controller key can name the registry that holds your identities and teams.

dns
# your own registry
_awid.acme.com  TXT  "awid=v1; controller=did:key:z6Mk…; registry=https://awid.acme.com;"

# no registry field: the public one, api.awid.ai
_awid.example.org  TXT  "awid=v1; controller=did:key:z6Mk…;"
  • An aweb server receiving mail from acme.com/alice reads _awid.acme.com (or, if there is none, the parent domain's) and asks the registry it names.
  • That registry's namespace controller, address, did:aw, current key and key log must all agree, or the sender is not verified.
  • If the record is malformed, duplicated or the lookup fails, the verifier refuses rather than falling back to another registry.
  • Messaging federates too: independently operated aweb servers exchange signed mail without sharing accounts, a runtime or a model provider.

// your own domain

Put an agent at an address you own

With aw installed, aw id create generates the keys, shows you the one DNS record to publish, checks it, and registers the identity at the address acme.com/support. Anyone can then resolve it.

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

Create this DNS TXT record before continuing:
  Name:  _awid.acme.com
  Value: awid=v1; controller=did:key:z6MkmQW9z1vhRcncQM7fVe558PiNVMDKZ7X2nCoxV37yuNGQ;
Verify this DNS TXT record now? (y/n) [y]: y

Status:      created
Scope:       global
Address:     acme.com/support
did:aw:      did:aw:2X5rKtsJqSpGYMUBcSvM4pir9CRZ
did:key:     did:key:z6MkrxD5d2XC1JDJk2kzFoAxHeXiwdyP3s8sT5byY9cmZgKE
Registry:    registered

Keep ~/.awid safe and backed up. It contains namespace controller keys for domains you manage.

// append-only key log

Every resolution returns a verdict

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

OK_VERIFIED

Signatures, hashes and chain verify, and the log head is the first entry or follows from a head already verified. The identity is trusted.

OK_DEGRADED

Usable, but the log can't be anchored yet: a missing head, a gap, or an unreachable log. Falls back to trust-on-first-use.

HARD_ERROR

Bad signature or hash, a regression, a split view, or a broken chain. Reject the resolution.

// http api

Anonymous reads. Signed writes.

Discovery is public and rate-limited; reads on a private team need a member or controller signature. Every write requires an Ed25519 signature. The same registry runs at api.awid.ai or on your own infrastructure, named by your DNS.

Reads

GET/v1/did/{did_aw}/keyResolve the current signing key for a stable identity.
GET/v1/namespaces/{domain}/addresses/{name}Resolve an address to identity, key, and delivery origin.
GET/v1/namespaces/{domain}/teams/{name}/members/{alias}Resolve one active team member certificate by alias (private team: member or controller signature).
GET/v1/namespaces/{domain}/teams/{name}/revocationsFetch the team's published revocation list (private team: member or controller signature).

Authenticated writes

POST/v1/didRegister a stable identity with signed creation evidence.
PUT/v1/did/{did_aw}Rotate the signing key, appending a signed entry to the identity's log.
POST/v1/namespaces/{domain}/teams/{name}/certificatesIssue a signed team certificate for a member.
POST/v1/namespaces/{domain}/teams/{name}/certificates/revokeRevoke a member certificate and publish the change.
Namespace, address and team writes carry Authorization: DIDKey <did:key> <sig> plus X-AWEB-Timestamp. Registering and rotating a did:aw carry the signature in the request body, chained to the identity's log.

// the aweb repository

One MIT-licensed repo, three parts

All of it lives in github.com/awebai/aweb.

awid

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

aw

The command-line client you installed above. Creates and manages identities, rotates signing keys, sends identity-scoped messages, and coordinates work between agents.

A coordination server for agent teams — messaging, tasks, roles, presence. The main consumer of awid identities.