# Hankweave Here, `[changed X.Y.Z]` marks a version-sensitive fact; unmarked facts describe the 0.10.0 artifact. Hankweave is a headless runtime for repeatable, repairable agent work. It freezes agentic behaviors into **hanks**: declarative JSON programs whose control flow, checkpoints, and evidence are deterministic while model output remains stochastic. This page explains why that runtime exists, walks through one small run so the mechanics are visible before the vocabulary, and ends with the paths into the rest of the documentation. ## Why agent work needs a runtime Hankweave is a labor of love: we want people and LLMs to work well together. When we find an agent workflow worth repeating months later, we need more than its chat transcript. A transcript records what the model said; it does not let us rerun the work, verify what happened, or repair the step that broke. A headless runtime – a process that works without an interactive screen – gives us that instead. Hankweave is not a library you embed; it is a process that runs hanks. Think Docker Compose for agent workflows, not a Python package. A codon is a task in that sequence, and a checkpoint records the run's sealed work. “Brownfield” means working with existing systems: maintenance, evolution, and the messy reality of production. Hankweave is built for AI systems that need to keep working six months from now. When an agent fails on run #47, we want to trace the recorded sequence of events, roll back to a checkpoint, and fix the workflow rather than reconstruct what happened from a conversation. \[changed 0.8.0] Two in-process harnesses ship in the artifact: the Claude Agent SDK harness for Anthropic models and the embedded Pi harness for all other providers. Both run inside Hankweave; subprocess shims were removed in 0.8.0. Running is the default operation. There are no CLI subcommands. The help usage line is: ```text hankweave [options] [config-or-data-path] ``` The CLI accepts up to two positional paths. When you provide both, the first is the hank path and the second is the data path, as in the fixture command below. The published artifact is the unscoped npm package `hankweave`. We can run it without a permanent install with either `bunx hankweave@0.10.0` or `npx hankweave@0.10.0`. These commands launch the package's Node entry point, so install Node ≥ 22.19.0. Bun supplies the `bunx` launcher; npm supplies `npx`. > **Pitfall:** `hankweave` with no hank path, data path, or qualifying flag launches the welcome wizard. It does not run your hank. \[since 0.3.0] The wizard detects the environment, validates credits, offers a demo hank, and exits with status 0. Walk through those choices in [first run](/start/first-run). For a normal run, use an explicit path. Outputs stay in the `agentRoot/` workspace by default; there is no default results directory. See the [runbook](/operate/runbook) for the full output contract, or [how a run works](/start/how-a-run-works) for the lifecycle vocabulary. ## See a run before learning the model The concepts above are easier to hold onto once you have seen them move. Let's start with a real, small hank rather than a blank program. We will inspect a fixture with one codon, `summarize-notes`. It uses the `haiku` model with `continuationMode: "fresh"`, reads one prompt file, checkpoints one file by glob – a filename pattern – and copies one output file. The full configuration is short enough to read in one pass: ```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"] } ] } ] } ``` From the `minimal-single-provider/` fixture directory, set `ANTHROPIC_API_KEY` and run it with an explicit hank path and data path. The example supplies both positional paths rather than relying on the bare-invocation wizard: ```text bunx hankweave@0.10.0 hank.json data/ ``` The startup capture below is what a healthy launch looks like. We can find the version, execution directory, hank structure, and server: ```text ╭────────────────────────────────────────────────────────────────────╮ │ Hankweave v0.10.0 │ │ darwin arm64 • node v23.8.0 │ ╰────────────────────────────────────────────────────────────────────╯ Created new execution directory: ~/.hankweave-executions/ New execution: Source → data Exec → ~/.hankweave-executions/ 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: ══════════════════════════════════════════════════ Running in headless mode on port ➜ Listening on: http://localhost:/ (all interfaces) ``` After a successful codon, a checkpoint seals as a git commit of the checkpointed files. The closing capture shows that checkpoint, a `codon.completed` event carrying its cost, and the server transitioning to `RunCompleted`: ```text {"id": "", "timestamp": "", "type": "state.transition", "data": {"transitionType": "CheckpointCreated", "runId": "", "codonId": "summarize-notes", "transition": {"type": "CheckpointCreated", "data": {"runId": "", "codonId": "summarize-notes", "checkpointType": "completed", "sha": "", "branch": "run-"}}, "resultingState": {"currentRunId": "", "runCount": 1, "totalCost":"", "currentRunCost":""}}} {"id": "", "timestamp": "", "type": "state.transition", "data": {"transitionType": "CodonTransitioned", "runId": "", "codonId": "summarize-notes", "transition": {"type": "CodonTransitioned", "data": {"runId": "", "codonId": "summarize-notes", "from": "running", "to": "completed", "metadata": {"exitCode": 0, "resultMessageReceived": true, "checkpointSha": "", "contextExceeded": false, "extensionCount": 0}}}, "resultingState": {"currentRunId": "", "runCount": 1, "totalCost":"", "currentRunCost":""}}} {"id": "", "timestamp": "", "type": "codon.completed", "data": {"codonId": "summarize-notes", "success": true, "cost":"", "duration":"", "exitStatus": {"type": "success"}}} {"id": "", "timestamp": "", "type": "state.transition", "data": {"transitionType": "RunCompleted", "runId": "", "transition": {"type": "RunCompleted", "data": {"runId": ""}}, "resultingState": {"currentRunId": null, "runCount": 1, "totalCost":"", "currentRunCost":""}}} ``` The failure path is just as visible. A missing key fails during the startup self-test, before any codon runs. The captured diagnostic is: ```text [] [ERROR] Self-test completed: FAILED [] [ERROR] Self-test FAILED: Some checks failed [] [ERROR] - authentication: ✗ No authentication found (set ANTHROPIC_API_KEY) [ERROR] Server startup failed! ``` Run the same explicit command again after the failure. The runtime resumes the existing execution directory from recorded state rather than starting from scratch. The complete validate, run, break, and resume walkthrough is in [the quickstart](/start/quickstart). ## Decide whether repeatability fits your work Before we commit to a hank, ask whether the work will benefit from a repeatable sequence. Keep it interactive or use ordinary automation if any of these three conditions is false: the workflow repeats, it is stable enough to describe in steps, and success has observable criteria. Hankweave is a poor fit for first-time exploration, a true one-off that will never run again, or work needing human steering every few minutes. In those cases, use a coding agent directly. Getting a new AI workflow to work once is easier than keeping it working six months later; a hank becomes useful when we need to carry a working method forward. For more help weighing that choice, see [is it right for you?](/start/is-it-right-for-you) and [why Hankweave](/start/why-hankweave). ## Follow one workflow from quotes to awards The fixture above showed the mechanics on one codon. The tutorial scales the same mechanics to a realistic job. In it, we build an end-to-end workflow from scratch: `quote-template-unification`, a fictional procurement request for quotation (RFQ) from Northstar Components with 5 bill-of-materials (BOM) parts and 8 quoting suppliers: 3 digitizer dialects plus 5 native extracts. One unknown-template supplier, GRN, is quarantined. We normalize, validate, repair, and reconcile the inputs into 40 supplier-part records – 40 data rows, or 41 CSV lines including the header – an exception ledger with 8 planted hazards, and a cited award brief. The captured run has 7 codons and $0.88 in tracked codon cost; provider health checks and sentinel calls are separate. We use the runtime's features as the work calls for them: seven codons seal after each step; the three digitizer normalizers remain agentic, while `rigs/native-inputs.ts` parses the five native exports and `rigs/render-exceptions.ts` renders the exception CSV. Per-codon budgets sum to a configured $9 cap; that is not a measured total or a price promise. The quality-observer sentinel receives completion-event status and budget fields, not artifact contents. `verify.py` checks the 40 rows and exception queue against held-out truth. We do not demonstrate killing this workflow and resuming it from a checkpoint at 0.10.0. The output is a cited award brief: every price and extension carries a citation back to its source document. Here is the beginning: ```text # Award brief ## Financial recommendation Projection of unified-records.csv only. Rank QUOTED, ranking_eligible=true rows by line_extension_minor; break equal-price ties by supplier_code ascending. Unit prices are already normalized per each upstream. No eligible bid means no recommendation; unsupported data stops export rather than inventing a price or citation. | Buyer part | Selected supplier | Unit price (USD per each) | Line extension (USD) | Tie / no-bid decision | Ineligible QUOTED suppliers | | --- | --- | --- | --- | --- | --- | | NC-1001-A | BCN | $3.95 [doc-beacon-8821:doc-beacon-8821-b1] | $1,975.00 [doc-beacon-8821:doc-beacon-8821-b1] | Unique lowest eligible bid | CDR [doc-cedar-cw-77:doc-cedar-cw-77-b1] | | NC-1002-A | AST | $0.79 [doc-aster-qb-1047-rev2:doc-aster-qb-1047-rev2-b2] | $1,580.00 [doc-aster-qb-1047-rev2:doc-aster-qb-1047-rev2-b2] | Unique lowest eligible bid | CDR [doc-cedar-cw-77:doc-cedar-cw-77-b2] | | NC-1003-B | EMB | $1.05 [doc-embar-quote:doc-embar-quote-b3] | $1,050.00 [doc-embar-quote:doc-embar-quote-b3] | Unique lowest eligible bid | CDR [doc-cedar-cw-77:doc-cedar-cw-77-b3] | | NC-1004-A | AST | $6.40 [doc-aster-qb-1047-rev2:doc-aster-qb-1047-rev2-b4] | $160.00 [doc-aster-qb-1047-rev2:doc-aster-qb-1047-rev2-b4] | Unique lowest eligible bid | None | | NC-1005-A | BCN | $0.19 [doc-beacon-8821:doc-beacon-8821-b5] | $950.00 [doc-beacon-8821:doc-beacon-8821-b5] | Unique lowest eligible bid | CDR [doc-cedar-cw-77:doc-cedar-cw-77-b5] | ``` All anchor corpus data is labeled `FICTIONAL TRAINING FIXTURE — NOT CUSTOMER DATA` and has data class `synthetic`; it contains no real customer, vendor, price, or transaction data. Build this anchor from scratch in [the 6-chapter tutorial and fixtures reference](/tutorial/0-tour). ## Choose a door into the docs The rest of the documentation splits by what you need to do next. Choose the destination that matches the job you have now: *Three doors from the index to the documentation paths.* ![Three doors from the index to the documentation paths.](/content-assets/cf45dff5691c48c0/diagrams/index/1.png) Three doors from the index to the documentation paths.
Diagram as text ```text [Index] / | \ [DO] [UNDERSTAND] [LOOK UP] | | | Build the anchor (~2.5h) 5-min model + Generated contracts · tutorial/0-tour 7 primitives dictionary | | start/how-a-run-works reference/* | concepts/* [Operator] → operate/* [Author] → author/* + tutorial [Integrator] → integrate/* [Contributor] → contribute/* [Agent] → /llms-full.txt ```
**Do** means building the anchor hands-on through `tutorial/0-tour` and chapters 1–5: six build chapters plus the fixtures reference, about 2.5 hours. **Understand** means starting with the 5-minute model in [how a run works](/start/how-a-run-works), then learning the 7 primitives one per page: codons, hanks, rigs, loops, sentinels, budgets, and checkpoints. **Look up** means using the generated contract pages in `reference/*` as a dictionary rather than a linear course. For operating a run, go to `operate/*`; for authoring one, `author/*` and the tutorial; for integration, `integrate/*`; and for contributing, `contribute/*`. Here, `*` names the family of pages under that route. For an agent, use `/llms-full.txt`: a build artifact specified to contain each docs page as clean Markdown at a stable URL, with a preamble for the version pin, one install command, harness-routing guidance, and a list of false claims to steer agents away from repeating. ## Track what changed in 0.10.0 The banner at the top describes hankweave 0.10.0. \[changed 0.10.0] This release has three breaking changes: strict hank reference paths, Pi catalog preflight, and late-bound harness selection. Read [upgrading](/start/upgrading) for the full narrative. \[changed 0.8.0] The earlier breaking surface introduced two in-process harnesses, made compaction off by default, and removed `GOOGLE_API_KEY` in favor of `GEMINI_API_KEY`. The complete migration story belongs in [upgrading](/start/upgrading). No computed compatibility table is supplied here at 0.10.0; the generated validation report records event and error extraction counts, not version compatibility. The upgrade narrative is the supported route for version changes. The footer “Built and tested by our doc hanks” is a documentation-build signal, not a runtime feature. It is enabled only after the documentation-maintenance hank runs in production; until then, it is absent or identifies the source of the last update.