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.
| Field | Required | Notes |
|---|---|---|
credentialId | yes | The cred_... id from the Anima console or anima vault list |
field | yes | Dot-path into the credential (e.g. apiKey.key, login.password) |
agentId | no | Explicit agent scope; defaults to the CLI’s authenticated agent |
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).
| Field | Required | Notes |
|---|---|---|
name | yes | Must be present in the environment at resolve time |
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).
| Field | Required | Notes |
|---|---|---|
command | yes | Bare binary name or absolute path; shell metacharacters (;, |, `, $, &) are rejected |
args | no | String array. Spawned with shell: false so each element is a literal argv slot |
passEnv | no | Env var names passed through to the subprocess — everything else is stripped |
cwd | no | Working directory for the subprocess |
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.
