A codon is one sealed agent task in a sequence of tasks. Before the agent can do its work, the environment often needs preparation: dependencies installed, templates copied, scaffolding generated. That preparation is mechanical and repeatable, which makes it a poor use of an agent's judgment and context. Hankweave gives it a declared stage of its own, called a rig. This page explains what a rig does before a codon starts, how its operations and failure policy work, what checkpointing preserves, and where the boundaries of the mechanism lie.
Why setup belongs before the agent#
We could begin a codon's prompt with "first, install dependencies and copy the template." But then we would be asking the agent to do mechanical work before it reaches the judgment we need from it, and paying for that work in tokens and context.
A rig is the declared setup stage for a codon. A rig executes in the preparing state, before that codon's agent session spawns. Under the default fail-fast policy, each operation must complete successfully before the codon starts. If setup fails, the codon fails during preparing; agent work does not begin and its tokens are not spent on work that was bound to fail. The per-operation allowFailure setting is the deliberate exception for best-effort operations.
This does not make every rig intrinsically deterministic. With pinned dependencies, the same copy source and command on the same machine produce the same filesystem. The author makes that repeatable by pinning everything the rig touches. Agent-led setup is stochastic and unversioned: it may install different dependency versions, create different scaffolding, or fail without making the cause visible. A rig puts that setup in version-controlled code in the hank directory – the project directory that supplies rig sources – instead of leaving it as an improvised prompt instruction.
The sequence below shows the order of events: the rig runs to completion, the resulting filesystem is sealed as a checkpoint, and only then does the agent session start.
Read the diagram as text
+---------------------------------------------+
| rig executes: copy + command |
+-----------------------+---------------------+
| completes fully before the codon starts
v
+---------------------------------------------+
| filesystem state sealed as a rig-setup |
| checkpoint |
+-----------------------+---------------------+
| the prepared state the agent starts from
v
+---------------------------------------------+
| agent session spawns, sees the prepared |
| environment |
+---------------------------------------------+
// pseudocode, not the implementation
rig executes (copy + command) → filesystem state sealed as rig-setup checkpoint → agent session spawns → agent sees prepared environment
The diagram abbreviates the two allowed operation types; an ordered rig may use either one or both. The rig prepares the filesystem state that the agent will see.
Before connecting a rig to an agent, execute every rig command manually against sample data. Once we have made setup explicit and verified it, rollback to the rig-setup checkpoint and replay can preserve the prepared state while the agent's judgment happens again. We can reserve the agent's attention for the work that requires it: if a shell script can do the setup, use a rig.
What a rig does before work starts#
A codon may omit rigSetup. When present, it is an ordered array of operations. Each item is either a copy or a command, selected by its type. The field summary:
| field | type | default | required | constraints | description |
|---|---|---|---|---|---|
type | string | yes | = copy | Type of setup operation | |
copy | object | yes | |||
allowFailure | boolean | false | no | If true, failure of this operation won't fail the codon (default: false). Recommended for rig setup in loop codons where operations might fail in some iterations (e.g., copying files that don't exist yet). | |
type | string | yes | = command | Type of setup operation | |
command | object | yes | |||
allowFailure | boolean | false | no | If true, failure of this operation won't fail the codon (default: false). Recommended for rig setup in loop codons where operations might fail in some iterations (e.g., running commands that might not succeed initially). |
A copy operation requires from and to strings. Think of them as starting from two different roots: from names a portable relative source path inside the hank directory under the strict-reference policy, while to is joined to agentRootPath when the rig executes, so an ordinary relative value lands in the agent workspace. The execution directory contains that workspace and other runtime state; the load-time containment check keeps the resolved target parent inside it. The complete strict-reference contract belongs to the hank JSON reference. to names the full destination, not a parent directory. For example, from: "templates/foo" with to: "src/foo" places directory foo at src/foo; it does not append the source directory name to make src/foo/foo. To place a child beneath that destination, name the child explicitly, such as src/foo/child.
Create the destination's parent before the copy. For that src/foo example, put a command operation with "run": "mkdir -p 'src'" first. Copying to deep/nested/file.json needs "run": "mkdir -p 'deep/nested'"; copy does not create those parents for you.
A command operation requires a shell command string in run. Its optional workingDirectory is "project" by default: here, project means the agent-root project workspace. The other value, "lastCopied", means the destination of the most recent copy. If no earlier copy exists, the runtime falls back to agentRootPath; it does not fail for that reason.
run is a shell string, not an argument array. Quote each path argument inside that string, as in "run": "bun 'pipeline/check input.ts' 'read_only_data_source/source notes.txt'" for a checker you have copied to that location. The outer JSON quotes encode the string; the inner shell quotes keep each path with spaces as one argument. Do not interpolate untrusted text into a shell command.
| field | type | default | required | constraints | description |
|---|---|---|---|---|---|
workingDirectory | enum | project | no | project | lastCopied | Working directory for command execution (default: 'project') |
- Add `rigSetup` to prepare your environment before a codon runs
Rig commands inherit the codon's env block, a mapping of variable names to strings. Variables declared there are available during dependency installation or any other rig command, and in the agent process.
While a rig runs, its output is visible rather than silent. Setup output streams through throttled rig.output events: at most one event per second for each output stream, standard output and standard error. Each event carries the codon ID, stream, a trimmed output line capped at 500 characters, and the rig operation index (commandIndex). The event samples the last line of each output chunk, so interior lines in a multi-line chunk may not appear. The TUI uses these events to show setup progress rather than an opaque wait.
The lifecycle reports an info event when setup starts and another for each operation. It reports rig.setup.completed with commandCount (the total operations), durationMs, and whether a checkpoint was created (createdCheckpoint). A failed setup reports rig.setup.failed with its failureType, exitCode, and whether the failure was ignored (ignored). That ignored flag connects to the failure policy, which is the next question: when should a failed operation stop the codon, and when should it not?
When a rig failure should continue#
By default, allowFailure is false for both operation types. A failed operation therefore stops the codon. Set allowFailure: true when the operation is best-effort: Hankweave logs a warning and the codon continues.
This setting has a specific loop use. A loop codon may prepare an iteration with an operation whose input is produced by an earlier iteration. The agent workspace persists across iterations, so that earlier output is still present when the next iteration's rig executes. The operation can fail on the first iteration and succeed later, so it can opt into best-effort behavior. The iteration mechanics belong to loops. When a loop codon has rig operations without allowFailure, Hankweave emits this configuration-load warning:
rigSetup in loop codon should use 'allowFailure: true' to prevent loop termination on setup failures. This is especially important if subsequent iterations might fail (e.g., trying to copy files to where they already exist).
For a resume workflow whose setup has partly completed, pass the CLI flag --ignore-rig-failures to make every rig operation globally best-effort. It overrides each operation's allowFailure setting. A rig.setup.failed event records ignored: true when either the per-operation policy or the global flag swallows the failure.
Use the narrow policy when setup is optional for a particular operation. Keep the default fail-fast behavior when the prepared environment is required for safe agent work; the global flag is broader and is intended for the resume situation.
What rig setup checkpointing gives you#
When rig setup completes, the runtime creates a rig-setup checkpoint. This is a git commit in the separate (shadow) git repository whose metadata lives at .hankweave/checkpoints/ inside the execution directory. It captures the filesystem state from which the agent starts; it is runtime state, not another item to add to rigSetup.
That checkpoint is what makes resume, replay and rollback cheap. On resume, Hankweave skips setup when the runtime has a rigSetupCheckpoint for the codon: the environment is already prepared. Replay also skips setup because it copies the original execution directory wholesale, including the post-setup filesystem state. Resume and replay therefore preserve the prepared state; rollback is the operation that chooses which work to repeat.
Rollback lets you choose which work to repeat. Rolling back to a rig-setup checkpoint repeats only the agent's work with the same prepared environment. Rolling back to the previous codon's checkpoint repeats both that codon's rig setup and agent work. The checkpoint type and wider rollback mechanics belong to checkpoints; here, the useful boundary is the one between preparation and judgment.
How to clean up after a rig#
Setup can leave templates or other intermediate files in the agent workspace. archiveOnSuccess is a codon-level field, separate from rigSetup: it accepts an array of file globs relative to agentRoot/. When the codon completes successfully, matching files move into rigArchive/ inside the execution directory and leave the agent workspace.
| field | type | default | required | constraints | description |
|---|---|---|---|---|---|
archiveOnSuccess | array<string> | no | Paths to archive after successful completion. These files/directories are moved to rigArchive/ after the codon completes successfully. Paths are relative to the agent workspace (agentRoot/). Archived files can be restor… |
The archive patterns must be relative, must not contain .., and must not be absolute; the schema enforces these limits at load. For the complete archive path contract and automatic restore during rollback, see the execution-directory reference.
The destination path depends on where the codon runs. At codon level inside a loop, a matching file is archived below rigArchive/<loopId>-<iteration>/<codonId>-<iteration>/<path>. Runtime IDs such as edit#0 use edit-0 in that path. The loop-archive fixture uses the file glob current-project/**, not the bare directory name, and records the resulting file at rigArchive/revise-0/edit-0/current-project/history.txt. On the next iteration, its rig copies the previous iteration's archived input back from the sibling path ../rigArchive/revise-0/edit-0/current-project/ while its command executes from agentRoot/.
A non-loop codon archives to rigArchive/<codonId>/<path>. A loop-level archiveOnSuccess is applied once when the loop terminates, not once per iteration, and archives to rigArchive/<loopId>-loop/<path>. The loop-level field is separate from the codon-level field; loop behavior belongs to loops, and the full destination and rollback contract belongs to the execution-directory reference.
The rigArchive/ directory is excluded from the checkpoint git repository by a .gitignore at the execution-directory root; archives are tracked by a manifest rather than by git.
What rigs cannot touch#
Rig operations are constrained at load time, before anything executes. The destination of a copy operation is sandboxed to the execution directory: the runtime checks that the resolved target parent stays inside that directory. The schema requires a non-empty string; an absolute or lexically ..-containing target is not rejected merely for that spelling if it still resolves inside the execution directory.
The source is constrained too: copy.from must point inside the hank directory and follow the file-reference rules. It cannot copy from an arbitrary location.
The loader rejects a copy.from that resolves to the hank directory itself. That includes spellings such as . and sub/.., which could otherwise copy the entire project into the execution environment. The load-time diagnostic ends with copy source "<path>" is the hank directory itself; move the files into a subdirectory and copy that (the full message also carries the codon context and rig-setup item number). When a source names a directory, Hankweave scans its tree with lstat and rejects symlinks, FIFOs, sockets, and device files before the tree is used.
Two execution-time behaviors are worth knowing in advance. A target that already exists is silently removed first, whether it is a file or directory, and then replaced by the copy. And the target parent must exist when the copy operation executes. If deep/nested/path/ is absent inside the execution directory, copying to deep/nested/path/file.json fails in the preparing phase with Target parent directory does not exist; it is not a load-time parent-existence failure.
Where rigs earn their place#
For worked examples, see the copy-script rigs, assemble-doc rig, and static check rigs in the documentation-pipeline guide.
We can make the same separation in the anchor fixture, a saved example Hank. Corpus-integrity preflight – checksums, shape and watermark checks – is setup work rather than agent judgment. Its normalize-aster codon has one rigSetup array with three steps: create pipeline, copy rigs/preflight.ts to pipeline/preflight.ts, and execute bun pipeline/preflight.ts. There is no separate schema-preflight rig. The paths satisfy the strict-reference rules, and validation exits with 0. The rig configuration from that codon:
"rigSetup": [
{
"type": "command",
"command": {
"run": "mkdir -p pipeline"
}
},
{
"type": "copy",
"copy": {
"from": "rigs/preflight.ts",
"to": "pipeline/preflight.ts"
}
},
{
"type": "command",
"command": {
"run": "bun pipeline/preflight.ts"
}
}
],
When designing your own setup, ask which operations you can declare and check before involving an agent.
A rig's command can also call a lightweight language model for a quick extraction or classification operation. Keeping that call outside the agent's context window reserves the codon's context for the judgment it needs. The script chooses its own client, model, and credentials; Hankweave's codon model resolution does not automatically configure an arbitrary rig script.
An external model or API call made by that script has its own billing scope. Its charges are not automatically included in tracked codon model cost or constrained by the codon's dollar cap. Give the script its own request limits and deadline, and include its provider bill when estimating the whole workflow. Declaring the call in a rig makes it inspectable; it does not make the model response deterministic or free.