# AI:MND Individual Identity, v0.2

Open specification. Anyone may implement it, with or without AI:MND One. No registry is required: the identity belongs to the
individual and its owner, and anyone can verify it from public information. An optional registry (docs/REGISTRY.md) keeps a public
record of births, status and duplicates, like a birth register beside the copy you keep at home. This text is licensed under Creative Commons Attribution 4.0
(CC BY 4.0); the reference verifier, `aimnd_verify.py`, under the MIT License.

## What it is for

Agent identity standards that exist in 2026 (enterprise agent IDs, OAuth-style delegation, on-chain agent registries) answer "which
agent is this, who does it act for, and what may it do". They are credentials. This spec answers a different question: **is this the
same individual it was before, whose is it, and what has it done?** It is meant to sit on top of those credentials, not to replace them.

It defines five things:

1. **An individual ID** that belongs to the individual, not to its model, its body or its host.
2. **An owner binding**, signed by the owner at birth, changed only by a signed transfer.
3. **Signed authority**: a signed order from the owner is real authority; a time-limited signed grant lends some of it; anything else
   is a claim.
4. **A life record**: append-only, hash-chained, signed. It records what kind of thing happened and when, never what anyone said.
5. **Honest continuity**: an individual that was wiped is a new individual, with the old one as its predecessor. Continuity cannot be
   claimed where it was broken.

## Keys

* Ed25519 for every signature. Keys and signatures are base64url without padding.
* The **individual key** is created at birth on the owner's own machine and never leaves it.
* The **owner key** is held by the owner's side: the developer's backend for a software agent, the owner's phone for a robot.
  The individual never holds the owner's private key.

## Signed bytes

Every signature and every hash in the standard is taken over the same text, so two implementations that follow these rules produce
the same bytes.

**Canonical JSON.** The text is UTF-8 and has no whitespace. Object keys are sorted by Unicode code point and separated from their
values by `:` and from each other by `,`. Strings are written with `"` and `\` escaped, the control characters U+0000 to U+001F
written as `\b`, `\f`, `\n`, `\r`, `\t` or `\u00xx` (lowercase hex), and every other character as itself, never as a `\u` escape.
`true`, `false` and `null` are written as such. Integers are written in decimal. A number written with a decimal point or an exponent
is a float (all timestamps are floats): it is written with the shortest digits that read back as the same value, in fixed notation
when its decimal exponent is from -4 to 15 (always with at least one digit after the point, as in `1790924400.0`) and otherwise as
`d.ddde+XX` or `d.ddde-XX` with at least two exponent digits. Only finite numbers are signed. Text that cannot be written this way is refused, never approximated: `NaN`, infinities, strings with an unpaired
surrogate, and objects with a repeated key (a verifier that reads files rejects a repeated key, because two parsers could disagree about
which value it means).

**What is signed.** Public keys are 32-byte Ed25519 keys and signatures are 64 bytes, both written as base64url without padding.
`H(x)` is the SHA-256 of the canonical JSON of `x`, in lowercase hex.

| Object | Signed by | Over |
|---|---|---|
| Identity document | the individual key | the document without its `signature` field |
| Birth statement | the individual key (`individual_signature`) and the owner key (`owner_signature`) | `birth.statement` |
| Transfer | the owner key in force before it | its `statement` |
| Life entry | the individual key | `{"hash": h}`, where `h = H(entry without hash and sig)` |
| Order, grant, revoke, registry statements | the owner key | the token's `statement` |
| Registry log entry | the registry key | `{"hash": h}`, computed as for a life entry |
| Registry checkpoint | the registry key | the checkpoint without `signature` and `witnesses` |
| Witness co-signature | the witness key | `{"cosign": H(checkpoint without signature and witnesses)}` |

## The individual ID

`aimnd:` followed by the first 26 characters of the base32 (lowercase, no padding) SHA-256 of the individual's public key.
Derived from the key, so it cannot be claimed without the key.

## The identity document (`aimnd.identity/1`)

```json
{"schema": "aimnd.identity/1",
 "id": "aimnd:k3x...",
 "public_key": "...",
 "born_at": 1793462400.0,
 "species": "aimnd-one",
 "predecessor": null,
 "owner": {"public_key": "...", "person": "p:3f9a...", "since": 1793462400.0},
 "birth": {"statement": {...}, "owner_signature": "...", "individual_signature": "..."},
 "transfers": [],
 "status": "active",
 "life": {"entries": 41, "head": "sha256 of the last entry"},
 "signature": "the individual's signature over everything above"}
