# Secret Manager

> The one place where AgentsRoom keeps a secret: a machine-local vault encrypted through the operating system keychain.

- Area: Desktop, mobile and web
- Plans: All plans
- Last checked against the product: 2026-09-29
- Web page: https://agentsroom.dev/docs/secret-manager

## What it does

The one place where AgentsRoom keeps a secret: a machine-local vault encrypted through the operating system keychain. You save an API key, a token or a password once under a name, then write `{{secret:NAME}}` wherever the value would have gone: in a dev command line, in the environment of an agent, in a provider's environment variables. The value is substituted at launch, inside the desktop process only, into the process being started. Those are the only doors: a reference written in a ticket, a brief, a prompt or a skill is plain text for the agent and is never replaced. Agents, the interface, the phone and MCP tools only ever handle names, so an agent can run a test suite against a real service or deploy to staging with a real credential in its environment while its prompt, its conversation and anything it can print only ever contained the name. SSH passwords, key passphrases and database passwords live in the same vault.

## Where to find it

- Inside a project, the room dock: **Commands & connections** > **Secrets** tab (Commands · Servers · Databases · Secrets). Also reachable from the terminal bar's **Commands** / **Servers** / **Databases** modal via the tab switcher. It is **not** in Settings: the Settings window has no Secrets page, only the environment blocks where a secret is referenced.
- Phone: the Secrets sheet of the project.
- Two smart hints watch the composer: one offers to open the vault when what you are typing looks like a pasted credential, and one ("Secret reference?", **A reference in a message is never resolved**) fires when your draft contains a `{{secret:NAME}}` reference, because a message is the one place it is never substituted. Its button, **Open the agent's settings**, takes you to the environment variables that do work.

## How to use it

1. **New secret**: a **Name** (letters, digits, dot, dash and underscore, 64 characters max, so it works as an environment variable name) and a **Value** typed in a password field. "There is no way to display it again afterwards, by design."
2. The row shows the name and its reference `{{secret:NAME}}`. **Copy reference** copies the reference, never the value. **Replace** reopens the form with the name filled and an empty value. Delete asks for confirmation.
3. Paste the reference into a dev command line, or into one of the three environment-variable blocks: a provider's in Settings, the whole project's (**Project settings > AI providers > Environment variables**), or a single agent's (**Edit agent > Advanced options > Environment variables**). When the terminal is created the desktop substitutes the real value. The Secrets tab says it in one line: use the reference as the value of an environment variable or in a dev command line, and "in a message to an agent it stays literal text".
4. An agent that needs a credential calls `secrets_list`, sees which names exist, and asks you to expose one as an environment variable of its own (`MY_TOKEN={{secret:STRIPE_KEY}}` in its **Environment variables**), then uses `$MY_TOKEN` in its shell. A reference the agent writes itself in a command is not substituted, and a dev command it authors or proposes is refused when it contains one. If the secret is missing, it asks you to add it in the vault (it can open the Secrets tab for you) rather than asking you to paste a token in the conversation.
5. Under each environment block, a warning names any variable that will not deliver a secret while you type: braces around something that is not `secret:NAME` (for example a token pasted as `KEY={{token}}`: it reaches the agent as typed, braces included), a `{{secret:NAME}}` naming a secret this machine does not hold, or a value that looks like a token typed in clear. It suggests the line to write instead; it never blocks saving.

## Settings

- `providerEnvVars` (global, Settings > AI providers & accounts): per-provider environment variables for agent launches; a value can reference a secret instead of the token itself.
- `envVars` (project override, Project settings > AI providers): environment variables handed to every agent of the project; the natural place for a token the whole repository needs, referenced rather than typed.
- Per-agent **Environment variables** (agent editor): same rule, per agent.
- The vault has no toggle: it is available whenever the machine has a working OS keychain.

## Agent tools (MCP)

- `secrets_list`: the names of the secrets on this machine, with their last update. The only tool; nothing returns a value.

## Providers

All providers, no difference: substitution happens in the environment and the command line before any CLI starts.

## Mobile

Yes: the Secrets sheet lists, creates and deletes secrets. Creating sends the value from the phone to the desktop over the end-to-end encrypted channel and writes it into the desktop's keychain; nothing ever comes back to the phone.

## Limits

