Inspect the minimal single-provider hank

Use this fixture for a first useful hank#

A hank is the configuration for a unit of work; a codon is one sealed agent task in its sequence. This page walks through the smallest useful hank: one codon, one provider key (ANTHROPIC_API_KEY), and one output file. By the end you will have read every file in the fixture, validated the configuration, run it headless, watched it fail safely without a key, and checked the evidence a good run leaves behind.

We follow one successful path and one authentication-failure capture, pausing at each field in hank.json to explain what it controls. If you would rather begin with a guided validate, run, break, and resume walkthrough, start with start/quickstart and come back here when you want the fixture itself explained.

Find the pieces before you run#

Work from the minimal-single-provider/ directory. Before running anything, look at what the fixture ships: the configuration, the prompt, the input data, a README, and a set of captured expected outputs you can compare your own run against.

FIG. 1 Find the pieces before you run
Read the diagram as text
Output
minimal-single-provider/
├── hank.json
├── prompts/
│   └── summarize.md
├── data/
│   └── notes.txt
├── expected/
│   ├── MANIFEST.md
│   ├── receipt.json
│   ├── validate-output.txt
│   ├── run-transcript.txt
│   ├── final-events.txt
│   ├── fail-no-key.txt
│   └── summary-example.md
└── README.md

The input, data/notes.txt, is fictional meeting material. It names the Calloway vendor decision, Devon as owner, and a Friday-the-12th deadline, and it carries a training-fixture watermark so it cannot be mistaken for real data:

Output
FICTIONAL TRAINING FIXTURE — invented content for documentation testing.

Meeting notes, Tuesday.
Attendees: Mara, Devon, Sam.
We compared the two vendor quotes for the packaging line refit.
Decision: go with the Calloway quote (lower total, includes installation).
Devon owns the purchase order and vendor follow-up.
Deadline: PO issued by Friday the 12th.
Sam raised spare-parts stocking; parked for next week.

The expected/ directory holds captures from one complete live execution. Its manifest dates the set to 2026-09-06, identifies hankweave@0.10.0, and records a tracked codon cost of $0.01394590. The capture set uses normalized placeholders for changing execution values, while final-events.txt retains some per-run process and session fields; diff-clean recapture therefore depends on the normalizer covering those fields too. The manifest marks the execution as actual service output. Note what is absent: there is no committed out/ directory, because out/summary.md is created by the run command below.

Output
# Capture manifest
- Captured: 2026-09-06T05:52:24.303456+00:00 · runtime: hankweave@0.10.0
- actual_service_output: true
- Scope: one complete live execution
- Raw execution (path normalized): ~/.hankweave-executions/minimal/1788673917095-hvhh-c5c378
- Complete codons: 1/1
- Tracked codon cost: $0.01394590 (provider health checks and sentinel calls are separate)
- Input scope: notes only

Read what hank.json controls#

The configuration is a single file. Its hank array holds one codon, and the $schema URL pins this fixture to the 0.10.0 schema rather than the @latest spelling used by the initialization fixture.

JSON
{
  "$schema": "https://unpkg.com/hankweave@0.10.0/schemas/hank.schema.json",
  "meta": {
    "name": "Minimal single provider",
    "version": "1.0.0",
    "description": "The smallest useful hank: one codon, one provider key, one output file. The quickstart's fixture."
  },
  "hank": [
    {
      "id": "summarize-notes",
      "name": "Summarize the notes",
      "model": "haiku",
      "continuationMode": "fresh",
      "promptFile": "./prompts/summarize.md",
      "checkpointedFiles": ["summary.md"],
      "outputFiles": [ { "copy": ["summary.md"] } ]
    }
  ]
}

The optional meta block carries a name, version, and description; it has no runtime effect. The summarize-notes codon declares id, name, model, and continuationMode, plus its prompt, checkpointed file, and output copy. Each of those fields does something specific:

haiku is a registry shortcut. When authentication fails, the capture prints its runtime-resolved display name: Claude Haiku 4.5 (latest) (anthropic/claude-haiku-4-5). That is a registry resolution result, not a pinned artifact string. Bare shortcuts such as haiku, sonnet, and opus are valid only when the registry defines them; use a full pi/<provider>/<model> or provider-prefixed slug for another model. See model resolution for the resolution phases.

continuationMode: "fresh" starts the codon in a new agent session. checkpointedFiles: ["summary.md"] makes that file watched, streamed to the client, and sealed into the git-based checkpoint store after the codon. outputFiles: [{"copy": ["summary.md"]}] copies it from the execution directory to the output directory when -o is configured. See concepts/codons, concepts/checkpoints, reference/hank-json, and operate/runbook for those mechanics.

