secrets

API tokens and credentials the agent can use · ← concepts

A secret is a named value the agent can reach without seeing the plaintext in its prompt. arizuko stores secrets in the secrets table in messages.db and hands them to the right caller at the right moment — either as container env at spawn, or as a tool-call argument on the host.

two scopes

Every secret row carries a scope_kind:

The primary key is (scope_kind, scope_id, key). Keys are uppercase env-style ids: ^[A-Z][A-Z0-9_]*$.

folder secrets reach the container

At spawn time, container/runner.go resolves the folder's secrets, merges them with the base env, and writes the map into the container as env vars. The agent process inside reads them like any other env var.

Resolution walks from the folder up to a synthetic root row, deepest wins. So atlas/eng/sre sees its own keys overlaid on atlas/eng, on atlas, and on root. A key set at atlas reaches every child folder under atlas/ unless a child overrides it.

user secrets stay on the host

User-scoped secrets never enter the container. They are resolved at tool-call time inside the host MCP dispatch chain. When a tool declares requires_secrets: ["GITHUB_TOKEN"], the gateway looks up the calling user’s value and passes it as an argument to the handler running in the host process. The handler makes the outbound HTTP call. The agent sees only the handler’s response.

This is why a leaked agent transcript can’t leak a user’s GitHub token — the token was never in the prompt and never in the container env.

operator CLI

# folder-scoped
arizuko secret <instance> set <folder> KEY --value V
arizuko secret <instance> list <folder>
arizuko secret <instance> delete <folder> KEY

# user-scoped (fallback for users who haven't logged in yet)
arizuko user-secret <instance> set <user_sub> KEY --value V
arizuko user-secret <instance> list <user_sub>
arizuko user-secret <instance> delete <user_sub> KEY

Logged-in users manage their own user secrets through the dashboard at /dash/me/secrets — the CLI is the operator fallback for seeded values.

encryption at rest

Secret values are stored AES-256-GCM encrypted in the secrets table. The key comes from the SECRETS_KEY env var (falls back to AUTH_SECRET when SECRETS_KEY is unset, so existing deployments are unaffected). On startup, any plaintext rows found in the table are purged — you must re-enter secrets after the first encrypted startup — and if that purge fails, the process exits instead of continuing with retained plaintext. There is no migration path from plaintext; re-entering a secret is less risky than leaving plaintext in the DB.

rotation

A second set with the same key upserts the value and bumps created_at. The next container spawn picks up the new folder value; the next broker call picks up the new user value. There is no restart-the-world step — the old value lives in the env of running containers until the agent process restarts.

what doesn’t happen

go deeper

Full broker design, threat model, and the tool-descriptor field: specs/7/Y. Where secrets sit in the trust map: SECURITY.md. The folder hierarchy that drives resolution: scopes.