Caldera docs
calderaapp.io

The manifest

caldera.agent.yaml sits at the root of a bundle. This page describes it field by field. The manifest is strict: an unknown field is an error with its name in it (a typo such as secret: for secrets: would otherwise install an agent without the credential it needs).

The JSON Schema caldera.agent.schema.json is the early warning for an editor. Caldera's own validation, including the rules that compare fields with each other, is the authority.

For what a blueprint is and how it is published and installed, see Blueprints.

Fields

Field Required What Rules
name yes The blueprint's name. ^[a-z][a-z0-9-]{0,62}$. Must equal the blueprint's name in the workspace.
version yes This version. Semantic version without build metadata: 1.2.3 or 1.2.3-rc.1.
description yes One paragraph for people. 1 to 500 characters.
runtime yes How the agent runs. type: process with command (argument list, 1 to 50 items) and optional workdir; or type: compose with file and optional workdir; or type: adapter with command, optional workdir (a bundle path or an absolute path) and timeout_seconds (1 to 120). Never a shell string.
instructions no The files that make the agent what it is (CLAUDE.md, .claude/, prompts). Up to 50 paths; each must exist in the bundle.
mcp no An ordinary .mcp.json. One path; must exist. Credentials in it are ${NAME} placeholders.
settings no schema (up to 50 fields) and defaults. See settings.
secrets no Third-party credentials the agent needs, by name and purpose only. Up to 50. See secrets.
bindings no Access to the suite's other products, through bots. Up to 10, one per product. See bindings.
state no Paths that hold the agent's state and survive every update. Up to 50; not inside each other. Created, not shipped.
health no The command that says whether the agent works. command (argument list) and timeout_seconds (1 to 600, default 60 in the runtime).
status no The file the agent writes its report to. One path. See the runtime.
controls no The buttons Caldera may show. Any of pause, resume, run_now; default pause and resume.
logs no The only logs Caldera may ask for. Up to 50 of {name, path}; names unique; path relative to the working directory.
account no false switches the Claude account hint off. A boolean; on by default. See the account hint.

Paths

Every path in a manifest is later joined onto a directory on somebody's machine, so paths are the security surface. A path is valid when it is:

  • relative, with forward slashes, at most 200 characters;
  • free of .., . and empty segments, backslashes, NUL bytes, a leading / and a drive letter;
  • not under .caldera/ (the runtime's own directory).

A trailing slash means the directory (data/, .claude/). The runtime checks again against the real file system after resolving.

runtime

runtime:
  type: process
  command: [python3, agent.py] # argv: no shell, no quoting, nothing to inject into
  workdir: . # optional, relative to the version directory

compose names a compose file in the bundle. It is untried; see the runtime.

adapter is for an agent that keeps its own processes (a timer, a bot, a pause file other things also set):

runtime:
  type: adapter
  command: [.venv/bin/python, caldera/adapter.py] # argv, run as the runtime's user
  workdir: /home/agent/my-agent # the agent's own checkout; or a path inside the bundle
  timeout_seconds: 25 # optional: replaces the per-verb timeouts

The runtime then starts nothing, stops nothing and reads no file of the agent: it reports what adapter status prints and passes commands on to the adapter, which has the last word. A manifest with this runtime may not name status, logs, state, secrets, bindings, instructions or mcp. The whole interface is on Adapter mode and its contract.

settings

The form Caldera shows. The fields have exactly the shape the protocol reports, so what the blueprint declares is what Caldera shows.

settings:
  schema:
    - key: max_budget_usd # ^[a-z][a-z0-9_]{0,63}$
      label: Highest cost of one run # 1 to 80 characters
      type: number
      min: 1
      max: 30
      step: 1
      unit: USD
      group: Work
      help: Stops a run that would cost more than this.
  defaults:
    max_budget_usd: 5
type Value Bounds
percent a number from 0 to 1 min/max narrow it; default range 0 to 1
number a number min and max are required
bool true or false none
datetime whole Unix seconds min/max optional
text a string of at most 300 characters, no NUL none
select one of options (value, label) options required, up to 50
  • step is counted from min.
  • A default must fit its field; a default for an undeclared key is an error.
  • A key with no default is optional: it may be unset, and a set command may clear it. A key with a default cannot be cleared.
  • Keys are unique. min may not exceed max.
  • Caldera shows unit cut to 20, help to 300 and group to 60 characters.
  • Every set is checked against these bounds in the runtime, all or nothing. Caldera checks first only to tell a person at once; the runtime decides.

secrets

secrets:
  - name: ANTHROPIC_API_KEY # ^[A-Z][A-Z0-9_]{0,63}$, may not start with CALDERA_
    purpose: Runs Claude Code, if the machine is not already signed in to Claude
    optional: true

A manifest never carries a value. caldera init asks for each secret on the machine (or reads CALDERA_SECRET_<NAME>) and writes it to .caldera/secrets.env (mode 600). Secrets never pass through Caldera; they are in the agent's environment under that name. Caldera holding third-party credentials is not built.

bindings

bindings:
  - product: "<product id>" # one product of the suite, see below
    role: member # member | guest, never more
    scopes: [content:read, content:write] # 1 to 4 of content:read, content:write, admin:read, admin:write

product is the id of the product the agent needs access to. The valid values are "basalt", "lithic", "tecto" and "caldera", exactly as the schema file lists them.

One binding per product, because the token is handed over as one set of environment variables per product. See Bindings and bots.

state

state: [data/]

An update replaces instructions and code and never touches state paths. They live in <dir>/state and are linked into every version. A file the bundle ships at a state path is a seed, copied only if nothing is there yet.

health

health:
  command: [python3, health.py]
  timeout_seconds: 30

Run after an update, in the new version's working directory, with the agent's environment. Exit 0 means it works. Write it so that it needs the new version to have run, by comparing a heartbeat with CALDERA_AGENT_STARTED.

A complete example

name: report-agent
version: 1.2.0
description: Writes a weekly report from a repository and keeps a status file.
runtime:
  type: process
  command: [python3, agent.py]
instructions: [CLAUDE.md, .claude/]
settings:
  schema:
    - key: minutes_between_runs
      label: Minutes between runs
      type: number
      min: 5
      max: 1440
      unit: min
      group: Work
    - key: model
      label: Model
      type: select
      options:
        - { value: sonnet, label: Sonnet }
        - { value: opus, label: Opus }
  defaults:
    minutes_between_runs: 60
secrets:
  - name: GIT_TOKEN
    purpose: Reads the repository
    optional: true
state: [data/]
status: data/status.json
controls: [pause, resume, run_now]
logs:
  - { name: agent, path: data/agent.log }
health:
  command: [python3, health.py]
  timeout_seconds: 30