Equally important is what this hank does not declare: no budget, onFailure, rig setup, sentinels, or requirements.env. Its failure policy therefore uses the default abort, and the remaining behavior comes from defaults. Because it declares no requirements.env, a missing ANTHROPIC_API_KEY is caught by the startup self-test, as the expected-failure capture shows below. See authentication and models.

Keep the data path in mind#

The prompt is the other half of the codon. It asks the agent to read notes.txt from read_only_data_source in its working directory, then write summary.md with one sentence and exactly three bullets: one decision, one owner, and one deadline. The prompt preserves the deadline wording from the notes and forbids inferring a month, year, calendar date, or other detail the notes do not give. The file must stay under 15 lines.

Output
# Summarize the meeting notes

Read the file `notes.txt` inside the `read_only_data_source` directory in your current working directory (use shell commands like `cat` — the directory may be a symlink).

Write `summary.md` in the current working directory containing:

1. A one-sentence summary of what the meeting decided.
2. Exactly three bullet points: one decision, one owner, one deadline — taken from the notes.

Keep the deadline's wording from the notes. Do not infer a month, year, calendar date, or other detail that the notes do not give.

Nothing else. Keep it under 15 lines.

One detail in that prompt deserves attention. The data-path positional mounts at agentRoot/read_only_data_source, regardless of the source directory's name. Here the source is data/, and the startup capture reports Source → data; use the mounted path in the prompt rather than depending on the source name.

This is the cheapest first run the fixture set offers: one mechanical summarization task on the cheapest model tier, one key, and one sealed output. It is the small version of the shape used by quote-template-unification at production scale.

Validate, run, and break safely#

Enter the minimal-single-provider/ directory – the directory containing hank.json – before running these commands. The shown bunx launcher invokes the package's Node entry point, so use Node >=22.19.0; Bun/bunx is the package launcher here. If you use npm instead, substitute npx once for bunx in each command. Set ANTHROPIC_API_KEY for the successful run: a local Claude Code login alone is not the default direct-Anthropic credential for this fixture.

Validate before the run#

Run the checked validation command from the fixture root:

⌁ Terminal
bunx hankweave@0.10.0 hank.json data/ --validate

The single .json positional is the hank path; the other positional is the data path. The command grammar belongs to reference/cli. At 0.10.0, validation initializes the registry with provider health checks disabled. It performs local SDK-import, credential-presence, catalog, configuration, and harness checks, but does not execute codons or make a model-generation self-test. Do not treat validation as a proof of provider connectivity or as a universal offline/no-write guarantee; runtime startup separately performs provider health checks, which can be billable and are outside the tracked codon total.

Check-it: the command prints ✓ Configuration is valid! and the GOOD TO RUN! box with 1 codons • 1 prompts • 0 system prompts • 0 rigs • 1 checkpoints. The full captured output looks like this:

Output

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

Calculating data signature for validation...

> Validating configuration: <workspace>/fixtures/minimal-single-provider/hank.json

  Data source:    <workspace>/fixtures/minimal-single-provider/data
  Execution path: ~/.hankweave-executions/validation-<id>

✓ Configuration is valid!

╭──────────────────────────────────────────────────────────────────────────────╮
│  Minimal single provider v1.0.0                                              │
│  1 codon • 0 loops                                                           │
╰──────────────────────────────────────────────────────────────────────────────╯

└─ [1] summarize-notes (Summarize the notes)
      model: haiku │ mode: fresh │ prompts: 1 (13 lines)
      checkpointedGlobs: 1

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

Run it:  hankweave hank.json <data_path>

Environment Variables:

  From System (HANKWEAVE_ prefixed):
    - CAPTURE_VERSION: 0.10.0
    - TELEMETRY: 0

exit=0

Run a fresh headless execution#

With validation passing, run without the terminal interface, force a fresh execution, and copy the result to out/:

⌁ Terminal
bunx hankweave@0.10.0 hank.json data/ --headless --start-new -o out

--headless runs without the terminal interface. --start-new (also -n) starts a fresh execution and does not resume one. -o out copies the output under the fixture root. The runtime creates a managed execution directory at ~/.hankweave-executions/<exec-id>/ and prints its path. The codon's working directory is that execution's agentRoot, where the mounted data appears as read_only_data_source.

