A passkey is how you approve things. When a write is held, or you undo a run, you sign with a passkey: Touch ID, a security key, or a password manager that stores passkeys. Postgres checks the signature before anything changes. The engine, the CLI and the pages only carry it. An agent can open a link but cannot sign, and an agent’s role can neither register nor remove a passkey.
For what a signature covers, see Approvals and Undo.
Register one
Section titled “Register one”basalt init registers your first passkey. After the guard is installed it prints a link:
- Open the link in a browser on the same machine.
- Press the button and confirm with your passkey.
- Copy the code the page shows (it starts with
basalt-passkey.1.) and paste it atPaste the code the page shows:.
You see basalt: passkey registered for localhost. The public key is stored in your Postgres. The private key never leaves your device.
To add another passkey, for a second device or a teammate, run init again for the same agent:
basalt init --agent NAME --add-passkey --passkey-label "work laptop"
Re-running init keeps the agent’s password. --skip-passkey on a first install defers the registration.
Which devices work
Section titled “Which devices work”A passkey belongs to the page where you registered it. The engine serves its pages at http://localhost:8787 by default, so the passkey is for localhost. A passkey made on that page signs only on that page, so keep the same port. For a bot on its own computer the pages come from the BasaltVault portal, and the passkey belongs to it.
- macOS. Touch ID, or any option listed for Linux.
- Linux desktop. There is no built-in passkey store, so use one of these:
- Your phone, through the browser’s QR code flow, only for pages on a real domain such as the BasaltVault portal. Both devices need Bluetooth.
- A USB or NFC security key. It needs a PIN, which you set with
ykman fido access change-pinor in the browser’s security key settings. - A password manager extension that stores passkeys.
A phone through the QR flow is not offered for pages on localhost (Chrome on macOS shows no phone option), so approving from a phone needs the pages on a real domain: the hosted portal.
If the engine runs on a headless server, open an SSH tunnel with the same port on both ends, then open the link on your own computer:
ssh -N -L 8787:127.0.0.1:8787 you@server
Register through the same tunnel. Keep it open while basalt init waits for the code.
List your passkeys
Section titled “List your passkeys”basalt passkey list --agent NAME
It prints one line per active passkey: its id, label, where it was registered, when it was registered, and when it last signed something (never if it has not). --json prints the same as JSON. It never prints key material.
Check which ones a device still has
Section titled “Check which ones a device still has”Nothing tells BasaltDB when you delete a passkey from a device or a password manager. basalt passkey check finds out.
basalt passkey check --agent NAME --open
It opens a page that asks for each passkey in turn. Confirm each one, then press Done and paste the code the page shows. The command prints each passkey as found on this device or not found on this device. For each one not found it asks Remove <label> (<id>)? [y/N]. Nothing is removed unless you answer y. A check signature authorizes nothing: it cannot approve a write or an undo.
Remove one
Section titled “Remove one”Remove a passkey you lost, or one on a device you no longer use. This needs the admin connection string, at a hidden prompt, because it changes your database.
basalt passkey remove PASSKEY_ID
PASSKEY_ID is the full id from basalt passkey list, or a unique start of it with at least 8 characters. The command shows the label, where it was registered and when it last signed, and asks Remove passkey ...? [y/N]. A removed passkey is refused from then on: it can no longer approve a write or sign an undo. The removal is recorded in the ledger.
Removing a passkey does not delete it from the device. The command prints a link ending /passkeys/forget. Open it on each device that holds the passkey, so its password manager drops it. --open opens the link for you. Not every browser supports this. If yours does not, delete the passkey by hand in your password manager.
The last passkey
Section titled “The last passkey”With no passkey, nothing held can be approved and no undo can be signed. So basalt passkey remove refuses to remove the last one. --force removes it, and you then type its label at the prompt, even with --yes. Add another passkey first, or run this afterwards:
basalt init --agent NAME --add-passkey
If you lose a device
Section titled “If you lose a device”- If you have another passkey, run
basalt passkey list --agent NAMEandbasalt passkey remove PASSKEY_IDfor the lost one. - If it was your only passkey, run
basalt init --agent NAME --add-passkeyfirst to register a new one, then remove the old one. - Held writes wait until you can sign. They expire after 24 hours.
When BasaltDB tells you
Section titled “When BasaltDB tells you”basalt log warns when no passkey is active. It also warns about a passkey that has not signed anything for 90 days, counted from registration if it never did. It names the passkey and says to use basalt passkey remove. Nothing is removed automatically. basalt status --agent NAME reports a missing passkey too. The agent sees the same as NO_PASSKEY. See When something is refused.
- Approvals: what a signature covers and when it expires.
- Undo a run: sign an undo.
- Remove BasaltDB: the passkey on your devices stays after you uninstall.
BasaltDB · Apache-2.0