--- title: 'secrets' description: 'Manage environment-scoped secrets bound to a running agent installation, with values that the CLI never prints.' position: 21 --- # stackbone secrets > `stackbone secrets` targets a **running agent installation**. With no > `--agent` it uses the local-dev installation linked to the current project, > so [`stackbone dev`](/docs/cli/reference/dev) must be running. See > [target resolution](/docs/cli/reference/conventions#target-resolution). > Every verb accepts `--json` and emits the > [standard envelope](/docs/cli/reference/conventions#json-output). Manage environment-scoped secrets bound to the targeted installation. There is **no reveal verb**: the CLI never prints a plaintext value, on any verb, in any output mode. Reading a stored secret back is a human-only action in Studio. That rule holds across the whole CLI; see [secrets are never printed](/docs/cli/reference/conventions#secrets-are-never-printed). `set` is idempotent on the name (create and rotate are the same call). | Command | Purpose | | --------------------------------- | ------------------------------------------------------------------------------ | | `stackbone secrets list` | List secret names (values always masked) and their last-rotated time. | | `stackbone secrets set ` | Create or rotate a secret. Value from `--value ` or stdin; `--description`. | | `stackbone secrets remove ` | Delete a secret. Requires `--yes`. | `remove` is destructive and refuses to run without `--yes`, described under [destructive verbs](/docs/cli/reference/conventions#destructive-verbs). A name is SHOUTY_SNAKE_CASE. It starts with an uppercase letter, then carries uppercase letters, digits and underscores, up to 128 characters. A value is at most 4 KiB, and a `--description` at most 256 characters. Names the install owns are refused. `set` and `remove` reject any name that starts with `STACKBONE_`, and these as well: `DATABASE_URL`, `AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`, `S3_ENDPOINT`, `S3_BUCKET`, `MODEL_PROVIDER_API_KEY`, `MODEL_PROVIDER_BASE_URL`, `OPENROUTER_API_KEY`, `OPENROUTER_BASE_URL`, `BROWSER_MODE`, `BROWSERBASE_API_KEY`, `BROWSERBASE_PROJECT_ID`. The runtime injects those itself, and an operator writes the model provider and the browser provider from their own Studio screens. `list` leaves them out too. **JSON payload** ```jsonc // secrets list: value_preview is a mask, never the plaintext { "schema_version": 1, "items": [ { "name": "OPENAI_API_KEY", "description": "Billing account key", "value_preview": "••••••", "created_by_email": "a@b.com", "created_at": "2026-05-20T09:00:00Z", "last_rotated_at": "2026-06-01T10:00:00Z", }, ], } ``` > [!NOTE] > A deployed box locks each secret with the per-agent `STACKBONE_SECRET_KEY` in > its `.env`, the same key the agent decrypts with. See > [what you set on the deployed container](/docs/cli/reference/package#what-you-set-on-the-deployed-container). > A box running an image older than CLI 0.3.3 wrote them under a different key, > so the agent read them as missing. You cannot recover those values: set them > again once the box runs a 0.3.3 image or newer. `stackbone dev` was never > affected. **Exit codes**: `0` ok · `4` not found (unknown secret) · `5` permission (`remove` without `--yes`) · `1` generic (empty value, a name that breaks the shape rule, a reserved name). See [exit codes](/docs/cli/reference/conventions#exit-codes).