Blueprints, versions and install codes
A blueprint is a prepared agent, like a Dockerfile: a named, versioned bundle
of files plus one manifest, caldera.agent.yaml, that says what the files
are. One command, caldera init <code>, sets it up on a machine; afterwards
Caldera can name a newer version and the agent applies it, checks it and keeps or
rolls back.
Existing formats are composed, not replaced. The bundle carries ordinary files (a
CLAUDE.md, a .claude/ directory, a .mcp.json, a compose file, your code).
The manifest names them and adds only what none of them says: settings, secrets by
name, bindings, state, health. The manifest is described field by field on
The manifest.
A blueprint says how an agent works, not what it works on. Caldera assigns no work.
The life of a blueprint, in order: write the files and the manifest, zip them
(the bundle), upload a version (a draft), publish it (immutable), issue an
install code, run caldera init on a machine. Afterwards a desired version
moves the agent: update, pin, roll back. The agent applies it, runs its health
check and keeps the version or rolls back.
Bundles
A bundle is a zip archive with caldera.agent.yaml at its root. It holds the
blueprint's files and nothing else: no secrets, no agent.env.
Limits (Caldera at upload and the runtime at install apply the same numbers):
| Limit | Value |
|---|---|
| Archive | 20 MB |
| Entries | 5000 |
| Unpacked, in total | 100 MB |
| One file, unpacked | 50 MB |
| Manifest | 256 KB |
Refused whole, before anything is stored: an archive that is not a zip, is
encrypted, spans disks or needs zip64; an entry with an unsafe path, or under
.caldera/; a symlink, device, pipe or socket; a name twice; a missing file that
the manifest names; a compressed entry that does not unpack to the size its header
declares; a manifest that does not validate.
The stored bytes are the uploaded bytes, never a rewrite, so the checksum an agent verifies is the checksum of what was validated.
YAML
Caldera parses the manifest with a full YAML reader (aliases are refused). The
runtime reads a subset, and refuses everything else by name: anchors, aliases,
tags, multiple documents, complex keys, tabs as indentation, and a plain scalar
that continues on the next line. Supported: block mappings and sequences, flow
sequences and mappings ([a, b], {k: v}), plain, single and double quoted
scalars, > and | block scalars, comments, one leading ---. Write plain
block-style YAML. A construct outside the subset could pass the upload and fail
at install.
The catalog
Blueprints Caldera ships itself, the same in every workspace, read-only, listed beside a workspace's own.
| Name | What it is |
|---|---|
starter |
The smallest agent: a loop that writes a heartbeat to data/status.json. Start here to see an agent appear, then replace agent.py. No secrets, no bindings, no settings. |
project-agent |
Works in one repository: clones it, sets it up, runs Claude Code in it at an interval. Settings: repository URL, branch, prompt, minutes between runs, highest cost of a run, model. Optional secrets GIT_TOKEN and ANTHROPIC_API_KEY. |
ops-agent |
An operations agent for a task board: its own scheduler with a daily run limit, a budget per run, a model choice and a board name. Two bindings to the suite's other products (a member that reads and writes, a member that reads). Optional secret ANTHROPIC_API_KEY. |
All three are version 1.0.0 today.
- One version per blueprint: the one this release of Caldera ships. A catalog
agent can fetch that version and no other, so a catalog update comes with a
release of Caldera, and a local
caldera rollbackis how a catalog agent goes back. - Install it directly, or copy it into the workspace to change it. The copy is an editable blueprint with that version already published.
Workspace blueprints and versions
The life of a version
- Create a blueprint: a name (
^[a-z][a-z0-9-]{0,62}$, unique per workspace) and a description. It has no versions yet. - Upload a version: the archive (at most 20 MB). The version number comes
from the manifest inside, and the manifest's
namemust equal the blueprint's name, becausedesirednames a blueprint by name and a version of another blueprint under this one would hand an agent somebody else's code under its own name. - A draft can be uploaded again; the new upload replaces it.
- Publish a version. This is idempotent; the time of the first publish stays. A published version never changes and cannot be deleted: it may be installed, and an agent can roll back to it. A change is a new version.
- Delete a draft version. Delete a blueprint only while no agent is installed from it (otherwise those agents could never fetch another version).
- Only published versions can be installed or named as the desired version.
Versions are ordered by semantic version (1.10.0 above 1.9.0; a pre-release
below its release).
The version rule in practice
The manifest's version is the version. To release a change you edit the
manifest's version, rebuild the bundle, upload, publish. Re-using a version
number that is published is refused (version_published). The same applies to
versions you uploaded as a test: if 1.0.1 and 1.0.2 exist, the next real
version is at least 1.0.3.
Install codes
An admin presses "Install" on a published version (or a catalog blueprint), chooses the agent name and gets a one-time code.
- Shape:
caldera_inst_plus a long random string. Only a hash is stored. Shown once. - Valid once, for 15 minutes, for one installation of one version.
- The agent name (
^[a-z][a-z0-9-]{0,62}$) becomes the agent's name in Caldera and the directory name. It must not be an agent's name in the workspace yet. - At issue, Caldera already checks what would fail later, so the dialog says it and not a terminal ten minutes on: the agent name is free, every binding's product is activated for the workspace, a same-named bot does not exist with another role, the issuer may lend the role, and the workspace stays within ten bots.
- The dialog shows two commands: fetch and verify
caldera.pyz, thenpython3 caldera.pyz init <code> --url <origin>. The warning says the code sets up an agent with a token and a bot token for each product, works once and is shown once. - Needs an admin role. Install codes are session-only: no personal token can issue one, because a token that could would be a credential that issues credentials.
Preview, then redeem
Both calls take no token; the code is the credential (the protocol).
- Preview reads what the code would install and creates and spends nothing: blueprint, version, description, agent name, runtime, secrets (name, purpose, optional), bindings. The CLI asks for secrets and notices a taken directory before the code is used.
- Redeem does it in one transaction: it claims the code (two redemptions racing for one code: exactly one wins), creates the agent and its token, creates or reuses one bot per binding with a token each, and returns the bundle once.
A refusal rolls back all of it, the claim included, so a refused redemption leaves the code usable after the cause is mended:
| Status | When |
|---|---|
| 403 | A bound product is not activated; or the person who issued the code may no longer install agents (it is checked as they stand now); or the workspace is not activated for Caldera. |
| 409 | The workspace would hold more than ten bots; a bot of that name exists with another role; the workspace has an agent of that name already. |
| 404 | An unknown, expired and used code: all the same answer, on both calls, so a code cannot be probed. |
| 429 | More than twenty install calls a minute from one address (preview and redeem together). |
An unredeemed code leaves no agent behind, and because the preview comes first, neither does a setup that is aborted at a secrets prompt.
Bindings and bots
A binding gives the agent access to one of the suite's other products without any person's credential on the machine.
At redemption, for each binding Caldera creates (or reuses) one bot in the
workspace, with the declared role, and mints a token with the declared scopes,
stamped for that product (it works at that product's address and nowhere
else). It writes the result into .caldera/agent.env:
| Variable | Is |
|---|---|
CALDERA_BINDING_<PRODUCT>_URL |
the product's origin |
CALDERA_BINDING_<PRODUCT>_WORKSPACE |
the id of the workspace the bot belongs to (the product's API addresses it by id) |
CALDERA_BINDING_<PRODUCT>_TOKEN |
the bot's token |
<PRODUCT> is the upper-cased product id. A blueprint's .mcp.json can refer to
these before anything is installed, for example
${CALDERA_BINDING_<PRODUCT>_URL}/mcp with the product id filled in. The
runtime does not rewrite that file; it passes the variables in the agent's
environment and whatever reads the file resolves them (Claude Code expands
${VAR} in .mcp.json).
Rules:
- The bot is named
<agent name> (<product>)and keeps that name when the agent is renamed. - The bot's owner is the person who issued the code. It is capped at their role
as it stands at redemption; a bot is a
memberorguest, never more. - An existing bot of that name and role is reused and never changed; one with another role is a 409.
- A workspace holds at most ten bots; the refusal says how many are needed and held.
- The product must be activated for the workspace.
- Binding tokens are valid for a year, the longest a token may be. Nothing renews one. After a year the binding breaks; see Operating agents.
- A bot is a workspace member, not product content.
Binding health. For each binding the runtime adds a health item Binding <product> to its report (at most once in five minutes), from one request to the
product with the bot's token. ok for 200 and for 403 (a token whose scopes do
not cover that read still works); bad for 401 (revoked, expired or deleted
token) and 404 (the bot is no longer a member); warn when the product cannot
be reached. Caldera shows bad as a broken binding on the agent's page. Only
the product's own bot settings can mend it. These items never count in the
agent's own level, so they cannot roll back an update.
Deleting an agent does not revoke its bots
Revoking is the product's own act. Caldera cannot do it. When an agent is deleted, its bots and their tokens stay. The delete confirmation names the bots so they can be revoked in the product's bot settings. A deleted agent's bot token still works until it expires or is revoked.
Updating, pinning and rolling back
All three are one field: the desired version of the agent. It must be a published version of the agent's own blueprint (a catalog agent: the one shipped version), or empty to withdraw the wish.
| You want | Name |
|---|---|
| Update | a newer published version |
| Roll back | the previous version |
| Pin | the version it runs (the agent sees nothing to do) |
| Withdraw the wish | nothing |
The agent's page ("Blueprint" panel) shows three versions: installed (what the code brought), running (what the agent says it runs now) and wanted (Caldera's wish), the last outcome in the agent's own words, and the broken bindings. The change is followed to the agent's answer: waiting for the next report, then applied, rolled back by the agent, or failed.
The runtime then fetches the bundle with its own token (its own blueprint's published versions only; another blueprint's version and an unknown one answer 404). See the runtime and Operating agents.
Writing your own blueprint, step by step
The example is a private assistant that sorts new mail and writes reply drafts.
-
Make the agent one long-running process that does its own scheduling and writes a status file. The example has one process, started with
python3 -m agent.cli serve, one thread per job, writingdata/status.jsonevery 30 seconds and on every change. Pause and resume are then the runtime stopping and starting that process. (An agent that cannot be one process uses an adapter instead.) -
Decide what is state. Anything the agent learns or stores must live under a
statepath, or an update will not keep it. The example keeps its secrets and database outside the blueprint entirely (in the user's own config and state directories) and declares onlydata/for its status file. -
Write the manifest. The example's is short:
name: mail-assistant version: 1.0.0 description: >- Sorts new mail and writes reply drafts. It never sends. Only numbers go out to Caldera, never contents. runtime: type: process command: [python3, -m, agent.cli, serve] state: [data/] status: data/status.json controls: [pause, resume, run_now] health: command: [python3, -m, agent.cli, health] timeout_seconds: 40It declares no
secrets(soinitasks for nothing), nosettingsand nologs(so nothing is asked for and no log ever leaves the machine). -
Write the health check so that it needs the new version to have worked. The example's check verifies its configuration and that the programs it calls are in the path, then waits for a heartbeat in the status file that is newer than
CALDERA_AGENT_STARTED. A fresh-looking file the old version left behind does not pass. -
Build the bundle from a fixed list of files, never "everything except". The example's build script includes code, prompts, templates, schemas, a config example and the manifest; a name that looks like a secret, state or
.gitstops the build; fixed order, timestamps and modes mean the same files give the same bytes. A bundle never holds secrets or state. -
Validate by uploading a draft. Caldera validates the manifest and the archive at upload and stores nothing on a refusal. The refusal names the field (
manifest_invalidcarries its path) or the rule. A draft can be uploaded again as often as needed; nothing is installable until it is published. -
Upload and publish. In the workspace: Blueprints, "New blueprint" (the name must equal the manifest's
name), "Upload a version" with the zip, then "Publish". -
Issue a code and install on a machine (the runtime).
-
Prove independence and an update with a forced failure (Connecting an agent). The example's check was: offline pause and resume, an update, and a deliberately broken version whose health command exits 1, rolled back within a second.
-
Release the next version by raising
versionin the manifest (never to a number that exists), rebuilding, uploading, publishing, and naming it as the desired version.
Not built
- Cloud spawning of agents and declared dependencies between blueprints.
- A marketplace or sharing across workspaces.
- Third-party credentials held by Caldera: they stay on the machine.
- A package registry for the runtime.