---
title: Secrets | Letta Docs
description: Securely store API keys and tokens for your agent to use in shell commands
---

Secrets let your agent use sensitive values like API keys and tokens in shell commands without ever seeing the actual values. The agent writes `$SECRET_NAME` in commands, Letta Code substitutes the real value at execution time, and scrubs it from all output before the agent sees the result.

## Managing secrets

Use the `/secret` slash command to manage your agent’s secrets:

```
> /secret set OPENAI_API_KEY sk-proj-abc123...
Secret '$OPENAI_API_KEY' set.
```

```
> /secret list
Available secrets (2):
  $OPENAI_API_KEY
  $GITHUB_TOKEN
```

```
> /secret unset GITHUB_TOKEN
Secret '$GITHUB_TOKEN' unset.
```

### Naming rules

Secret names must be uppercase letters, numbers, and underscores only, starting with a letter or underscore. Names are automatically normalized to uppercase.

| Valid          | Invalid                                  |
| -------------- | ---------------------------------------- |
| `API_KEY`      | `api-key` (hyphens not allowed)          |
| `MY_TOKEN_123` | `123_TOKEN` (cannot start with a number) |
| `_PRIVATE`     | `my secret` (no spaces)                  |

## Using secrets in commands

Reference secrets with `$SECRET_NAME` syntax in any shell command. Your agent can discover available secrets through its memory and use them naturally:

```
> Can you call the OpenAI API to list my models?


Agent runs: curl -H "Authorization: Bearer $OPENAI_API_KEY" https://api.openai.com/v1/models
```

The agent writes the command with `$OPENAI_API_KEY`. Letta Code substitutes the actual key value when executing the command, then scrubs the value from the output. The agent never sees `sk-proj-abc123...` in any tool result.

### Which tools support secrets?

Secret substitution applies to all shell-based tools:

- `Bash` / `ShellCommand`
- `TaskOutput`

Read-only tools like `Read`, `Grep`, and `Glob` do not perform secret substitution since they don’t execute shell commands.

## How it works

Secrets are protected through multiple layers:

### Substitution at execution time

When the agent calls a shell tool, Letta Code scans the command arguments for `$SECRET_NAME` patterns and replaces them with the actual values right before execution. The agent’s tool call in the conversation history always shows the `$SECRET_NAME` placeholder, never the real value.

### Output scrubbing

After a shell command runs, Letta Code scans all output (stdout, stderr, and the full tool response) for any occurrence of a secret value and replaces it with `$SECRET_NAME`. This prevents accidental leaks even if a command echoes the value.

### Memory integration

Your agent’s memory includes a list of available secret *names* so it knows what secrets are available. Secret values are never written to memory.

```
## Available Secrets


Use `$SECRET_NAME` syntax in shell commands to reference these secrets:


- `$OPENAI_API_KEY`
- `$GITHUB_TOKEN`
```

### Server-side storage

Secrets are stored on the Letta server as part of the agent, not on your local machine. They are fetched and cached in memory when Letta Code starts.

Because secrets are tied to the agent, they are available anywhere you use that agent. If you set a secret on your laptop and then connect to the same agent from a different machine, the secret is already there. This makes it easy to share credentials across devices without reconfiguring each one.

### Input redaction

When you run `/secret set KEY value`, the value is redacted from the command history. Other users reviewing the conversation will see `/secret set KEY ***`.

## See also

- [Slash commands](/letta-code/slash-commands/index.md) - Full list of built-in commands
- [Permissions](/letta-code/permissions/index.md) - Control what tools your agent can use
