SecretRef & anima.json
A SecretRef is a declarative pointer to a secret. Instead of writing API_KEY=sk-... in a .env file and praying it doesn’t end up in a commit or an LLM’s context window, you write:
The three sources
Every SecretRef has asource field that determines where the value comes from. Only these three are supported, and that’s deliberate — every additional source is a new place a secret can be misused.
anima — Anima Vault
The default. Points at a credential in your vault.
Under the hood the CLI mints a single-use
vtk_ token, exchanges it, and the resolved value never touches disk. Every resolution is written to the audit log with the actor’s key type recorded — reveals via a master key (mk_) show up distinctly from agent-scoped accesses.
env — Environment variable
Escape hatch for secrets that aren’t yet migrated into Anima (rotating dev tokens, one-off sandbox keys).
If the variable is unset, the CLI refuses to run. It does not fall back to an empty string — that pattern causes too many “it worked locally but 401’d in prod” bugs.
exec — Trusted binary
For dynamic secrets that come from a local tool (AWS STS, op read, gcloud auth print-access-token, short-lived GitHub App tokens).
Output is captured with a 15-second timeout and a 1 MB buffer cap. If the binary exits non-zero, the CLI refuses to run. The child process starts with a minimal environment: only the variables listed in
passEnv, plus PATH so the binary can be found. Be explicit about what your provider needs — e.g. "passEnv": ["HOME", "AWS_PROFILE"] for the AWS CLI.
anima.json — putting it together
Drop an anima.json at the root of any project (or any ancestor directory — the CLI walks up from cwd). The shape:
GH_TOKEN, DATABASE_URL, AWS_KEY) are the variable names that will be exposed to whatever command consumes the refs — typically environment variables passed to a child process.
The $schema line is optional, but with it any JSON-Schema-aware editor (VS Code out of the box) validates refs and autocompletes fields as you type. The schema is published at docs.useanima.sh/schemas/anima.json.
Using it
Why not just .env?
Three reasons:
.envfiles are static.execsources pull fresh values on every resolve — matters for STS tokens, SSO-minted GitHub App tokens, and anything else with a lifetime under an hour..envfiles are untyped. A SecretRef is a JSON schema — you get IDE completion, and the CLI can refuse to run if the shape is wrong before the subprocess starts..envfiles don’t participate in the audit log. Everyanima-source resolution is attributed to an agent or user and shows up in the console Access Log. Agents that ingest a.envfile by accident are a common leak vector; ananima.jsoncommits only references — the values live exclusively in the vault.
Security rules the resolver enforces
These are non-negotiable — the resolver refuses to run if any are violated:exec.commandmay not contain whitespace or;,|,&,<,>,$,`,\. If you need a pipeline, write a wrapper script and pointcommandat it.execchild processes get a minimal environment:PATH, plus only the variables listed inpassEnv. Everything else is dropped.animarefs require an active CLI auth context — the resolver prompts for login rather than falling through silently.- Resolved values never reach disk. They live in process memory for the duration of the child, then are overwritten.