Without -o, summary.md remains only in ~/.hankweave-executions/<exec-id>/agentRoot/; there is no default results directory. See operate/runbook for output-directory behavior.

Check-it: after this command, out/summary.md exists under the fixture root and the capture contains the Hankweave Server Started box and Running in headless mode on port <port>:

Output

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

Created new execution directory: ~/.hankweave-executions/<exec-id>
New execution: <exec-id>
  Source → data
  Exec   → ~/.hankweave-executions/<exec-id>
  SDKs   → Claude node_modules ✓

╭──────────────────────────────────────────────────────────────────────────────╮
│  Minimal single provider v1.0.0                                              │
│  1 codon • 0 loops                                                           │
╰──────────────────────────────────────────────────────────────────────────────╯

└─ [1] summarize-notes (Summarize the notes)
      model: haiku │ mode: fresh │ prompts: 1 (13 lines)
      checkpointedGlobs: 1


══════════════════════════════════════════════════
  Hankweave Server Started
  WebSocket: ws://localhost:<port>
══════════════════════════════════════════════════

Running in headless mode on port <port>
➜ Listening on: http://localhost:<port>/ (all interfaces)

exit=0

Break authentication before a codon runs#

To exercise the named failure fixture, unset the key and run the same minimal hank command:

⌁ Terminal
env -u ANTHROPIC_API_KEY bunx hankweave@0.10.0 hank.json data/ --headless --start-new -o out

Startup creates the execution directory, then its self-test fails before the codon runs. The diagnostic prints the resolved model name and an installed hankweave@0.10.0 bundle path in its stack trace – not a source checkout.

Check-it: the expected-failure capture says No authentication found (set ANTHROPIC_API_KEY) and Server startup failed!:

Output

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

Created new execution directory: ~/.hankweave-executions/<exec-id>
New execution: <exec-id>
  Source → data
  Exec   → ~/.hankweave-executions/<exec-id>
  SDKs   → Claude node_modules ✓

[<ts>] [ERROR] Self-test completed: FAILED
[<ts>] [ERROR] Self-test FAILED: Some checks failed
[<ts>] [ERROR]   - authentication: ✗ No authentication found (set ANTHROPIC_API_KEY)
[ERROR] Server startup failed!
Error message: Self-test failed for 1 model(s):
  - Claude Haiku 4.5 (latest) (anthropic/claude-haiku-4-5): Some checks failed
      • authentication: No authentication found (set ANTHROPIC_API_KEY)
