diff --git a/docs/secret-store.md b/docs/secret-store.md index 5f674757..cd1b9c26 100644 --- a/docs/secret-store.md +++ b/docs/secret-store.md @@ -116,6 +116,24 @@ one value — or comes from a file read on demand. - `JWT_SECRET` — a signing key rather than an encryption key, but it has the same properties: must survive restarts, must never be regenerated silently, and benefits from versioning during a rotation. Leaving one in a store and one in `.env` would be the scattering this is meant to end. +- **The anthropic proxy secret**, purpose `anthropic-proxy`. Agreed 2026-08-12. Neither an encryption + key nor a signing key — a bearer credential, generated once by `ensureProxySecret` and presented by + `officer-agent` to `officer-anthropic-proxy` on `127.0.0.1`. It qualifies on the same three + properties: generated once, shared between two processes, fatal to regenerate silently. + + It is in the store for a sharper reason than the other two, though. It is not in `.env` today — it + is in `$DATA_PATH/sidecar/claude-state.json`, mixed in with session records. That is the one + location [decision 3](#3-where-the-file-goes) rules out by name: `DATA_PATH` is what people back up, + so the secret already travels in the same tarball as the data it protects. + + **Naming.** It is called `ANTHROPIC_API_KEY` in `ensureAnthropicEnv`, and that name is wrong in both + halves — it is not Anthropic's and it is not an API key. Anthropic's real credential is the OAuth + token in `~/.claude/.credentials.json`, which the proxy swaps this one for on the way out. Our name + for it is **anthropic-proxy-secret** everywhere we control. + + The exception is the last line before the spawn. `claude` reads the variable `ANTHROPIC_API_KEY` and + format-checks the `sk-ant-api03-` prefix, so both are the CLI's contract rather than ours and both + stay. That one assignment keeps the CLI's name, with a comment saying why. ---