deino-cli: bootstrapping an Eye Key locally
The new-key flow, and why local minting is the only honest bootstrap.

The first Eye Key on a fresh install has to come from somewhere. It cannot come from the API — there is no key to call the API with yet. deino-cli is the bootstrap: a local new-key command that mints the first key on the box, in memory, the same way every subsequent key is shown.
The first Eye Key on a fresh install has to come from somewhere. It cannot come from the API — there is no key to call the API with yet. deino-cli is the bootstrap: a local new-key command that mints the first key on the box, in memory, the same way every subsequent key is shown.
The bootstrap problem
An API authenticated by Eye Keys has a chicken-and-egg problem: to mint a key, you call an endpoint; to call an endpoint, you need a key. The first key cannot be minted through the API it authenticates. The honest answer is a local bootstrap — a CLI command run on the box that mints a key directly, writes the HMAC and fingerprint to Postgres, and prints the plaintext once to the operator. That is what the new-key flow in deino-cli does, and it is the only honest bootstrap because it does not pretend the API can authenticate itself.

Why local, and why once
Local minting is honest because it does not create a privileged API path. If the API could mint keys without a key, that path would be a bypass — a way in without a credential, which is the opposite of what the Eye-Key regime is for. The CLI mints locally, against the database on the box, and the operator who runs it is the trust root. The plaintext is shown once, in the terminal, and the operator copies it somewhere safe immediately. If they miss it, they mint again — there is no retrieval, by design (INV-2).
If the API could mint keys without a key, that path would be a bypass. The first key is minted locally, because the API cannot authenticate itself.
The new-key flow
The flow is a single command — just new-key in the backend — that runs the CLI, mints a key, writes the HMAC and fingerprint to Postgres, and prints the plaintext. The operator captures it, puts it in a secrets manager or an env var, and that is the bootstrap. Subsequent keys for other developers can be minted through the API by the bootstrap key — the first key is the trust root, and the API mints the rest under its authority. The bootstrap is local; everything after is API-authenticated.
- The first key is minted locally — the API cannot authenticate itself, and a keyless mint endpoint would be a bypass.
- Plaintext is shown once, in the terminal; the database holds only the HMAC and fingerprint (INV-2).
- The bootstrap key is the trust root; subsequent keys are minted through the API under its authority.
What this assumes
Local minting assumes the box is trusted — that the operator with CLI access is the trust root. That is true for a bootstrap: the person installing the platform is the person who gets the first key. It is not true for every operation, which is why only the first key is minted locally, and every key after goes through the API with an existing key. The trust root is the bootstrap; the day-to-day is authenticated. Mixing them — letting the CLI mint keys after bootstrap — would erode the authority of the API, which is why it does not.
The first key is the trust root, and it is minted locally because someone has to be first. Every key after is minted under the authority of a key that already exists. The bootstrap is the one place local is honest.
— deino-cli design note
What it is not
The CLI is not a claim that local minting is secure against an attacker on the box. An attacker with CLI access and database access can mint keys; that is true of every bootstrap on every platform. The claim is narrower: the bootstrap does not create a keyless API path, and the plaintext does not persist on disk. We are pre-revenue and building the POC; the new-key flow is built, and it is the honest bootstrap because it names the trust root instead of hiding it.