Skip to content

Hankweave v0.11.0

Choose a tag to compare

@github-actions github-actions released this 16 Sep 18:46
· 6 commits to release/alpha since this release

Installation

Via npm:

npm install -g hankweave
# or
npx hankweave --init

Via Standalone Executable:
Download the binary for your platform below, make it executable, and run it.

What's Changed

[0.11.0] - 2026-09-16

Added

  • --yes accepted as a long alias for -y (#233)
  • Finalize-time journal diet with byte-identical restore — a finished run's events.jsonl can now be shrunk: file bodies ≥ 4 KB move into a per-run content-addressed store (.hankweave/events/cas/, zstd -19, each unique body stored once), the remaining pointer journal is compressed whole (events.jsonl.zst, zstd -3), and journal.meta.json records the original's SHA-256. hankweave --restore-journal <executionPath> rebuilds the original journal byte-for-byte, proven against that hash; hankweave --diet-journal <executionPath> runs the diet offline. The diet verifies the restore from disk before unlinking the original (a crash at any point leaves either the intact original or a complete verified diet — SIGKILL-tested ×25), is idempotent, and only rewrites a line after proving the rewrite inverts to the exact original bytes. Runs at run end by default via dietOnFinalize (HANKWEAVE_RUNTIME_DIET_ON_FINALIZE, default on; set to false to opt out), gated on terminal runs. The trace upload (hankweave-trace, synchronous) runs first because it reads events.jsonl off disk, and the shutdown watchdog is re-armed after it so the diet gets its own 30 s window: shutdown is bounded per phase (cleanup, upload, diet) rather than by one 30 s span, and a slow multi-run trace upload can no longer starve the diet. The runtime auto-restores a dieted directory on boot or resume (verified byte-identical; the stale diet pair is pruned, the CAS kept for the next diet's dedup) — interrupt-then-resume just works, and the run re-diets at its next finalize. Damaged diet artifacts still fail the boot rather than running against a hole. Offline readers (streamAllEvents, getAllEvents, tail/cursor reads) work transparently against dieted directories without restoring. Plan: intermediates/60-shim-debug-diet/phase-3-finalize-diet.md
  • Event journal cursor pages — IEventStorage.getEventsAfter(cursor, limit) pages forward through the journal with opaque (segment, line) cursors that are stable across restarts. history.sync full scans now run through it, and it is the primitive later journal work (segment rotation, resumable sync) builds on. IEventStorage.close() flushes and releases the journal on shutdown.

Changed

  • Updated @anthropic-ai/claude-agent-sdk 0.3.232 → 0.3.267 (extraction cache key bumped to match), the pi packages (@earendil-works/pi-coding-agent, @earendil-works/pi-ai) 0.84.2 → 0.85.1 (pi shim bundle rebuilt against 0.85.1; 0.85.1 adds GPT-6 Astra support), and the codex shim's @openai/codex-sdk 0.144.5 → 0.153.4 (shim rebuilt; CODEX_SDK_VERSION cache key stamped 0.153.4 — it was stale at 0.144.6)
  • Updated model data — refreshed models-dev-data.json from models.dev (188 → 213 providers, 6,472 → 7,436 models). New models: anthropic/claude-fable-5-1 (Claude Fable 5.1, verified end-to-end via the init hank), google/gemini-3.8-flash (Gemini 3.8 Flash), openai/gpt-6-astra (GPT-6 Astra); google/gemini-robotics-er-1.6-preview was removed upstream. gemini-3.8-flash is now the most recent Gemini flash entry, so fuzzy queries like gemini-flash resolve to it instead of gemini-flash-latest
  • BREAKING (behavioral): git is now required. Checkpoints, rollback, and crash recovery are all built on the shadow git repository, so a host without a runnable git used to be silently downgraded — "Git is not available. Checkpointing disabled." in the log, then a run with no save points at all. The CLI now proves git --version runs before the execution directory is created, wiped, or copied into, and HankweaveRuntime.start() proves it again first thing in boot; either failure is a clear GitUnavailableError telling you to install git and put it on PATH, with nothing touched. There is no opt-out: checkpoints are not optional, so neither is git.
  • BREAKING (schema): file.updated carries fingerprints, never file bodies — every file.updated event (journal and WebSocket broadcast alike) now carries sha256 (hex hash of the body's UTF-8 text), bytes, and source ({kind: "tool_use", toolUseId} for a file tool call, {kind: "codon-start"} for the tracker's initial snapshot) instead of an inline content body. The change's bytes live in the assistant.action receipt the source.toolUseId joins to — Write bodies and Edit old_string/new_string are journaled verbatim in toolInput, now a pinned never-truncated contract (only tool results truncate); full file states live on disk and in checkpoints. assistant.action gains toolUseId (required, with toolName, when action is "tool_use"). state.snapshot.recentFileAccess slims to a {path, timestamp} pointer. Sentinels are unaffected: triggers on path/filename/action work unchanged, and content conditions and templates keep working — the sentinel view resolves the body at trigger time from a fingerprint-addressed retained-body map with a hash-verified disk fallback (content is now a registered virtual field for condition-path validation). The event payload contract is versioned file-level: EVENT_SCHEMA_VERSION (2) is exported from @southbridgeai/hankweave/schemas and recorded as eventSchemaVersion in events.meta.json; v2 is not additive — a consumer that read file.updated.content must move to the receipts-and-fingerprints model (toolInput + sha256 + checkpoints). Measured motivation: file bodies were 77% of fleet journal bytes, 43.5% of them byte-identical repeats. Design: intermediates/60-shim-debug-diet/proposal-fingerprint-events.md
  • BREAKING (behavioral): tool-path file.updated matching now follows resolver semantics — the per-tool-call check that decides whether a Read/Write/Edit/MultiEdit target counts as a watched file now goes through the shared UnifiedFileResolver (micromatch + cached gitignore rules) instead of raw minimatch with matchBase. Two consequences for hank authors: a slash-less pattern like *.md or notes.md now matches only at the project root on the tool path (write **/*.md / **/notes.md for recursive intent, matching what the codon-start snapshot and checkpoint system always did), and gitignored files plus hard-excluded paths (read_only_data_source/, checkpoint shadow repos) no longer emit file.updated on tool use. This makes the journal, sentinel routing, and state.snapshot consistent with the checkpoint system for the same checkpointedFiles list, as the config schema always promised. The direct minimatch dependency is removed (a Biome noRestrictedImports rule keeps it out). Spec: intermediates/65-watched-patterns-bugs/02-divergent-pattern-matching.md
  • Event journal writer holds its file open — FileEventStorage opens events.jsonl once instead of reopening it for every event, and remembers the event count in an advisory events.meta.json sidecar instead of rescanning the whole journal at startup (measured in the investigation: writes 28K → 272K events/s; on-disk format unchanged). WebSocket handshakes now read the last events by seeking from the end of the file instead of parsing the entire journal (241 ms → sub-ms on a 200 MB journal).

Fixed

  • The two bundled models-data JSON imports in the LLM provider registry now carry with { type: "json" } import attributes. Deno refuses a bare JSON import, so any module graph that reached the registry failed to load there; Bun, Node 22, and tsc accept the attribute unchanged.
  • Crash-safe checkpoint storage (#239) — a kill during the first checkpoint no longer leaves a half-built shadow repository that the next start accepts: the repository is built in a temporary folder and renamed only once its first entry exists; on start, a folder git cannot read is rebuilt and stale git lock files are removed; checkpoint storage is proven readable before the state file is loaded, so "could not read the repository" can never look like "no checkpoints"; a completed codon can no longer record an empty checkpoint id; and recovery rolls back only to save points git confirms exist - when none is restorable the working folder is saved to a recovery/<timestamp> branch, a "Recovery degraded" event is emitted and a fresh run starts. A rollback error no longer kills startup: a rollback rejected before touching files falls through to continuation, one that failed after changing files stops the boot and names the pre-rollback copy.
  • Loop iterations keep their checkpointedFiles across a restart — checkpoint patterns are read from the execution plan rather than the top-level codon list, so a loop iteration registers its own patterns (and the same helper restores them after a rollback); previously a loop child's patterns were dropped after a restart and its files went uncheckpointed.
  • A rig setup runs again when a restart crossed a run boundary — a rig is skipped only when its rig-setup checkpoint was taken in the run currently executing; a rig-setup checkpoint from an earlier run no longer lets a retry skip the rig after the working folder was restored to an older state.
  • Resume rollback no longer logs a bogus "Target checkpoint … not found in manifest" error or un-archives the wrong files (#228). The archive manifest is not a checkpoint registry — only archiveOnSuccess archives ever land in it — so the old list-order lookup failed on every ordinary resume and, when the manifest was non-empty, fell back to restoring every archive, including ones made at or before the rollback target. Rollback now selects entries to restore by git reachability (git rev-list target..pre-rollback-HEAD): entries archived strictly after the target on the abandoned line (and orphan entries) are restored; entries at or before the target or on unrelated timelines stay archived; entries whose checkpoint SHA the repository does not know stay archived with a warning. Only successfully restored entries leave the manifest, and an archived copy never overwrites a path the target checkpoint tree already contains. Every rollback path (automatic resume, rollback.toCheckpoint through history, and the startup continuation seed) already verifies the target and snapshots the work tree before touching a file, so a failed rollback leaves the workspace intact.
  • Resuming an execution with a changed hank.json in a non-interactive environment (CI, piped stdio, --headless) now fails closed with a self-contained error explaining the hash mismatch and the real recovery options (-y, --start-new, --start-new --force), instead of the misleading "Operation cancelled by user."; --headless is now always treated as non-interactive (it never prompts, even from a real terminal), and the $schema auto-add now happens before the execution hashes are recorded (with the hank hash additionally computed on $schema-normalized content), so rewriting a schema-less hank.json no longer makes the very next resume report a phantom config or data-source change.
  • --idle-timeout 0 is now accepted on the command line (0 disables the timeout, matching the documented default); values are parsed as strict integers, so inputs like 0.5 or 0junk now error instead of being silently truncated (#232)
  • --help now documents --replay, --max-cost, --max-time, --without-proxy, and --ignore-data-mismatch (marked deprecated); a parity test keeps the help text in sync with the parser's flag inventory (#230)
  • Rerunning an already-completed execution (same data hash, no --start-new) now prints a clear notice — "Resumed completed execution — nothing to do. All codons already completed. Use --start-new to run fresh." — on the console in headless mode and via the info event in TUI mode, instead of exiting silently like a successful fresh run. Exit code stays 0. (#231)
  • Read no longer fabricates file.updated events — reading a watched file used to journal a file.updated with action: "modified" and the full file body embedded, although nothing touched the file. The audit log over-counted modifications, sentinels fired on phantom changes, and repeated reads of large reference files duplicated their bodies in the journal. Read is now excluded from watched-file tracking entirely (it also no longer updates the recent-file state or rebuilds the file tree). file.updated still fires at tool-use time for Write/Edit/MultiEdit; moving emission to confirmed tool results remains a separate change. Spec: intermediates/65-watched-patterns-bugs/03-read-bug-explainer.md
  • A corrupt journal line no longer breaks client connection — the event journal reader skips unparseable lines (reporting a corruptLines count) instead of throwing mid-handshake, and a torn final line left by a crash is healed on the next startup so new events can't fuse with it. Previously one half-written line made every history-requesting WebSocket handshake fail with a SyntaxError.

Platform-Specific Instructions

macOS

  • Apple Silicon (M1/M2/M3): hankweave-darwin-arm64
  • Intel: hankweave-darwin-x64

After downloading:

xattr -d com.apple.quarantine hankweave-darwin-arm64
chmod +x hankweave-darwin-arm64
./hankweave-darwin-arm64 --help

Linux

  • x64: hankweave-linux-x64
  • ARM64: hankweave-linux-arm64
chmod +x hankweave-linux-x64
./hankweave-linux-x64 --help

Windows

  • x64: hankweave-windows-x64.exe
.\hankweave-windows-x64.exe --help