```

* `birth.statement` is `{"kind": "birth", "individual": id, "individual_key": ..., "owner_key": ..., "owner_person": ..., "ts": ...}`.
  The owner signs it (this individual is mine) and the individual signs it (this is my owner).
* `status` is `active` or `retired`. A retired document stays valid as a record; it can never become active again.
* The document is public. It holds no memories, feelings, relationships, messages or names: people appear only as `p:` followed by a
  keyed hash (see the life record).

## Signed authority

**Order** (`aimnd.order/1`), made by the owner's side:

```json
{"kind": "order", "individual": "aimnd:k3x...", "text_sha256": "...", "nonce": "unique", "ts": 1793462400.0}
```

The individual accepts an order when the signature verifies under the current owner key, `individual` is its own ID, the hash matches
the text it received, `ts` is recent (default 10 minutes) and the nonce was never seen before. Who delivered it does not matter: a
signed order relayed by someone else is still the owner's order.

**Grant** (`aimnd.grant/1`): the owner lends authority to one person for a while.

```json
{"kind": "grant", "individual": "aimnd:k3x...", "to": "human:ray", "scope": "handle my schedule", "actions": ["schedule"],
 "from_ts": ..., "until_ts": ..., "nonce": "..."}
```

While it is active, messages from `to` carry owner authority within the scope. It ends at `until_ts`, or earlier by a signed
`revoke` (`{"kind": "revoke", "grant_nonce": ...}`).

**Anything else is a claim.** "Sam put me in charge" is testimony. The individual does not act on it as an order and tells the host
it is unverified.

Hosts that authenticate their users already (a logged-in owner in a web app) can sign every owner message server-side; it is one call.

## Transfer

The current owner signs `{"kind": "transfer", "individual": id, "new_owner_key": ..., "new_owner_person_sha256": ..., "ts": ..., "nonce": ...}`.
The owner's id for the new owner travels beside the signed statement and must match the hash; only the signed statement goes into the
public document, so use an opaque id (an account number, not a name, since a hash of a short name can be guessed). The individual
verifies the statement against the current owner key, appends it to `transfers`, and from that moment obeys the new owner.
It keeps its whole life: the old owner becomes someone it belonged to. The transfer is a moment it lives through, like any other.

## Life record (`aimnd.life/1`)

One JSON object per line, append-only:

```json
{"n": 12, "ts": 1793462400.0, "kind": "order_accepted", "data": {"text_sha256": "...", "delivered_by": "p:3f9a..."},
 "prev": "sha256 of entry 11", "hash": "sha256 of this entry without hash and sig", "sig": "individual's signature over hash"}
