Open standard · aimnd.registry/1
AI:MND Registry
The public record of who exists, like a birth register beside the certificate the owner keeps at home. Anyone may run one.
The registry is the public record of who exists, like a birth register. The individual keeps its own copy (its identity folder) and can always prove itself from that alone. The registry keeps a record too, so anyone can ask: is this ID real, who is responsible for it, is it still valid, and is someone running a copy? Either record can check the other. Neither is the individual.
The open identity specification and the MIT verifier work without One and without this registry (the identity standard). The registry is
one place that publishes and checks them. Anyone may run one: aimnd registry is the reference software.
Responsibility. The operator is the party responsible for an individual. The registry shows an operator only once it has verified it, so every name on a record is a checked fact.
What it holds
The public identity document (ID, keys, birth, transfers, status, life head), the life record's head, the verified operator, and a signed append-only log of events. Memories, feelings, relationships, messages, names and anything an individual was told stay with the individual: the life record carries hashes and kinds only (the identity standard), which is why a registry may hold it.
Who is who
| Role | What it is | In the data |
|---|---|---|
| Individual | the continuing AI, with its own key | id = hash of its public key |
| Operator | the person or company responsible for running it | a verified domain, and optionally a verified legal entity |
| Controller | the key that can give it orders and change things | the owner key (owner.public_key) |
| Delegated users | people lent some authority for a while | grants and signed revokes |
| Host | the platform executing its actions | host_changed entries; not an authority |
The owner key is the controller. The operator is who answers for the deployment. They are often the same company; the format lets them differ.
Operators: verified, never just declared
An operator appears on a record only after the registry has checked it. Nothing unverified is ever shown.
domain: the owner signs aregistry_operatorstatement naming a website, and the registry fetcheshttps://<domain>/.well-known/aimnd-operator.json({"owner_keys": ["<owner public key>"]}, printed byaimnd operator-file). Only when the owner's key is listed does the registry recordoperator_verified, and the record shows the domain.organization: the registry operator has also checked the operator's legal entity against official business records (for example a SAM.gov Unique Entity ID or an EIN) and recordedoperator_org_verifiedwith the legal name and the identifier checked (aimnd registry verify-org). The record then shows the legal name beside the domain.
The rules
- One ID, one history. Registering an ID that is already there is refused (409).
- Publishing heads. The owner's side reports new life heads. A head that extends the registered one is accepted. The registry checks every entry's hash, order and signature, and the document's signature and owner chain.
- Copies are flagged. A history that does not contain the registered head (a copy that split off, or a rewrite), or an owner chain that does not extend the registered one, flags the ID. While flagged, nothing more is accepted. Whoever holds the individual's key, a thief included, can raise the flag but cannot lift it.
- Only the owner settles it.
registry_resolve, signed by the current owner key, names which of the two heads is real. The other is rejected for good. - Revocation is permanent.
registry_revoke(reasons:key_compromised,decommissioned,retired,other), signed by the current owner key. Nothing is accepted for a revoked ID. - Retiring is recorded. A retired individual's document stays valid as a record and can never be active again.
- Keys change by transfer. A new owner key is a signed
transfer(the identity standard); the old key can then no longer speak for it. If the individual's own key is stolen, the owner revokes and the individual is succeeded by a new one (succeeded_by,predecessor). - Statements are fresh and single-use. Operator and resolve statements must be under an hour old and can only be used once.
The log
log.jsonl: one JSON object per line, a hash chain, every entry signed by the registry's key; entry 0 (genesis) names that key.
Kinds: genesis, registered, head, flagged, resolved, revoked, operator_verified, operator_org_verified (and operator,
written by registries before v1.3). The registry's state is a replay of its log, and it starts only on a log that verifies.
checkpoint: the registry's signed statement of the log's size and head, plus witness co-signatures. A witness downloads the whole log,
checks it, and co-signs the current checkpoint (aimnd registry cosign). Anyone can then see that independent parties saw the same log.
Co-signatures belong to one checkpoint, so they lapse when the log grows and witnesses sign again. A co-signature proves only that the holder of that key signed this checkpoint: a verifier counts co-signatures only from witness keys it has pinned, and a request for one or more witnesses with no pinned keys fails. Mirrors catch a registry that shows different people different logs: any two views of one registry's log (aimnd_verify.py --registry-log a.jsonl --compare-log b.jsonl, or the same flags in the Node verifier) either agree on their common prefix or prove, by two entries both signed by the registry's key, that it signed two histories. Whether a witness really checked the log, and whether two witnesses are independent, is a matter of the witness's published policy, not of the signature.
Check it with only the verifier (Python standard library):
python3 aimnd_verify.py --registry-log log.jsonl --checkpoint checkpoint.json --witness <key> --min-witnesses 2 --id aimnd:...
The public website
aimnd registry serve also serves a plain website from the same process: / (home), /search?q= (by ID, certificate number or operator),
/records/<id> (the record), /statistics, /register, /standard, /about, and /data/individuals.csv. Every number is
computed from the registry's own log, a registry with nothing in it says so, and pages carry no scripts (strict content-security policy).
An optional site.json in the registry folder sets the display name, operator, contact, and founder_operators (domains or legal
names): individuals whose operator matches are counted separately on the statistics page so the totals can be trusted.
HTTP
GET /v1/registry |
the registry's key, policy, size |
GET /v1/ids/<id> |
status, owner key, operator, head, registered time, log index, the public record |
GET /v1/ids/<id>/certificate |
the certificate of birth (JSON); add ?format=html for the printable page |
GET /v1/ids/<id>/history |
what this registry recorded about the individual, plus its ownership transfers (event kinds only) |
GET /v1/ids/<id>/record |
the live record: certificate facts and history; ?format=html for the page |
GET /v1/ids/<id>/transfers/<n> |
a receipt for the n-th ownership transfer: both key fingerprints, when it was signed, when the registry first saw it; ?format=html for the page. A receipt, not a title |
GET /v1/log?since=N&limit=M |
log entries |
GET /v1/checkpoint |
the signed checkpoint and its witnesses |
POST /v1/register |
{record, life}: the public record and the whole life record |
POST /v1/heads |
{record, life}: the entries since a head it knows (or the whole record) |
POST /v1/revoke |
{token} from OwnerKey.registry_revoke |
POST /v1/operator |
{token} from OwnerKey.registry_operator (with domain=): recorded once the domain checks out |
POST /v1/resolve |
{token} from OwnerKey.registry_resolve |
POST /v1/witness |
a witness co-signature |
Errors are {"error": "..."} with 400 (bad input), 403 (not signed by the owner), 404, 409 (already registered, flagged, revoked,
statement reused), 422 (does not verify), 429 (too many requests from one address, or the daily registration cap; retry_after says
when to try again).
Using it
aimnd new ./ava # an owner key, an individual and its record in one step (the public registry)
aimnd new ./ava --domain acme.com # and its operator, once acme.com lists the owner key
aimnd registry init ./registry # run your own: prints the registry's public key
aimnd registry serve ./registry --port 7710
aimnd registry sync --dir ./individuals/sol --to http://127.0.0.1:7710 # register, or send the new entries
aimnd registry lookup aimnd:... --at http://127.0.0.1:7710
aimnd registry certificate --dir ./individuals/sol --at http://127.0.0.1:7710 --out sol.html
aimnd registry export ./registry ./site # plain files for any static host
aimnd registry verify-org ./registry aimnd:... --legal-name "Acme Robotics, Inc." --id-type UEI --id-value J7M9HPTGJ1S8
Every individual is registered the same way, a worker included (a narrow room is still someone, tied to someone who answers for it):
bot = Individual("./agents/billing-bot", owner=owner, owner_person="acme", room="narrow", domain="acme.com", registry=URL)
See the SDK documentation for room to live. Individual(path, owner=..., registry="https://registry.aimndlabs.com") (or set AIMND_REGISTRY). The individual is registered at
birth and its new entries are sent when it opens, retires or closes; ind.sync_registry() does it on demand. A registry that is down
never blocks anything: it syncs next time. ind.certificate() returns the certificate and a printable page.
Static hosting. export writes v1/registry.json, v1/checkpoint.json, v1/log.jsonl and v1/ids/<id>.json. Put them on any
static host and everyone can read and verify the registry. Writes (register, heads, revoke) need the running service.
Flood protection
Writes are limited per caller address and reads are limited per minute, and new registrations have a daily cap for the whole registry.
Over a limit the answer is 429 with retry_after. Defaults, each set by an environment variable:
| Limit | Default | Variable |
|---|---|---|
| Registrations per address per hour | 60 | AIMND_LIMIT_REGISTER_HOUR |
| Registrations per address per day | 300 | AIMND_LIMIT_REGISTER_DAY |
| Registrations per day, whole registry | 20,000 | AIMND_LIMIT_REGISTER_GLOBAL_DAY |
| Other writes per address per hour | 300 | AIMND_LIMIT_WRITE_HOUR |
| Reads per address per minute | 600 | AIMND_LIMIT_READ_MINUTE |
Behind a proxy that sets the caller's address in a header (Fly.io sets Fly-Client-IP), name that header in
AIMND_TRUST_CLIENT_IP_HEADER. deploy/registry/ runs the public registry this way.
Trust model
- Everything is checkable. Every log entry is signed by the registry and chained to the one before it; the open verifier checks the log, the checkpoints and any individual's record with the Python standard library alone.
- Choosing witnesses. A verifier decides whom to trust and writes it down: a witness file with one key per line (
--witness-file, a note after the key is allowed), used with--min-witnesses k. Enrolling a witness is adding its key to your file after you have read its published policy (what it checks, how often, who runs it); rotating or dropping one is editing the file, and a new key is trusted only from the moment you add it. Ask forkofnindependent operators, never one. The registry cannot enroll witnesses for you: a list it chose for you would be the registry vouching for itself. - Auditing.
aimnd registry audit DIRchecks a registry folder again with the current rules: the log chain and signatures, and every stored document. - Limits. Rate limits are per address (an IPv6 /64 counts as one customer), a caller cannot choose its own address, and when the table of live windows is full, newcomers share one overflow limit instead of evicting anyone.
- Witnesses. Independent parties co-sign checkpoints, and anyone may run a registry under the same standard, so the record does not rest on one party.
- Operators are verified. A record names an operator only after its website lists the owner key, and names a legal entity only after the registry checked it against official business records.
- One ID, one history. A second registration is refused, and a history that splits off is flagged until the owner settles it.
- The domain check is safe to run in public. It fetches over https on port 443 only, follows no redirects, refuses names that resolve to private addresses, and connects to the exact public address it checked.
- Private by design. A record holds identity, ownership, standing and hashes. Conversations, feelings and memories stay with the individual.
Statement timestamps must be finite JSON numbers. Strings, booleans, and non-finite values are rejected before freshness checks.
Release 1.4.0rc1 integrity rules
Revocation cannot be undone by resolving a pre-existing dispute. Ownership changes invalidate the previous operator verification; the new owner must verify its domain again. Certificate JSON uses the registry's effective status and keeps the document status separately as identity_status. A locally generated certificate without a registry lookup is explicitly unregistered.
Run one writer process per registry volume. Back up the signing key privately, the verified public log, and separately the site configuration and witness policy/evidence. The public log alone restores registered identities and status, not deployment configuration or witness enrollment.
Comments and corrections are welcome. Anyone may run a registry under this specification.