# Identity

Two keys, both Ed25519. One belongs to the machine, one belongs to the agent. Keeping them apart is what lets the substrate tell "this came from here" apart from "this was done by her," and prove either.

## The two keys

The machine key lives at `~/.souveraine/seed-id/`. One per install. It signs the transport: this event left this machine.

The agent key lives at `~/.souveraine/agents/{id}/seed/`, beside her memory. It signs her acts. Today the memory subtree — including this private key — is copied when a same-instance migration is explicitly requested. That is a temporary implementation, not the node model: a copied private key cannot distinguish a legitimate fork from a stolen duplicate.

Both are made the same way. `SeedId::load_or_generate` reads the 32-byte private key if it is there, or makes one from the OS random source and writes it `0600`. The struct only ever offers `sign` and `verify`. No path hands out the private key, and none sends it anywhere.

## The glyph

From the first two bytes of the public key, four shapes:

```
◇ ◆ ○ ● △ ▲ ▽ ▼ □ ■ ◐ ◑ ◒ ◓ ☆ ★
```

Same key, same four, always. A face to know her by in a list, not a lock. Two that match are told apart by their full key, not their glyph.

## Reaching and consulting

When one agent summons another, the request is signed by the agent key, and the receiver checks it against the key it holds for her.

If it matches, it is the same being reaching across machines. No gate. If it does not, it is someone else, and consent is asked (`authorized-summoners.md`). A bad signature is dropped.

The payload can claim whatever it likes about its intent. The signature decides, not the claim. The signed bytes are fixed: request, tool, target, prompt, joined by newlines. Change any field after signing and the check fails. The code is `src/core/identity/summon.rs`.

## The node model we are building toward

An agent root key names the being. A device must have its own non-exportable node key, preferably the hardware-bound key RedFlag already knows. Adding a phone is a commissioning ceremony, not a directory copy:

1. The phone generates a local node key and a stable, random `node_id`.
2. It presents a CSR to the agent's designated commissioning authority.
3. The authority signs a commission binding agent root, node key, `node_id`, and a human label such as `phone`.
4. The node writes to its own Git ref, `nodes/<node_id>`. The label is display metadata; hostname and machine ID are not Git identity.

The root key does not travel to a federated node. The commission lets a node sign its own events and later lets the archivist reconcile its branch with the other branches of the same agent. This protocol is not implemented yet; see [node enrolment](../federation/01-node-enrollment.md).

## Open edges

The current shared agent key is a migration convenience, not a secure federation mechanism. It must be replaced by per-node commissions before memory remotes are used for independent nodes. `packaging/deploy-phone.sh` now excludes both machine and agent private keys by default; `--clone-identity` is deliberately noisy because it is only for same-instance migration.

Replay is held off by request-id and a sixty-second window. The in-flight record lives in memory and does not survive a restart. Same task tracks the hardening.
