Design Codons and Handoffs

Decide where one codon's job ends#

A hank is the hank.json work program Hankweave loads, and its hank array is the immutable sequence of codons that carry the logic. Designing a hank means deciding where one codon's job ends and the next begins, and what files cross each boundary. This page works through those decisions on the shipped anchor hank, a seven-codon example that normalizes supplier quotes, validates and reconciles them, and produces an award brief.

Three questions guide the placement of a boundary. Does the next job need a different model tier? Does it need a different failure policy? Does the current job produce something a person might inspect? A yes is evidence for a new codon, not an automatic rule. Keep work together when it must succeed or fail as a unit, or when the task needs no intermediate checkpoint.

The anchor hank processes RFQ NC-RFQ-0042, with five BOM parts and eight quoting suppliers: AST, BCN, CDR, DVR, EMB, FJR, HBR, and IRS. GRN is quarantined, not treated as a ninth quoting supplier. Five codons use haiku; the two judgment codons use pi/baseten/deepseek-ai/DeepSeek-V4-Pro. Setup rigs render the financial section and exception CSV.

To see why boundaries matter, suppose we need to copy source values, then choose between conflicting records. If we put both jobs in one codon, a bad result is harder to trace to copying or policy. In the anchor hank, normalize-aster writes both Aster submissions to envelope-aster.json; validate-and-repair later decides which submission wins. We can inspect that file and see the conflict before a decision is made.

Three or more distinct tasks are also a strong signal that a codon has too much responsibility:

Scroll to explore the table →
Too heavySplit into
Parse doc, find stubs, read source, analyze, write notesExtract → Research → Synthesize
Read codebase and generate docsAnalyze structure → Generate docs
Review and fix all issuesReview (find issues) → Fix (address them)

A preparation codon that only extracts, lists, or maps can give later codons a smaller input. Separate codons provide per-codon logs, exact failure attribution, incremental resume, and a checkpoint for rollback. A checkpoint seals the files named by checkpointedFiles.

The normalize-* codons copy fields verbatim and leave deduplication, alias resolution, and validity checks to validate-and-repair. Even though Aster's rev2 supersedes field makes the likely winner look mechanical, deciding the winner downstream keeps the conflict visible to the codon that records exceptions. This narrower assignment does not make extraction infallible: a normalizer can still copy a value incorrectly, omit output, hit its budget, or fail for another runtime reason.

Treat onFailure, continuationMode, and retryConfig as boundary inputs; their field semantics belong on codons. Find candidate boundaries during the observation step in discover before you freeze. Use measured runs to compare model tiers; do not treat one run's price as universal.

Match constraints to the work#

Prescribe the procedure when the output must be exact, as in parsing, validation, or rendering. When a task requires exploration or judgment, state the goal, decision rules, and limits without scripting every reasoning step. These two modes are often called tight and loose.

Let's compare two assignments in the anchor. normalize-aster is tight: its prompt requires an envelope with exact fields, never omitting a key or inventing a value. validate-and-repair is loose: its prompt supplies rules such as "never multiply a missing price or invent one" and "continue must never mean silent omission," but does not prescribe every reasoning move. award-brief becomes tight again because every claim must already be settled and it makes no new judgment calls.

Keep judgment between fixed handoffs. validate-and-repair writes exactly 14 declared fields per validated record. Its ledger rows have seven declared fields; the EXPIRED_VALIDITY row alone adds judgment_call, options, tentative_resolution, and confidence. The model can choose how to reach a decision, while the next codon still receives a predictable shape that you can inspect and roll back.

Do not prescribe every codon this closely. A prompt that assumes every input follows one expected path can fail when the input varies. Choose the amount of freedom for each job. Prompt craft for these modes belongs on prompts.

The opening of the validate-and-repair prompt shows the loose mode in practice. Read it for the boundary it draws: the handoff files and their shapes are fixed, while the rules govern how the model resolves what it finds inside them.

Prompt example – the input contract for a judgment codon.

MD
# Validate & Repair Envelopes

