Hankweave

Here, [changed X.Y.Z] marks a version-sensitive fact; unmarked facts describe the artifact this page documents.

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.

"When your agent fails on run #47, you don't debug emergent behavior — you trace the exact sequence of events, roll back to a checkpoint, and fix it."

"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.

[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; subprocess shims were removed in 0.8.0.

Running is the default operation. There are no CLI subcommands. The help's usage synopsis reads hankweave [options] [config-or-data-path] – quoted help text, not a runnable command:

Output
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.11.0 or npx hankweave@0.11.0. These commands launch the package's Node entry point, so install Node ≥ 22.19.0. Bun supplies the bunx launcher; npm supplies npx.

[since 0.3.0] The wizard detects the environment and offers a demo hank. Before launching the demo, the wizard verifies the chosen provider's credentials with a lightweight API call, catching dead keys and exhausted balances up front. Walk through those choices in 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 for the full output contract, or 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.11.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:

Output
bunx hankweave@0.11.0 hank.json data/

The startup capture below is what a healthy launch looks like. It was taken from a run started with --start-new, which is why it prints Created new execution directory:; a rerun of the plain command above without that flag resumes the newest matching execution instead, printing Resuming execution in: when one exists. We can find the version, execution directory, hank structure, and server:

Output
╭────────────────────────────────────────────────────────────────────╮
│  Hankweave v0.11.0                                                 │
│  linux x64 • node v22.23.2                                         │
╰────────────────────────────────────────────────────────────────────╯

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 collects anonymous usage statistics to help          │
│  improve the tool. No personal information, file contents,      │
│  or prompts are collected.                                      │
│                                                                 │
│  Learn more: https://docs.hankweave.dev/reference/telemetry     │
│  Opt out:    export HANKWEAVE_TELEMETRY=0                       │
│                                                                 │
│  This notice won't be shown again.                              │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘


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

Running in headless mode on port <port>
➜ Listening on: http://localhost:<port>/ (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:

Output
{"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>"}}}

The failure path is equally visible. A missing key fails during the startup self-test, before any codon runs. The captured diagnostic is:

Output
[<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!

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.

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.

"Greenfield AI is easy; brownfield AI — keeping it working six months later — is hard."

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, and come back when it breaks on run #47. 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? and 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 unified records – 40 data rows, or 41 CSV lines including the header – an exception ledger with eight exception types across eight rows (the corpus plants ten dialect hazards, D1–D10, each covered by a named invariant probe), and a cited award brief. The captured run has 7 codons and $0.73 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.

The output is a cited award brief: every price and extension carries a citation back to its source document. Here is the opening of the captured brief, through its generated financial table:

Output
# Award brief

<!-- BEGIN GENERATED FINANCIALS -->
## 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] |
<!-- END GENERATED FINANCIALS -->

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.

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.

FIG. 1 Three doors from the index to the documentation paths.
Read the diagram as text
Output
                                      [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, 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 this release#

[changed 0.11.0] Three breaking changes: git is now required (the runtime proves git --version runs before it creates, wipes or copies into an execution directory); every file.updated event now carries the six fingerprint fields path, filename, action, sha256, bytes and source, with no inline content body; and tool-path watched-file matching follows resolver semantics, so a slash-less pattern matches only the project root and gitignored or hard-excluded paths no longer emit. Read upgrading for the full narrative and the migration for each change.

[changed 0.10.0] The previous release's one breaking change was strict hank ref paths; its Pi catalog preflight and late-bound harness selection shipped as changes, not breaking changes.

[changed 0.8.0] The earlier breaking surface introduced the two in-process harnesses, made compaction off by default, and removed GOOGLE_API_KEY in favor of GEMINI_API_KEY.

No computed compatibility table is supplied; 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.