```

* Kinds: `born`, `owner_confirmed`, `order_accepted`, `claim_not_verified`, `grant_added`, `grant_revoked`, `transfer`, `model_changed`,
  `host_changed`, `action_suggested`, `action_outcome`, `snapshot`, `rollback`, `succeeded_by`, `retired`.
* People appear only as `p:` followed by a keyed hash of the host's id for them (the key stays with the individual), so the record can
  be shown to an auditor without naming anyone. Text never appears, only its hash.
* The record lives outside the individual's mind database, so rolling the mind back to a snapshot cannot roll the record back. A
  rollback is itself an entry.

## Continuity rules

* **Model upgrade or new host:** same individual. Recorded (`model_changed`, `host_changed`).
* **Rollback to a snapshot:** same individual, with the lost time recorded (`rollback`).
* **Reset or wipe:** a new individual. The old one gets `succeeded_by` and is retired; the new one is born with `predecessor` set.
* **Retire:** the mind is deleted. The identity document (status `retired`) and the life record stay, because neither holds what
  anyone said.

## Verification

`verify(document, life_record)` checks the document's signature, the birth signatures, each transfer against the owner key at that
time, and every life entry's hash chain and signature. The final head must equal `life.head` in the document.

Every verifier also enforces what each signed statement is *about*, because a valid signature on the wrong thing proves nothing:

* **Strong keys only.** Every public key (individual, owner, registry, witness) must decode to a point of the prime-order subgroup of
  Edwards25519 and must not be the identity. A key of small order, or with a small-order part, makes some signatures verify for several
  messages, so such a key never counts as control of anything. Honest keys, which are multiples of the base point, always pass.
* **The birth is this individual's.** `birth.statement.kind` is `birth`; its `individual` is the document's `id` and its `individual_key`
  is the document's `public_key`; while there are no transfers, the document's `owner.person` equals the statement's `owner_person`.
* **Each transfer is a transfer of this individual.** `statement.kind` is `transfer` and `statement.individual` is the document's `id`; no
  two transfers share a nonce; each is signed by the owner key in force before it.
* **Revoked grants stay revoked.** An individual remembers the nonce of every grant the owner revoked (even if the revocation arrived
  before the grant) and never accepts that grant again.
* **Public entries hold no caller-supplied strings.** `model_changed` and `host_changed` carry keyed hashes (`from_ref`, `to_ref`), and
  `action_suggested` / `action_outcome` carry a hash of the capability name and a status from a fixed list.

## Reference verifier

`aimnd_verify.py` (https://aimndlabs.com/standard/aimnd_verify.py) is one file, Python standard library only, MIT licensed. It implements
`verify(document, life, published_heads)` exactly as described above, with its own Ed25519 check (RFC 8032), so anyone can check an
individual without AI:MND software:

```
python3 aimnd_verify.py identity.json life.jsonl --heads heads.txt
```

Real example files, from an individual that was born, took a signed order, was lent to someone for a week, and changed owners, are at
https://aimndlabs.com/standard/examples/ (including `life-tampered.jsonl`, which the verifier rejects).

## Roles (v0.2)

Five roles are kept apart. The **individual** (its own key); the **operator** (who is responsible for running it; named by a signed
`registry_operator` statement, never assumed); the **controller** (the owner key: orders, grants, transfers); **delegated users** (grants);
and the **host** (the platform; recorded as `host_changed`, never an authority). The operator is accountable for the individual under applicable law and contract.

## Registry statements (v0.2)

Three more owner-signed statements, used only with a registry: `registry_revoke` (permanent), `registry_operator` (the website that answers for
it, recorded once that website lists the owner key), `registry_resolve` (which of two flagged histories is real). Each carries `individual`, `ts` and a single-use `nonce`.
See docs/REGISTRY.md for the rules and the signed log. The reference verifier also checks a registry's log and checkpoint.

## Publishing and catching copies

Nobody has to ask a company or a government whether a signature is genuine: signatures are checked with public keys. Publishing is
how anyone can also tell that an individual is the one and only continuation of its history:

* **The public record** (`aimnd.public/1`): the identity document plus the life record's latest head and entry count. It holds no
  memories, no messages and no names.
* **Where it goes:** wherever the owner chooses, and any number of places. The simplest is the owner's own domain at
  `https://<owner's domain>/.well-known/aimnd/<individual id>.json`, the way websites already prove they own a domain. Public append-only
  logs that anyone can run (in the style of certificate transparency logs) work the same way.
* **How a copy is caught:** every head the owner ever published must appear in the individual's life record. A copy that split off
  earlier cannot contain the heads the original published after the split, and a rewritten record cannot contain the heads published
  before the rewrite. `verify(document, life, published_heads=[...])` checks exactly that.

## Security considerations

* **Copies are caught by publishing.** An individual's folder holds its key, so a copied folder signs as the same individual. Its two
  life records fork from one entry, and every head the owner publishes (above), or reports to a registry, exposes the fork.
* **Tamper-evident record.** Changing or dropping an entry breaks the chain and `verify` names the entry. A published head also fixes
  everything before it, so even a consistent rewrite by whoever holds the individual's key is caught.
* **Owner keys are the owner's to keep.** The owner key proves the owner's side signed. Store it like any signing key, back it up, and
  hand an individual to a new key with a signed transfer whenever a key may be at risk.
* **Works with credentials.** Use it alongside OAuth, enterprise agent IDs or on-chain registries; the individual ID can be listed in any
  of them.
* **Key rotation for the individual's own key** is reserved for a later version (a permanent ID with a signed rotation chain). Today a
  compromised individual key is retired and succeeded by a new individual that names it as predecessor.
* **No one in the middle is required.** An individual is valid without registering, and no authority can switch it off. A registry
  (docs/REGISTRY.md) adds a public list, revocation, duplicate flags and a verified operator.

## 1.3.1 implementation clarifications

`born_at` must be a finite numeric Unix timestamp from 0 through 253402300799 and equal the timestamp in the owner-signed birth statement. A certificate reports this signed claim, not an independently witnessed physical birth time. Signed order timestamps must be finite JSON numbers. Certificate status must include the latest registry status when one is supplied.
