Secrets
How to reference secrets, and what each agent ends up storing.
Stacks hold references, never values. References are resolved when you apply, and they’re never written to state or to the lock.
| Reference | Source |
|---|---|
${env:NAME} |
An environment variable |
${file:~/.secrets/x} |
The contents of a file. Relative paths start from the stack’s directory |
${op://…} and ${keychain:…} are planned, and using them now is an error.
What ends up in each agent’s file
If an agent can expand a reference itself, Pegboard writes it in that agent’s own syntax and the secret stays out of the file. If not, the value is written in plain text, and the plan warns you first.
| Agent | ${env:X} becomes |
${file:…} becomes |
|---|---|---|
| Claude Code | ${X} |
Plain text |
| Codex | Depends on the field, see below | Plain text |
| opencode | {env:X} |
{file:/absolute/path} |
| Hermes | Plain text | Plain text |
| Pi | ${X} |
Plain text |
| OMP | ${X} |
Plain text |
| OpenClaw | ${X} |
Plain text |
| Cursor | ${env:X} |
Plain text |
| Gemini CLI | ${X} |
Plain text |
Codex keeps the value out of its file in three cases, and uses plain text for everything else:
- An env var whose key is
X, asenv_vars = ["X"] Authorization: Bearer ${env:X}, asbearer_token_env_var- A header set to
${env:X}, asenv_http_headers
Rotating a secret
State stores a hash of each entry with plain-text values masked, so it can detect manual edits without depending on the secret. When you rotate a plain-text secret, plan shows it as ~ update.