Skip to content

Settings

The Settings page exposes operational configuration that lives outside config.json — namely app-level secrets (API tokens, webhook keys) and SSH keys for remote execution. Everything is gated behind the same auth as the rest of the Command Center.

Settings vs. OptimalVault

This page documents the app-level secrets store (src/secrets/store.ts) and SSH key manager (src/ssh/manager.ts) — both ship in legacy and fabric modes. OptimalVault is a separate, fabric-only store for multi-recipient encrypted credentials shared across paired devices. The two do not overlap: workflow secrets and deploy keys live here; cockpit-bound vault entries live in OptimalVault. See /fabric/vault for the vault.

Secrets

The Secrets card manages API keys and webhook tokens stored on disk in a redacted store. Values are written atomically and rotated through five backups.

API

MethodPathPurpose
GET/api/system/secretsReturns the redacted list. Each entry shows key and lastFour only; the full value is never echoed.
PUT/api/system/secretsSet or update a secret. Body: { key, value }.
DELETE/api/system/secrets/:keyRemove a secret.

Routes: src/routes/secrets.ts. Store: src/secrets/store.ts. The UI card lives under the Settings tab in client/ (legacy widget grid + fabric cockpit both mount it).

Allowlist

The set of permitted keys is enforced server-side. PUT requests with keys not on the allowlist are rejected. Common entries include API tokens (e.g. OPENROUTER_API_KEY, STRAPI_API_TOKEN) and webhook tokens. Check src/secrets/store.ts for the current allowlist constant — the list ships with the build and changes only with new code releases.

Atomic writes + rotating backups

Every write goes through a temp-file-plus-rename pattern so a crash during write cannot leave a half-written secrets file on disk. The five most recent prior versions of the secrets file are retained as numbered backups so a human can roll back if a wrong value is committed.

Reading secrets from a workflow

Workflow steps can resolve secrets via ctx.secrets("KEY_NAME"), returning the string value or null if the key is not set. The signature is part of StepContext (optimalOS/src/loom/types.ts:36-38).

SSH Keys

The SSH Keys card manages key pairs used for remote execution (cross-node dispatch, deploy workflows like popos-deploy).

API

MethodPathPurpose
GET/api/system/ssh/keysList installed key pairs.
POST/api/system/ssh/keysGenerate a new ed25519 key pair. Body: { name }.
DELETE/api/system/ssh/keys/:nameRemove a key pair.
POST/api/system/ssh/scanScan a remote host's host keys (populates known_hosts). Body: { host }.
POST/api/system/ssh/testTest SSH connectivity to a host with the named key. Body: { host, user, key }.

Routes: src/routes/ssh.ts. Manager: src/ssh/manager.ts.

What gets generated

POST to /api/system/ssh/keys runs ssh-keygen -t ed25519 under the hood. The private key lands in ~/.ssh/id_<name> and the public key in ~/.ssh/id_<name>.pub. The card displays the public key so you can paste it into the destination host's authorized_keys.

Host scanning

Before testing SSH connectivity, scan the remote host's host keys so OpenSSH doesn't prompt interactively. The /api/system/ssh/scan endpoint runs ssh-keyscan and appends the result to ~/.ssh/known_hosts.

Test reachability

/api/system/ssh/test runs a non-interactive ssh -i ~/.ssh/id_<key> -o BatchMode=yes <user>@<host> exit and reports success or the error code. Use it as a health check before relying on a deploy workflow.

Where this lives in each mode

ModeOriginNotes
Legacyoptimal.miami (Pi)Secrets + SSH keys persist under ~/.optimalos/ on the Pi.
Fabricfabric.optimal.miami (Hetzner)Same routes mount under the cockpit. Per-device SSH keys and secrets on paired devices are managed locally on each device, not synced through this UI — OptimalVault is the path for cross-device secret sharing.

Cross-check against src/server.ts route mounts and the live allowlist in src/secrets/store.ts before integrating against any of the endpoints above.

Built by Carlos Lenis in Miami