> ## Documentation Index
> Fetch the complete documentation index at: https://docs.useanima.sh/llms.txt
> Use this file to discover all available pages before exploring further.

# SecretRef & anima.json

> A declarative spec for pointing at secrets without hardcoding them — used by anima vault exec, anima vault proxy, and the zero-knowledge MCP tools.

# 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:

```json theme={null}
{ "source": "anima", "credentialId": "cred_abc123", "field": "apiKey.key" }
```

The Anima CLI resolves these refs at execution time — the agent composing the command, and the LLM reviewing its output, never see the actual value.

## The three sources

Every SecretRef has a `source` 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.

```json theme={null}
{
  "source": "anima",
  "credentialId": "cred_01HXYZ...",
  "field": "apiKey.key",
  "agentId": "agent_optional"
}
```

| 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    |

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).

```json theme={null}
{ "source": "env", "name": "MY_DEV_TOKEN" }
```

| Field  | Required | Notes                                              |
| ------ | -------- | -------------------------------------------------- |
| `name` | yes      | Must be present in the environment at resolve time |

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).

```json theme={null}
{
  "source": "exec",
  "command": "aws",
  "args": ["sts", "get-session-token", "--output", "text"]
}
```

| 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                                                                |

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:

```json theme={null}
{
  "$schema": "https://docs.useanima.sh/schemas/anima.json",
  "secrets": {
    "GH_TOKEN":    { "source": "anima", "credentialId": "cred_github", "field": "apiKey.key" },
    "DATABASE_URL":{ "source": "env",   "name": "DATABASE_URL" },
    "AWS_KEY":     {
      "source":  "exec",
      "command": "aws",
      "args":    ["sts", "get-session-token", "--output", "text"]
    }
  }
}
```

The keys (`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](https://docs.useanima.sh/schemas/anima.json).

### Using it

```bash theme={null}
# Resolve all refs and exec a subprocess with them in-env
anima vault exec -- gh api /user

# Proxy a single ref through an HTTPS injector
anima vault proxy --cred GH_TOKEN --allow-host api.github.com --port 19840

# Quick lookup (plaintext; requires `anima vault unlock` first)
anima vault get GH_TOKEN
```

If the CLI can't resolve a ref (missing env var, failing exec, deleted vault credential) it refuses to run and emits a structured error — no partial execution, no silent fallback.

## Why not just `.env`?

Three reasons:

1. **`.env` files are static.** `exec` sources pull fresh values on every resolve — matters for STS tokens, SSO-minted GitHub App tokens, and anything else with a lifetime under an hour.
2. **`.env` files 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.
3. **`.env` files don't participate in the audit log.** Every `anima`-source resolution is attributed to an agent or user and shows up in the console Access Log. Agents that ingest a `.env` file by accident are a common leak vector; an `anima.json` commits 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.command` may not contain whitespace or `;`, `|`, `&`, `<`, `>`, `$`, `` ` ``, `\`. If you need a pipeline, write a wrapper script and point `command` at it.
* `exec` child processes get a minimal environment: `PATH`, plus only the variables listed in `passEnv`. Everything else is dropped.
* `anima` refs 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.

See also: [Vault overview](/vault), [Security](/security).