You check ALL normalized envelopes (eight suppliers: AST, BCN, CDR from the dialect codons; DVR, EMB, FJR, HBR, IRS from the extracts codon) plus the intake survey against the RFQ contract and the corpus lookups, repair what you can repair deterministically, and route everything else — including one deliberately unresolvable judgment call — to a typed exception ledger. **Continue must never mean silent omission**: if a line, a part, or a whole quote doesn't cleanly resolve, it must appear in `exception-ledger.json` with a reason. It may never simply vanish from your output.

From the current directory (written by the three normalize codons and survey-and-extracts):
- `envelope-aster.json` — a JSON array of **two** envelope objects (Aster's original submission and its rev2 re-submission).
- `envelope-beacon.json` — a JSON array of **one** envelope object.
- `envelope-cedar.json` — a JSON array of **one** envelope object.
- `envelope-dover.json`, `envelope-embar.json`, `envelope-fjord.json`, `envelope-harbor.json`, `envelope-iris.json` — one envelope array each (native extracts, normalized).
- `survey-notes.json` — the raw-intake survey; carry every `quarantined` entry into the exception ledger as type `UNKNOWN_TEMPLATE` (quarantine is a success path — zero rows, onboarding note).

Notice the clause "continue must never mean silent omission." It operationalizes the whole design principle: a line, part, or quote that does not resolve cleanly must land in exception-ledger.json with a reason, so nothing can drop out of the pipeline between handoffs. The judgment stays loose; the obligation to account for every input is absolute.

Reset context between independent jobs#

A long conversation accumulates details that the next job may not need, and early decisions can keep influencing later work. Starting the next codon with a fresh context leaves the previous model conversation behind. The codon still uses the shared agent workspace; a fresh conversation does not restrict which files it can read. If the result is wrong, the files and checkpoints show which job produced it and where to resume. For a broader explanation of the problem with one long context, see why Hankweave.

All seven anchor codons use continuationMode: "fresh"; their explicit handoffs use files rather than the preceding model conversation. Use continue-previous when the next job genuinely needs the preceding conversation; its semantics belong on codons.

Pass work through files consumers can inspect#

Before freezing a handoff, walk the execution path. For every intermediate file, ask what the next codon expects to read and where we have named that consumer. Let's follow the anchor's files:

  • The four input codons write the eight envelope-*.json files and survey-notes.json; validate-and-repair reads them.
  • validate-and-repair writes validated-records.json and exception-ledger.json; reconcile reads them.
  • reconcile writes unified-records.csv and appends to exception-ledger.json; award-brief reads them.
  • award-brief writes only the qualitative part of award-brief.md; render-award.ts is a setup rig that derives the cited financial section, and render-exceptions.ts is a setup rig that serializes exceptions.csv from the unchanged ledger. A human reviewer reads the resulting deliverables.

Name the consumer inside the contract. Each downstream prompt has a Read section listing its upstream files: validate-and-repair names the envelopes and survey, reconcile names the validation outputs, and award-brief names the reconciliation outputs. Check every intermediate by name in its consumer's Read section.

Make the exception ledger an append-only contract. reconcile may append rows, but it must not remove or rewrite a prior exception_id.

Apply the rule to data boundaries too. The prepared task-data directory is available inside the execution directory as read_only_data_source/. Treat that input as read-only, but do not mistake the directory name for a permissions boundary: the runtime creates a symlink or copy, not a read-only mount. The prompts prohibit reading the held-out truth/ directory because that is the answer key checked after the run. Keep checkpointedFiles complete: it is the enforcement surface that makes every intermediate inspectable and rollback-able at the boundary. Checkpoint mechanics belong on checkpoints.

Name files for their consumer, not for the answer you hope they contain. The anchor calls its output unified-records.csv, even though it matches the held-out answer key's columns. The name keeps the hank's output distinct from that answer key.

When a prompt author inserted a three-supplier enumeration into reconcile, that codon followed the written instruction against the eight-supplier corpus. It followed what was written, not what the author meant.

Check-it: inspect each downstream Read section and find every upstream filename there; in particular, reconcile names validated-records.json and exception-ledger.json as inputs.

Write for an agent with no hidden context#

Write as if the agent knows only the prompt and the files. We know the user's intent, what earlier codons did, why a decision was made, what the data looks like, and what “good” looks like. The agent can use that context only if we put it in the prompt or a file.

Do not write “after the rig runs” or “in the next codon”: neither phrase tells a fresh agent what state it will find. Describe that state instead: file paths, shapes, and the condition that makes the next action safe. Apply this self-containment test to every prompt, bridge, and handoff: “If I were a fresh agent seeing only this prompt and these files, would I know what to do?”

The common failures are implicit instructions: “continue the analysis” when no analysis exists, “use the approach we discussed” when there was no discussion, and “fix the issues” without saying what counts as an issue.

Make the information gap explicit#

You know why the task matters, what happened before, what “good” looks like, the edge cases you have met, and your team's conventions. The model knows only what is in the prompt, its context window, and general world knowledge. If two outputs could both satisfy the stated task but you care which one it chooses, state that preference. Also name the choices the agent may make, and explain constraints that should guide decisions at the margins.

The anchor does this in normalize-aster.md: it explains that deduplication is a judgment call for validate-and-repair, not that codon, and its prohibitions explain themselves. It also describes state instead of runtime concepts: normalize-aster.md and validate-and-repair.md tell the model to use shell commands such as cat and ls to read read_only_data_source/, because the directory may be a symlink. The survey prompt states that task inputs are under read_only_data_source/ and forbids reading an answer key or anything outside the supplied task inputs.

For the prompt method–Context, Process, Constraints, Output; anchored paths; the per-sentence why test; and HTML comments–use prompts.

Separate building from review#

Give the completed artifact to a separate review pass. The reviewer should see the artifact and its requirements, not the builder's reasoning history. A cold reader can expose assumptions the builder no longer notices. A less capable model can help check whether instructions are understandable, but is not the default choice for correctness review: the reviewer still needs enough capability for the task and independent evidence, such as source records, executable checks, or a held-out answer. When a review finds a problem, give the current artifact and review findings to a fresh improvement pass.

In the hank, the quality-observer sentinel–an event-triggered observer configured alongside the codon–fires after validate-and-repair. It is an event observer, not an artifact checker: it receives completion-event status and budget fields, cannot read output files, and never edits them. Artifact existence, row coverage, and correctness belong to an ordinary rig or an artifact-reading codon. A rig is the setup or checking script that prepares or mechanically verifies those files; it is not another codon.

The observer's configuration makes that scope explicit. Read the description and prompt below for what the sentinel is told it can and cannot claim:

Example observer contract.

JSON
{
  "description": "Observes the validate-and-repair completion event. Reports only status and budget fields present in that event; cannot read or verify output artifacts.",
  "userPromptText": "The codon `validate-and-repair` completed. Here are the triggering completion events:\n\n<%= JSON.stringify(it.events, null, 1) %>\n\nSummarize only status, failure reasons and budget fields actually present. These completion events do not provide file contents or file.updated events. State explicitly that artifact existence, row coverage and correctness cannot be verified from this input. Never treat missing file-update events as proof of missing files. Observe and report only.",
}

The prompt instructs the observer to state plainly that artifact existence, row coverage, and correctness cannot be verified from its input, and never to treat missing file-update events as proof of missing files. That disclaimer is not caution for its own sake: the sentinel runs on harness lifecycle events, not on disk state, so it has no basis to judge the artifacts at all.

A documentation review used this separation on one draft at a time. It caught a claim that promptFile and promptText were mutually exclusive; the contract actually requires at least one and gives promptFile precedence. The builder had silently read the intended rule into the draft, while the fresh reviewer evaluated the words on the page. Find the broader loop on reliability patterns, and sentinel conditions and output-path semantics on sentinels and sentinel configuration.

Check-it: use the event observer only for its captured status and limitations; use the deterministic (rule-based) checker for rows and artifact correctness.

Spell a sentinel model with its provider. In the sentinel scenario, the bare haiku spelling passes --validate but fails runtime triggers with No LLM provider available and leaves only an initialized log header. The provider-qualified spelling fires. The shipped observer uses anthropic/claude-haiku-4-5.

Its captured report records a successful completion in about 3.3 minutes, but says that artifact existence, row coverage, and correctness cannot be verified from completion events.

Captured observer report.

Output
---
# Codon Completion Summary: `validate-and-repair`

**Status:** Success

...

- **Artifact existence cannot be verified** — no file.updated events provided
- **Row coverage cannot be verified** — no file contents or update events provided
- **Correctness cannot be verified** — no file contents or update events provided

The three "cannot be verified" lines at the end are the separation principle showing up in the output: observation of the run and evaluation of the artifacts stay in different hands.

Decide: codon boundary or same codon?#

Let's decide whether validation and reconciliation belong in one codon. Both use pi/baseten/deepseek-ai/DeepSeek-V4-Pro, so model tier alone suggests keeping them together. The other two questions change the result:

Scroll to explore the table →
QuestionCurrent evidenceDecision
Is the model tier different?No. Both codons use the same model.No reason to split on this axis.
Is the failure policy different?Yes. Both abort on task failure, but validate-and-repair has onExceeded: "complete", while reconcile has onExceeded: "fail".Reconciliation needs its own boundary because an incomplete 40-row join must fail rather than advance.
Is the output something a human might inspect?Yes. Validation produces per-line records and an exception ledger; reconciliation produces the whole-grid unified-records.csv.Seal and inspect the validation decision record before building the grid.

Result: split the codons, even though they use the same model. The failure policy and the inspectable decision record each justify the boundary on their own.

onExceeded: "complete" does not give a model time to finish its current reasoning. When a budget limit is reached, Hankweave sends SIGTERM to the codon process. The policy controls the status recorded afterward: complete records completion, while fail records failure. Treat complete as permission to keep work written before interruption, not as a completeness guarantee. The validation prompt still requires every unresolved item to reach exception-ledger.json, but that task intent cannot prevent a budget interruption.

If no required handoff was written before that interruption, a downstream model may invent a substitute and still produce a convincing report. Check the handoff deterministically in the consumer's rig before starting its agent; a prompt's Read list and checkpointedFiles patterns neither create the file nor prove it is complete. Keep the check fail-fast and choose onExceeded and onFailure deliberately. The small guarded-handoff example shows this boundary without the seven-codon anchor.

The same three questions, applied to every neighboring pair in the pipeline, produce the full set of boundaries:

Scroll to explore the table →
Proposed boundaryModel tierFailure policyInspectable resultChoice
Normalization → validationhaikupi/baseten/deepseek-ai/DeepSeek-V4-ProThe three normalize codons use onExceeded: "fail"; validation uses onExceeded: "complete". All four abort on task failure.Supplier envelopes → validated records and exception ledgerSplit
Validation → reconciliationSame modelBudget policy changes from complete to failPer-line decisions → complete 40-row gridSplit
Reconciliation → publicationpi/baseten/deepseek-ai/DeepSeek-V4-ProhaikuBudget policy changes from fail to completeMachine-shaped table → cited report and exception CSVSplit

The normalization prompts deliberately exclude deduplication, alias resolution, and validity checks. That narrower assignment reduces the decisions each extraction codon makes; it does not make model extraction infallible. A normalizer can still copy a value incorrectly, omit required output, hit its budget, or fail for another runtime reason. Keeping envelope-*.json as a checkpoint gives validation–and a human inspector–a place to catch those failures before policy decisions are added.

The final boundary also separates code from model work. Setup rigs derive the financial recommendation and serialize exceptions.csv; the award-brief agent completes only the qualitative assessment. This keeps financial projection out of the final agent's judgment.

A live run revealed one more boundary. survey-and-extracts was added last as the seventh codon, although it runs fourth, after the input set grew beyond the three dialect-specific normalizers. Its setup rig parses five native exports deterministically. The haiku agent reviews unmatched raw intake and records quarantine decisions; unrecognized intake produces no extracted rows and remains visible for exception handling.

This is the only retry codon. For retriable failures, maxAttempts: 3 permits up to three retries after the initial start, not three total starts. The retry counter begins at zero and increments only when a retry is taken. The first retry waits 20,000 ms, and maxDelayMs caps later delays at 120,000 ms. A non-retriable failure falls back to abort, as do task failures in the other codons.

The diagram below is the physical realization of these decisions. Follow the shape: four parallel haiku input codons converge on the validation handoff, then judgment, reconciliation, and publication run in series.

Anchor boundary map – four input codons feed fixed-file handoffs into judgment, reconciliation, and publication.

FIG. 1 Anchor boundary map — four input codons feed fixed-file handoffs into judgment, reconciliation, and rendering.
Read the diagram as text
Output
normalize-aster     haiku · fresh · abort · $0.50 cap · envelope-aster.json ┐
normalize-beacon    haiku · fresh · abort · $0.50 cap · envelope-beacon.json├─┐
normalize-cedar     haiku · fresh · abort · $0.50 cap · envelope-cedar.json  │ │
                    (all three feed the validation handoff)                 │ │
survey-and-extracts haiku · fresh · up to 3 retries after initial start     ┘ │
                    envelope-dover.json + envelope-embar.json +              │
                    envelope-fjord.json + envelope-harbor.json +              │
                    envelope-iris.json +                                       │
                    survey-notes.json                                         │
                                                                            ▼
validate-and-repair  pi/baseten/deepseek-ai/DeepSeek-V4-Pro · fresh ·        │
                     abort · onExceeded: complete · sentinel observer      │
                     validated-records.json + exception-ledger.json         │
                                                                            ▼
reconcile             pi/baseten/deepseek-ai/DeepSeek-V4-Pro · fresh ·      │
                     abort · onExceeded: fail · unified-records.csv +       │
                     appended exception-ledger.json                         │
                                                                            ▼
award-brief           haiku · fresh · abort · onExceeded: complete ·        │
                     award-brief.md + exceptions.csv → human reviewer       │

The diagram's labels are current configuration: five codons use haiku, two use the full judgment model ID, all seven use fresh, and the handoffs are named files. The four input codons write the eight envelopes and survey; validation writes the validated records and ledger; reconciliation writes the unified table and appends the ledger. At the final stage, rigs render the financial section and exception CSV, and the haiku agent writes the qualitative assessment.

Budget sizing follows the failure-policy axis. Historical three-supplier estimates tripped at $1.05 against a $1.00 cap and $0.51 against a $0.50 cap when the workload expanded to eight suppliers. Those pairs are historical, not current caps. Size caps from observed work; use the method in discover before you freeze. For the anchor's codon-by-codon account, use tutorial chapters 3–5.

The configuration excerpt below pairs the two codons that carry the most distinctive boundary policies: the discovered survey-and-extracts boundary with its retry configuration, and the reconcile handoff with its model, failure, budget, and checkpoint fields. Read it as the field-level expression of the failure policies analyzed above.

Configuration excerpt – the discovered boundary and its judgment handoff.

JSON
{
      "id": "survey-and-extracts",
      "name": "Prepare native exports and review raw intake",
      "model": "haiku",
      "continuationMode": "fresh",
      "promptFile": "./prompts/survey-and-extracts.md",
      "onFailure": "retry",
      "retryConfig": {
        "maxAttempts": 3,
        "delayMs": 20000,
        "maxDelayMs": 120000
      },
      "budget": {
        "maxDollars": 1.5,
        "maxTimeSeconds": 1800,
        "onExceeded": "complete"
      },
      "checkpointedFiles": [
        "envelope-dover.json",
        "envelope-embar.json",
        "envelope-fjord.json",
        "envelope-harbor.json",
        "envelope-iris.json",
        "survey-notes.json"
      ]
    },{
      "id": "reconcile",
      "name": "Reconcile to Unified Records",
      "model": "pi/baseten/deepseek-ai/DeepSeek-V4-Pro",
      "continuationMode": "fresh",
      "promptFile": "prompts/reconcile.md",
      "checkpointedFiles": [
        "unified-records.csv",
        "exception-ledger.json"
      ],
      "outputFiles": [
        {
          "copy": [
            "unified-records.csv",
            "exception-ledger.json"
          ]
        }
      ],
      "onFailure": "abort",
      "budget": {
        "maxDollars": 2.0,
        "maxTimeSeconds": 1800,
        "onExceeded": "fail"
      }
    }

Run the drill on one boundary in your own hank. Pick a pair of adjacent codons, answer the three questions for the seam between them, and record what the answers imply:

Scroll to explore the table →
QuestionAnswerEvidenceResulting boundary
Different model tier?
Different failure policy?
Human-inspectable artifact?

Check-it: fill all three rows, then compare the reasoning with the current validation-to-reconciliation example above. One yes is evidence, not an automatic rule; failure policy or inspectability can justify a boundary even when the model stays the same.

The fixture also includes an optional historical design note. It records an earlier three-supplier, Sonnet-era design and preserves obsolete claims about extraction and budget interruption. Use the current configuration and runtime behavior above when designing a new hank.

Inspect the boundaries on disk#

The boundary decisions above are verifiable without spending tokens: prepare the task inputs, validate the plan, and read the resolved topology. From the extracted bundle root, enter anchor-hank, then prepare once and reuse that directory for validation and fresh executions. In the extracted bundle layout, verify.py, quote-template-unification, and anchor-hank are sibling paths, which is why the relative paths below work:

⌁ Terminal
cd anchor-hank
python3 ../verify.py prepare-data ../quote-template-unification task-data
bunx hankweave@0.10.0 hank.json task-data --validate
bunx hankweave@0.10.0 hank.json task-data --headless --start-new --execution exec --max-cost 9 --shim-idle-timeout 1800 --overwrite-output -o out
python3 ../verify.py anchor out

The command's --max-cost 9 option requests a $9 global maximum; the validation plan still reports no global budget because its configured plan limits are per-codon. The preparation step copies only the digitized inputs, native extracts, lookups, RFQ inputs, source quotes, and a filtered manifest. It leaves the held-out answer key, generator, and failure specimens outside the agent input. The destination must not already exist. Use Bun, Git, and a non-root account with writable execution and output directories; export ANTHROPIC_API_KEY and BASETEN_API_KEY. For the default direct-Anthropic route, the normal startup self-test requires ANTHROPIC_API_KEY; a Claude Code login alone fails that test and is not the credential recipe. The two judgment codons use pi/baseten/deepseek-ai/DeepSeek-V4-Pro.

Add --validate to check configuration and paths without running codons or provider health checks; it does not prove credentials work. Add -y to skip confirmation prompts and -o <path> to copy outputs out of the managed execution directory. The data argument is the prepared directory, not the raw corpus. The provider-qualified model rule above applies to sentinels; codon entries in this hank intentionally use the configured haiku alias.

The capture below is what --validate produces: the resolved plan, its per-codon budget table, and the GOOD TO RUN! verdict. It confirms the static topology–codon count, models, checkpoints, and caps–without consuming tokens.

Validation capture – the resolved plan and its GOOD TO RUN! result.

Output

╭────────────────────────────────────────────────────────────────────╮
│  Hankweave v0.10.0                                                 │
│  darwin arm64 • node v23.8.0                                       │
╰────────────────────────────────────────────────────────────────────╯

Calculating data signature for validation...

> Validating configuration: <workspace>/fixtures/anchor-hank/hank.json

  Data source:    <workspace>/fixtures/quote-template-unification
  Execution path: ~/.hankweave-executions/validation-<id>

✓ Configuration is valid!

╭──────────────────────────────────────────────────────────────────────────────╮
│  quote-template-unification v1.0.0                                           │
│  7 codons • 0 loops                                                          │
╰──────────────────────────────────────────────────────────────────────────────╯

├─ [1] normalize-aster (Normalize Aster (Datalab dialect))
│     model: haiku │ mode: fresh │ prompts: 1 (72 lines)
│     checkpointedGlobs: 1
│     rigs: cmd: mkdir -p pipeline
│     ↓
├─ [2] normalize-beacon (Normalize Beacon (Reducto dialect))
│     model: haiku │ mode: fresh │ prompts: 1 (71 lines)
│     checkpointedGlobs: 1
│     ↓
├─ [3] normalize-cedar (Normalize Cedar (generic-OCR dialect))
│     model: haiku │ mode: fresh │ prompts: 1 (71 lines)
│     checkpointedGlobs: 1
│     ↓
├─ [4] survey-and-extracts (Prepare native exports and review raw intake)
│     model: haiku │ mode: fresh │ prompts: 1 (21 lines)
│     checkpointedGlobs: 6
│     rigs: copy: <workspace>/...
│     ↓
├─ [5] validate-and-repair (Validate & Repair Envelopes)
│     model: Pro │ mode: fresh │ prompts: 1 (78 lines) │ checkpointedGlobs: 2
│     sentinels: 1
│     rigs: copy: <workspace>/...
│     ↓
├─ [6] reconcile (Reconcile to Unified Records)
│     model: Pro │ mode: fresh │ prompts: 1 (41 lines) │ checkpointedGlobs: 2
│     ↓
└─ [7] award-brief (Award Brief & Exception Queue)
      model: haiku │ mode: fresh │ prompts: 1 (32 lines)
      checkpointedGlobs: 2
      rigs: copy: <workspace>/...


Budget
─────────────────────────────────────────────────────────────────
  No global budget. Per-codon limits only.

  Codon                Model       Max Dollars                       Max Time          On exceeded
  ─────                ─────       ───────────                       ────────          ───────────
  normalize-aster      Claude Ha…  $0.50 (codon cap)                 240s (cap)        ⚠ fails run
  normalize-beacon     Claude Ha…  $0.50 (codon cap)                 240s (cap)        ⚠ fails run
  normalize-cedar      Claude Ha…  $0.50 (codon cap)                 240s (cap)        ⚠ fails run
  survey-and-extracts  Claude Ha…  $1.50 (codon cap)                 1800s (cap)       completes
  validate-and-repair  Deepseek …  $3.00 (codon cap)                 2400s (cap)       completes
  reconcile            Deepseek …  $2.00 (codon cap)                 1800s (cap)       ⚠ fails run
  award-brief          Claude Ha…  $1.00 (codon cap)                 1200s (cap)       completes

╭─ GOOD TO RUN! ──────────────────────────────────────────────────────╮
│  7 codons • 7 prompts • 0 system prompts • 10 rigs • 7 checkpoints  │
╰─────────────────────────────────────────────────────────────────────╯

Run it:  hankweave hank.json <data_path>

Environment Variables:

  From System (HANKWEAVE_ prefixed):
    - CAPTURE_VERSION: 0.10.0
exit=0

The validation capture shows seven codons, seven prompts, no system prompts, ten rigs, and seven checkpoints, followed by exit=0. Its tree displays Pro for the judgment tier; use the full provider/model ID from hank.json for the runnable configuration.

A managed execution directory accumulates one artifact set per boundary in agentRoot/: preflight-report.json, the envelope files, survey-notes.json, validated-records.json, exception-ledger.json, unified-records.csv, award-brief.md, and exceptions.csv. The plan's seven checkpoints are per-codon checkpoints; each can contain multiple named files in its checkpointed file set. Outputs stay there unless you use -o. The default topology is ~/.hankweave-executions/<id>/, overridable with HANKWEAVE_RUNTIME_EXECUTION_BASE_DIR; the workspace is <exec>/agentRoot/, the input-data link or copy is <exec>/agentRoot/read_only_data_source/, state is <exec>/.hankweave/state.json, and the journal is <exec>/.hankweave/events/events.jsonl. The anchor copy-rigs rigs/preflight.ts into pipeline/preflight.ts; its RFQ contract lives under reference/ and is hand-transcribed rather than read at runtime.

The full anchor covers eight suppliers across five parts: 40 data rows, or 41 CSV lines including the header. The golden capture completed all seven codons, matched the structured table against truth for all 40 data rows, routed eight exception rows spanning eight hazard types, and recorded actual_service_output: true. Its tracked codon cost was $0.88303367; provider health checks and sentinel calls are separate. The configured per-codon caps are $0.50 + $0.50 + $0.50 + $1.50 + $3.00 + $2.00 + $1.00 = $9.00. That sum is a configured ceiling, not a predicted bill, universal retry total, or price promise.

Reconcile's onExceeded: "fail" means a budget stop fails loudly rather than shipping a truncated reconciliation. Check that policy in hank.json, the prompt, and the run instructions. After the run, python3 verify.py anchor out checks missing or duplicate supplier-part rows, value drift, missing hazards, and broken exception fields. The truth remains held out during the run; verify it only afterward.

Check-it: after a full run, inspect agentRoot/, confirm all seven codons completed in the golden-run receipt, and run the deterministic anchor check. Do not use the sentinel log as a substitute for artifact verification.

The final handoff has two authorities: the agent writes the qualitative assessment, while the render-award.ts rig derives the cited financial projection and the render-exceptions.ts rig serializes the ledger. Their checks preserve the structured exception identities and source references and enforce export completeness, not the semantic truth of every assessment sentence.