Secrets
Secure secret storage, the safety model, and how secrets flow through templates
Earl stores secret values in the OS keychain (macOS Keychain, Linux Secret Service, Windows Credential Manager). Values are never written to disk in plaintext.
Safety Model
The secret management system is designed around a core principle: AI agents can use secrets but never read them.
Secrets live in the OS keychain only
When you run earl secrets set, the value is passed directly to the OS credential store via the keyring crate. Earl uses the service name earl for all keychain entries. The plaintext value never touches the filesystem.
The CLI never exposes secret values
earl secrets get returns metadata only -- the key name, created timestamp, and updated timestamp. The value is always shown as [REDACTED]. There is no CLI flag or command to print the raw value.
Templates can reference secrets at render time
Operation templates (URL, headers, auth blocks, body) can reference secrets.<key> during request construction. The secret is fetched from the keychain, injected into the request, and then discarded from memory.
Output templates cannot access secrets
The result.output template has no access to the secrets.* namespace. Even if a template author accidentally writes {{ secrets.api_key }} in the output block, it will not resolve.
Redaction catches accidental leaks
If a secret value appears in API response data, earl's redactor replaces it with [REDACTED] before the output reaches the user or agent. The redactor checks the raw value plus its base64, hex, and URL-encoded variants.
Linux: A Secret Service daemon is required (gnome-keyring, kwallet, or
keepassxc with Secret Service enabled). If no daemon is running, earl secrets set will fail with a keyring error. See
Troubleshooting for setup guidance.
Commands
Store a secret
# Interactive prompt (value is not echoed to the terminal)
earl secrets set github.token
# Read from stdin (useful in CI or scripting)
printf '%s' "$GITHUB_TOKEN" | earl secrets set github.token --stdinThe --stdin flag reads the value from standard input and trims trailing newlines.
Show metadata
earl secrets get github.tokenOutput:
key: github.token
created_at: 2025-06-15T10:32:00Z
updated_at: 2025-06-15T10:32:00Z
value: [REDACTED]If the key does not exist, earl exits with an error.
List all secrets
earl secrets listDisplays a table of all known secret keys with their created and updated timestamps. No values are shown. If no secrets have been stored, earl prints "No secrets found."
Delete a secret
earl secrets delete github.tokenRemoves the secret from both the OS keychain and the metadata index. If the secret did not exist, earl prints a message and exits normally.
Metadata Index
Earl maintains a JSON metadata index at ~/.local/state/earl/secrets-index.json to track which keys exist and when they were created or updated. This file:
- Contains only key names and timestamps -- never secret values
- Is written with
0600permissions on Unix (owner read-write only) - Is automatically created and updated when you use
earl secrets setorearl secrets delete
The index enables earl secrets list and earl secrets get to show metadata without querying the keychain for every possible key.
Referencing Secrets in Templates
Secrets are referenced by key name in template auth blocks and expressions:
auth {
kind = "bearer"
secret = "github.token"
}auth {
kind = "api_key"
location = "header"
name = "X-API-Key"
secret = "stripe.api_key"
}API keys can be placed in a header, query parameter, or cookie.
auth {
kind = "basic"
username = "deploy"
password_secret = "registry.password"
}auth {
kind = "oauth2_profile"
profile = "my_provider"
}The OAuth2 token is fetched automatically. See Auth for profile configuration.
For SQL templates, the database connection URL is referenced as a secret:
operation {
sql {
connection_secret = "mydb.connection_url"
query = "SELECT * FROM users LIMIT 10"
}
}Secret key names use dot notation by convention (e.g., github.token, stripe.api_key, mydb.connection_url). The key in earl secrets set must exactly match the key referenced in the template.
Never put secret values directly in template files. Always store them with
earl secrets set and reference by key name.