Using Secrets in Agents
Agents never see secret values. They reference secrets by name using the handle syntax, and the daemon substitutes the plaintext at dispatch time.
Handle Syntax
{{secret:<name>}}
Use handles anywhere in tool call JSON arguments:
{
"url": "https://api.openai.com/v1/chat/completions",
"headers": {
"Authorization": "Bearer {{secret:openai-key}}"
}
}
{
"url": "https://api.example.com/data?key={{secret:api-key}}"
}
The daemon:
- Parses the tool input JSON
- Finds all
{{secret:<name>}}occurrences - Checks the agent has
secret.use:<name>capability - Finds an active pre-approval policy matching (name, tool, host)
- Substitutes the plaintext inline in the tool input (only for the handler, never logged)
- Calls the tool handler with the substituted input
- Scrubs the tool output for any secret values before returning to the agent
Manifest Declaration
Declare which secrets an agent may use:
spec:
capabilities:
- secret.use:openai-key
- secret.use:db-* # glob: any secret starting with "db-"
SDK Usage
The Agent SDK does not need special handling for secrets; just pass the handle as a string in your tool input:
#![allow(unused)] fn main() { let result = agent.invoke_tool("web.fetch", json!({ "url": "https://api.openai.com/v1/models", "headers": { "Authorization": "Bearer {{secret:openai-key}}" } })).await?; }
If the secret is not registered, the capability is missing, or no policy matches, the call returns a ToolFailed error describing why.
Output Scrubbing
After the tool handler returns, agentd scans the result for any registered secret values. If found, they are replaced with [REDACTED:<name>]:
{"body": "Error: invalid token [REDACTED:openai-key]"}
This prevents accidental leakage into the agent's LLM context.
sandbox.exec and Secrets
The sandbox.exec tool supports injecting secrets as environment variables in the sandboxed process:
{
"runtime": "sh",
"code": "curl -H \"Authorization: Bearer $OPENAI_KEY\" https://api.openai.com/v1/models",
"secrets": {
"OPENAI_KEY": "{{secret:openai-key}}"
}
}
The environment variable is set for the child process only. It does not appear in tool logs.