Stack trace:
Error: Self-test failed for 1 model(s):
  - Claude Haiku 4.5 (latest) (anthropic/claude-haiku-4-5): Some checks failed
      • authentication: No authentication found (set ANTHROPIC_API_KEY)
    at eU (file://<workspace>/build/runtime/0.10.0/node_modules/hankweave/dist/index.js:260:5401)
    at async Egt (file://<workspace>/build/runtime/0.10.0/node_modules/hankweave/dist/index.js:842:647)
    at async file://<workspace>/build/runtime/0.10.0/node_modules/hankweave/dist/index.js:843:754

exit=1

Check the completion evidence#

After a successful run, inspect the normalized event capture. It records RunStarted, CodonStarted, the codon transitions preparing → starting → initializing → running, cost and assistant-message updates, CodonFinalCostSet, a completed CheckpointCreated, the codon transition running → completed with exit code 0, one successful codon.completed, and RunCompleted. The initializing transition records the agent log path.

Check-it: the capture contains CheckpointCreated, one successful codon.completed, and RunCompleted:

Output
{"id": "<id>", "timestamp": "<ts>", "type": "state.transition", "data": {"transitionType": "RunStarted", "runId": "<id>", "transition": {"type": "RunStarted", "data": {"runId": "<id>", "runFolder": "~/.hankweave-executions/<exec-id>/.hankweave/runs/<id>", "gitBranch": "run-<id>", "startingConditions": {"type": "fresh"}, "serverPid": 50024}}, "resultingState": {"currentRunId": "<id>", "runCount": 1, "totalCost":"<n>", "currentRunCost":"<n>"}}}
{"id": "<id>", "timestamp": "<ts>", "type": "state.transition", "data": {"transitionType": "CodonStarted", "runId": "<id>", "codonId": "summarize-notes", "transition": {"type": "CodonStarted", "data": {"runId": "<id>", "codonId": "summarize-notes"}}, "resultingState": {"currentRunId": "<id>", "runCount": 1, "totalCost":"<n>", "currentRunCost":"<n>"}}}
{"id": "<id>", "timestamp": "<ts>", "type": "state.transition", "data": {"transitionType": "CodonTransitioned", "runId": "<id>", "codonId": "summarize-notes", "transition": {"type": "CodonTransitioned", "data": {"runId": "<id>", "codonId": "summarize-notes", "from": "preparing", "to": "starting", "metadata": {}}}, "resultingState": {"currentRunId": "<id>", "runCount": 1, "totalCost":"<n>", "currentRunCost":"<n>"}}}
{"id": "<id>", "timestamp": "<ts>", "type": "state.transition", "data": {"transitionType": "CodonTransitioned", "runId": "<id>", "codonId": "summarize-notes", "transition": {"type": "CodonTransitioned", "data": {"runId": "<id>", "codonId": "summarize-notes", "from": "starting", "to": "initializing", "metadata": {"claudePid": 962109, "claudeLogPath": ".hankweave/runs/<id>/summarize-notes-claude.log"}}}, "resultingState": {"currentRunId": "<id>", "runCount": 1, "totalCost":"<n>", "currentRunCost":"<n>"}}}
{"id": "<id>", "timestamp": "<ts>", "type": "state.transition", "data": {"transitionType": "CodonTransitioned", "runId": "<id>", "codonId": "summarize-notes", "transition": {"type": "CodonTransitioned", "data": {"runId": "<id>", "codonId": "summarize-notes", "from": "initializing", "to": "running", "metadata": {"claudeSessionId": "be7a1143-f289-4e61-9346-9c3bf0dc8ed2"}}}, "resultingState": {"currentRunId": "<id>", "runCount": 1, "totalCost":"<n>", "currentRunCost":"<n>"}}}
{"id": "<id>", "timestamp": "<ts>", "type": "state.transition", "data": {"transitionType": "CostsIncremented", "runId": "<id>", "codonId": "summarize-notes", "transition": {"type": "CostsIncremented", "data": {"runId": "<id>", "codonId": "summarize-notes", "costDelta":"<n>", "tokensDelta": {"inputTokens":"<n>", "outputTokens":"<n>", "cacheCreationTokens":"<n>", "cacheReadTokens":"<n>"}}}, "resultingState": {"currentRunId": "<id>", "runCount": 1, "totalCost":"<n>", "currentRunCost":"<n>"}}}
{"id": "<id>", "timestamp": "<ts>", "type": "state.transition", "data": {"transitionType": "AssistantMessageCountUpdated", "runId": "<id>", "codonId": "summarize-notes", "transition": {"type": "AssistantMessageCountUpdated", "data": {"runId": "<id>", "codonId": "summarize-notes", "newCount":"<n>"}}, "resultingState": {"currentRunId": "<id>", "runCount": 1, "totalCost":"<n>", "currentRunCost":"<n>"}}}
{"id": "<id>", "timestamp": "<ts>", "type": "state.transition", "data": {"transitionType": "CostsIncremented", "runId": "<id>", "codonId": "summarize-notes", "transition": {"type": "CostsIncremented", "data": {"runId": "<id>", "codonId": "summarize-notes", "costDelta":"<n>", "tokensDelta": {"inputTokens":"<n>", "outputTokens":"<n>", "cacheCreationTokens":"<n>", "cacheReadTokens":"<n>"}}}, "resultingState": {"currentRunId": "<id>", "runCount": 1, "totalCost":"<n>", "currentRunCost":"<n>"}}}
{"id": "<id>", "timestamp": "<ts>", "type": "state.transition", "data": {"transitionType": "AssistantMessageCountUpdated", "runId": "<id>", "codonId": "summarize-notes", "transition": {"type": "AssistantMessageCountUpdated", "data": {"runId": "<id>", "codonId": "summarize-notes", "newCount":"<n>"}}, "resultingState": {"currentRunId": "<id>", "runCount": 1, "totalCost":"<n>", "currentRunCost":"<n>"}}}
{"id": "<id>", "timestamp": "<ts>", "type": "state.transition", "data": {"transitionType": "CostsIncremented", "runId": "<id>", "codonId": "summarize-notes", "transition": {"type": "CostsIncremented", "data": {"runId": "<id>", "codonId": "summarize-notes", "costDelta":"<n>", "tokensDelta": {"inputTokens":"<n>", "outputTokens":"<n>", "cacheCreationTokens":"<n>", "cacheReadTokens":"<n>"}}}, "resultingState": {"currentRunId": "<id>", "runCount": 1, "totalCost":"<n>", "currentRunCost":"<n>"}}}
{"id": "<id>", "timestamp": "<ts>", "type": "state.transition", "data": {"transitionType": "AssistantMessageCountUpdated", "runId": "<id>", "codonId": "summarize-notes", "transition": {"type": "AssistantMessageCountUpdated", "data": {"runId": "<id>", "codonId": "summarize-notes", "newCount":"<n>"}}, "resultingState": {"currentRunId": "<id>", "runCount": 1, "totalCost":"<n>", "currentRunCost":"<n>"}}}
{"id": "<id>", "timestamp": "<ts>", "type": "state.transition", "data": {"transitionType": "CostsIncremented", "runId": "<id>", "codonId": "summarize-notes", "transition": {"type": "CostsIncremented", "data": {"runId": "<id>", "codonId": "summarize-notes", "costDelta":"<n>", "tokensDelta": {"inputTokens":"<n>", "outputTokens":"<n>", "cacheCreationTokens":"<n>", "cacheReadTokens":"<n>"}}}, "resultingState": {"currentRunId": "<id>", "runCount": 1, "totalCost":"<n>", "currentRunCost":"<n>"}}}
{"id": "<id>", "timestamp": "<ts>", "type": "state.transition", "data": {"transitionType": "AssistantMessageCountUpdated", "runId": "<id>", "codonId": "summarize-notes", "transition": {"type": "AssistantMessageCountUpdated", "data": {"runId": "<id>", "codonId": "summarize-notes", "newCount":"<n>"}}, "resultingState": {"currentRunId": "<id>", "runCount": 1, "totalCost":"<n>", "currentRunCost":"<n>"}}}
{"id": "<id>", "timestamp": "<ts>", "type": "state.transition", "data": {"transitionType": "CostsIncremented", "runId": "<id>", "codonId": "summarize-notes", "transition": {"type": "CostsIncremented", "data": {"runId": "<id>", "codonId": "summarize-notes", "costDelta":"<n>", "tokensDelta": {"inputTokens":"<n>", "outputTokens":"<n>", "cacheCreationTokens":"<n>", "cacheReadTokens":"<n>"}}}, "resultingState": {"currentRunId": "<id>", "runCount": 1, "totalCost":"<n>", "currentRunCost":"<n>"}}}
{"id": "<id>", "timestamp": "<ts>", "type": "state.transition", "data": {"transitionType": "AssistantMessageCountUpdated", "runId": "<id>", "codonId": "summarize-notes", "transition": {"type": "AssistantMessageCountUpdated", "data": {"runId": "<id>", "codonId": "summarize-notes", "newCount":"<n>"}}, "resultingState": {"currentRunId": "<id>", "runCount": 1, "totalCost":"<n>", "currentRunCost":"<n>"}}}
{"id": "<id>", "timestamp": "<ts>", "type": "state.transition", "data": {"transitionType": "CostsIncremented", "runId": "<id>", "codonId": "summarize-notes", "transition": {"type": "CostsIncremented", "data": {"runId": "<id>", "codonId": "summarize-notes", "costDelta":"<n>", "tokensDelta": {"inputTokens":"<n>", "outputTokens":"<n>", "cacheCreationTokens":"<n>", "cacheReadTokens":"<n>"}}}, "resultingState": {"currentRunId": "<id>", "runCount": 1, "totalCost":"<n>", "currentRunCost":"<n>"}}}
{"id": "<id>", "timestamp": "<ts>", "type": "state.transition", "data": {"transitionType": "AssistantMessageCountUpdated", "runId": "<id>", "codonId": "summarize-notes", "transition": {"type": "AssistantMessageCountUpdated", "data": {"runId": "<id>", "codonId": "summarize-notes", "newCount":"<n>"}}, "resultingState": {"currentRunId": "<id>", "runCount": 1, "totalCost":"<n>", "currentRunCost":"<n>"}}}
{"id": "<id>", "timestamp": "<ts>", "type": "state.transition", "data": {"transitionType": "CodonFinalCostSet", "runId": "<id>", "codonId": "summarize-notes", "transition": {"type": "CodonFinalCostSet", "data": {"runId": "<id>", "codonId": "summarize-notes", "finalCost":"<n>", "finalTokens": {"inputTokens":"<n>", "outputTokens":"<n>", "cacheCreationTokens":"<n>", "cacheReadTokens":"<n>"}}}, "resultingState": {"currentRunId": "<id>", "runCount": 1, "totalCost":"<n>", "currentRunCost":"<n>"}}}
{"id": "<id>", "timestamp": "<ts>", "type": "state.transition", "data": {"transitionType": "CheckpointCreated", "runId": "<id>", "codonId": "summarize-notes", "transition": {"type": "CheckpointCreated", "data": {"runId": "<id>", "codonId": "summarize-notes", "checkpointType": "completed", "sha": "<sha>", "branch": "run-<id>"}}, "resultingState": {"currentRunId": "<id>", "runCount": 1, "totalCost":"<n>", "currentRunCost":"<n>"}}}
{"id": "<id>", "timestamp": "<ts>", "type": "state.transition", "data": {"transitionType": "CodonTransitioned", "runId": "<id>", "codonId": "summarize-notes", "transition": {"type": "CodonTransitioned", "data": {"runId": "<id>", "codonId": "summarize-notes", "from": "running", "to": "completed", "metadata": {"exitCode": 0, "resultMessageReceived": true, "checkpointSha": "<sha>", "contextExceeded": false, "extensionCount": 0}}}, "resultingState": {"currentRunId": "<id>", "runCount": 1, "totalCost":"<n>", "currentRunCost":"<n>"}}}
{"id": "<id>", "timestamp": "<ts>", "type": "codon.completed", "data": {"codonId": "summarize-notes", "success": true, "cost":"<n>", "duration":"<n>", "exitStatus": {"type": "success"}}}
{"id": "<id>", "timestamp": "<ts>", "type": "state.transition", "data": {"transitionType": "RunCompleted", "runId": "<id>", "transition": {"type": "RunCompleted", "data": {"runId": "<id>"}}, "resultingState": {"currentRunId": null, "runCount": 1, "totalCost":"<n>", "currentRunCost":"<n>"}}}

Recognize a good run's evidence#

Each capture above answers a different question about the run, so read them as a set. Validation ends with ✓ Configuration is valid!, a one-codon structure box, the GOOD TO RUN! counts, a Run it: line, and an environment report. Its execution path is a synthetic validation path, not a real directory. The captured report is labeled From System (HANKWEAVE_ prefixed) and shows that scope rather than the whole machine environment; its captured values include CAPTURE_VERSION: 0.10.0 and TELEMETRY: 0.

The run capture supplies the version banner, the New execution block with Source → data, the managed execution path, and the Hankweave Server Started box. --headless removes the terminal interface, but the runtime still starts this local server and reports its WebSocket (the local client connection); it shuts down after all codons complete. The event capture shows the completed checkpoint, successful codon completion, and RunCompleted. Its initializing metadata gives the agent log path as .hankweave/runs/<id>/summarize-notes-claude.log.

Finally, compare your summary with this captured codon output:

MARKDOWN
# Meeting Summary

The team decided to proceed with the Calloway vendor quote for the packaging line refit based on lower total cost and included installation.

- **Decision:** Go with the Calloway quote for packaging line refit
- **Owner:** Devon
- **Deadline:** PO issued by Friday the 12th

Model output is stochastic, so another run can differ in wording. Treat the contract as the shape – one sentence and three bullets taken from the notes – not identical output bytes.

Measure the run cost#

The full run cost measured $0.01394590 on 2026-09-06 against the published hankweave@0.10.0 artifact with the haiku model. Treat this as a dated capture, not an estimate. Provider health checks and sentinel calls are tracked separately from the codon cost.

The hank has no budget caps. The operator-level ceilings are --max-cost and --max-time; the runtime parses them, but they are absent from the shipped --help. See reference/cli for that parity note.

How the example captures were recorded#

The published transcripts come from this fixture directory against the pinned runtime: the validation and headless commands above are rerun, then expected/ is recaptured. The corpus records a passed recapture transaction for this minimal fixture and a verification step. Its normalizer masks changing execution values. The maintenance scripts are not shipped in the fixture corpus; you do not need them to run the example.

The maintenance capture transaction reports a successful live minimal run, an explicit no-key refusal, and preserved expected bytes.

Adapt one piece at a time#

To make this example your own, change either prompts/summarize.md or data/notes.txt, then run with --start-new. Changing the data directory changes the data hash; use operate/runbook for the distinction between resuming and starting fresh.

For a Gemini version, swap the single model field to a spelling such as pi/google/gemini-2.5-flash and use GEMINI_API_KEY. Generate it from this same fixture rather than hand-forking it; start/quickstart owns that provider variant.

When this shape is no longer enough, add a codon budget, a second codon, or a sentinel. Follow concepts/budgets, concepts/codons, or concepts/sentinels for those mechanics. For the full-sized version of this shape, continue to quote-template-unification.