- Machine-local by design: secrets are never synced to AgentsRoom servers, never backed up, never relayed to the phone. Set them up again on a second machine.
- No OS keychain available means AgentsRoom refuses to store a secret rather than writing clear text (the **New secret** button is disabled and an amber notice says why).
- Only values are substituted, never environment variable names; an unknown name is left as is rather than replaced by an empty string, so a missing secret stays visible in the error.
- Text an agent reads is never substituted: a `{{secret:NAME}}` in a ticket description, a brief, a prompt, a skill or an agent's CLI options stays literal in the agent's prompt and on its command line (since 1.181.0; before that, a reference in a ticket brief could reach the launched agent's first message as the real value, so a secret exposed that way should be rotated). The only door to a value is an environment variable of a dev command or of the agent's environment.
- `commands_output` refuses to show the output of a command whose line contains a secret reference, since the resolved value could appear in it.
- Names are global to the machine, not scoped per project.
- This is exactly why a project's environment variables should carry a reference rather than the token: the project block is synced with the project, so a literal credential typed there leaves the machine, while `{{secret:NAME}}` never does.

## Common questions

- **I added a secret but my agent does not see it (`secrets_list` does not list it).** Three usual causes. (1) It was never saved in the vault: the vault is the **Secrets** tab of **Commands & connections** inside a project, not a page of Settings, and a value typed between braces in an environment block (`KEY={{token}}`) is not a secret. (2) It was saved on another computer: secrets are machine-local and never synced, and `secrets_list` shows the vault of the machine the agent runs on. (3) The save was refused (for example no system keychain): the form now shows why. Once it is listed, expose it to the agent with `KEY={{secret:NAME}}` in an environment block and start a new session of that agent.
- **Where are secrets in Settings?** Settings has no Secrets page. It holds the provider environment blocks, where a secret is referenced (and the Antigravity account rows, which can store their own API key in the vault). The secrets themselves are listed and added in any project, **Commands & connections** > **Secrets**.
- **Where are my secrets stored?** In one vault file in the AgentsRoom home folder, owner-only permissions, each value encrypted through the OS keychain, replaced atomically on write.
- **Can my agent read a secret?** No. It can list names and reference one; there is no code path that returns a value to an agent, to the interface or over MCP.
- **I wrote `{{secret:X}}` in my ticket, will the agent get the value?** No, by design. The ticket text arrives in the agent's prompt exactly as written, and the same goes for a brief, a prompt, a skill or the agent's CLI options. Give the value through an environment variable instead (project, provider or agent block, or the dev command that needs it): the agent runs the command, the process gets the value, the conversation keeps the name.
- **I pasted the reference in a message and my agent says it cannot read the key.** Same rule, and it is the most common misstep: a message is literal text, so the agent receives `{{secret:NAME}}` and has nothing to resolve. Add a line like `MY_TOKEN={{secret:NAME}}` in **Edit agent > Advanced options > Environment variables** (or in the project or provider settings), then tell the agent to use `$MY_TOKEN`. The hint that appears while you type says exactly this and opens that screen for you.
- **If someone copies the vault file?** On another machine it is ciphertext: the key belongs to your OS keychain.
- **Does it replace my `.env` files?** It solves the part that hurts with agents: keeping the credential out of files, prompts and conversations. Your project keeps what it needs at runtime.
- **Why does the reference look so verbose?** `{{secret:NAME}}` cannot be typed by accident and is obvious in a diff.
- **Can one webhook trigger get its own token without exposing it to the rest of the project?** Yes. In the Triggers editor, **Who runs it** > **Advanced** > **Environment variables** (`KEY={{secret:NAME}}`) or **MCP servers** (`{{secret:NAME}}` in a server's `env` or `headers`) apply to that trigger's runs only. For a trigger fed by untrusted input, prefer the MCP server with **Restricted run** on: the server holds the token and the agent calls its tool without ever reading it. The secret must exist in the vault of the machine that fires the trigger (pin **Machines**). See [Webhook Triggers](https://agentsroom.dev/docs/webhook-triggers.md).

## Related

- [SSH Connections](https://agentsroom.dev/docs/ssh-connections.md) and [Database Connections](https://agentsroom.dev/docs/database-connections.md): the two internal users of the vault.
- [Dev Terminals](https://agentsroom.dev/docs/dev-terminals.md): command lines where the reference is substituted.
- [Smart Hints](https://agentsroom.dev/docs/smart-hints.md): the anti-paste hint that points to the vault.
- [Bring Your Own OpenAI Key](https://agentsroom.dev/docs/bring-your-own-openai-key.md): an account key kept through the same vault.
- [MCP Servers](https://agentsroom.dev/docs/mcp-servers.md): `{{secret:NAME}}` in a server's headers or env, resolved at launch.
- [Webhook Triggers](https://agentsroom.dev/docs/webhook-triggers.md): a credential scoped to one trigger, and the restricted run that keeps it out of the agent's reach.
