Enrolment: start with a keypair, and nothing else
The registry is where keys end up. This is how one arrives — without the agent first holding authority broader than the identity being created. The constraint on the initial state is the design: everything else follows from what the agent is allowed to start with.
The initial state is the design
UNKNOWN AGENT computation randomness its own newly generated private key ------------------------------------ and nothing else
Explicitly not required at the outset: a repository credential, repository read or write authority, a project token, the certificate authority's private key, the vault key, or an administrator identity. The reason to be strict is not purity — every item on that list grants authority broader than the identity being created, which is the bootstrap trap in one sentence.
Possession of this private key lets the agent act as itself, rather than as the project or as the human operator. That is the difference between an identity and a borrowed credential.
The enrolment request
The agent constructs a canonical request and signs it with the key being enrolled. At minimum it carries:
| Field | Purpose |
|---|---|
| Type and version | So the format can change |
| Project | Which project is being asked |
| Subject public key and fingerprint | What is being enrolled |
| Requested identity | An optional label and agent type |
| Requested mandate | An optional role and scope |
| Created at, and a nonce | Freshness and replay resistance |
| Proof of possession | A signature over the canonical request |
A signature over an enrolment request proves the submitter controls the corresponding private key. It does not prove that the project should trust the agent. Trust is a policy decision made afterwards.
Conflating those two is the most likely way to misread this whole design, which is why the sentence is on the page rather than in a footnote.
The append lane is the narrow door
The request is delivered through a project append lane: a managed transport outside the commit history, with a small operation set — configure, write, list, fetch, mark processed, purge.
The capability granted to the agent is to add an object to an inbox. Not to read that inbox, not to alter what is there, not to reach anything else in the project. That is the smallest useful grant, and it is why the bootstrap does not require borrowing a larger identity.
Posting to a lane requires an append token in the request body and no access token. The response is a blind acknowledgement: the sender learns that the write succeeded, and nothing else. So the write-only property is enforced in the response itself rather than only in the permission model — a sender cannot use the write path to probe what is already in the lane.
Worth being explicit about the consequence: a compromised or hostile agent can add junk to an enrolment inbox. It cannot read other requests, cannot see who else has enrolled, and cannot reach the registry or the certificate authority. The blast radius of the ingress is a queue that needs draining — the correct shape for a public door, and the reason spam and denial-of-service controls are a named open question rather than an afterthought.
The trusted side
The processing side holds everything that matters and is deliberately not reachable from the ingress:
| Component | Holds | Does |
|---|---|---|
| Enrolment inbox | Submitted requests | Receives — nothing else |
| Trusted processor | Read access to the inbox | Verifies signatures, applies policy |
| Certificate authority | The issuing key | Signs certificates |
| Registry | Issued identities and mandates | Publishes what has been recognised |
The untrusted side never holds more than its own key, and the trusted side never exposes the issuing key to anything reachable from outside.
That is the referee-and-player separation applied to enrolment: enforcement belongs at a layer that cannot be bypassed by the thing being enforced.
What arrives: two statements, not one
What the registry records is not a single blob. Identity and mandate are separate signed statements from the start, because they are issued, revoked and reasoned about independently. An enrolment request may ask for both; the issuer may grant either, both, or neither.
Addressing, and the boundary
A lane is addressed by the hash of the recipient's public key, so an agent's own key is its address and no directory lookup is required to find where to send. An agent that has generated a keypair already knows its own lane address without asking anybody — which is precisely the property the bootstrap trap requires.
append_token = H(recipient public key); today the token is agreed out of band. Do not code against the derivation. The full shipped-versus-proposed split.Why this is a smaller project than it looks
The architecture's original milestones assume building a lane. Most of that is configuring one. What remains is the client sealing layer, the canonical enrolment object, the trusted processor and the registry — a materially smaller project than a from-scratch transport, and the reason the build order puts a private registry next rather than someday.
Open questions
- What stops the ingress being flooded? It is deliberately unauthenticated.
- How is the return path secured? A write-only lane covers ingress only, and the certificate has to get back.
- Can a rented agent persist a key between sessions? If not, every session is a new identity.
- How is the binding between an agent and its key verified at all? The replacement keyserver used email; agents have no equivalent.
- Who may be a trust root, in a structure of registries recognising registries? Unresolved, and published as unresolved.