Repository navigation
Hankweave v0.11.0
·
6 commits
to release/alpha
since this release
Installation
Via npm:
npm install -g hankweave
# or
npx hankweave --initVia 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
--yesaccepted as a long alias for-y(#233)- Finalize-time journal diet with byte-identical restore — a finished run's
events.jsonlcan 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), andjournal.meta.jsonrecords 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 viadietOnFinalize(HANKWEAVE_RUNTIME_DIET_ON_FINALIZE, default on; set tofalseto opt out), gated on terminal runs. The trace upload (hankweave-trace, synchronous) runs first because it readsevents.jsonloff 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.syncfull 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-sdk0.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-sdk0.144.5 → 0.153.4 (shim rebuilt;CODEX_SDK_VERSIONcache key stamped 0.153.4 — it was stale at 0.144.6) - Updated model data — refreshed
models-dev-data.jsonfrom 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-previewwas removed upstream.gemini-3.8-flashis now the most recent Gemini flash entry, so fuzzy queries likegemini-flashresolve to it instead ofgemini-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
gitused 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 provesgit --versionruns before the execution directory is created, wiped, or copied into, andHankweaveRuntime.start()proves it again first thing in boot; either failure is a clearGitUnavailableErrortelling 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.updatedcarries fingerprints, never file bodies — everyfile.updatedevent (journal and WebSocket broadcast alike) now carriessha256(hex hash of the body's UTF-8 text),bytes, andsource({kind: "tool_use", toolUseId}for a file tool call,{kind: "codon-start"}for the tracker's initial snapshot) instead of an inlinecontentbody. The change's bytes live in theassistant.actionreceipt thesource.toolUseIdjoins to — Write bodies and Editold_string/new_stringare journaled verbatim intoolInput, now a pinned never-truncated contract (only tool results truncate); full file states live on disk and in checkpoints.assistant.actiongainstoolUseId(required, withtoolName, whenactionis"tool_use").state.snapshot.recentFileAccessslims to a{path, timestamp}pointer. Sentinels are unaffected: triggers onpath/filename/actionwork unchanged, andcontentconditions 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 (contentis 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/schemasand recorded aseventSchemaVersioninevents.meta.json; v2 is not additive — a consumer that readfile.updated.contentmust 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.updatedmatching now follows resolver semantics — the per-tool-call check that decides whether aRead/Write/Edit/MultiEdittarget counts as a watched file now goes through the sharedUnifiedFileResolver(micromatch + cached gitignore rules) instead of raw minimatch withmatchBase. Two consequences for hank authors: a slash-less pattern like*.mdornotes.mdnow matches only at the project root on the tool path (write**/*.md/**/notes.mdfor 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 emitfile.updatedon tool use. This makes the journal, sentinel routing, andstate.snapshotconsistent with the checkpoint system for the samecheckpointedFileslist, as the config schema always promised. The directminimatchdependency is removed (a BiomenoRestrictedImportsrule keeps it out). Spec:intermediates/65-watched-patterns-bugs/02-divergent-pattern-matching.md - Event journal writer holds its file open —
FileEventStorageopensevents.jsonlonce instead of reopening it for every event, and remembers the event count in an advisoryevents.meta.jsonsidecar 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, andtscaccept 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
checkpointedFilesacross 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
archiveOnSuccessarchives 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 (andorphanentries) 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.toCheckpointthrough 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.";--headlessis now always treated as non-interactive (it never prompts, even from a real terminal), and the$schemaauto-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 0is now accepted on the command line (0 disables the timeout, matching the documented default); values are parsed as strict integers, so inputs like0.5or0junknow error instead of being silently truncated (#232)--helpnow 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) Readno longer fabricatesfile.updatedevents — reading a watched file used to journal afile.updatedwithaction: "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.updatedstill fires at tool-use time forWrite/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
corruptLinescount) 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 --helpLinux
- x64:
hankweave-linux-x64 - ARM64:
hankweave-linux-arm64
chmod +x hankweave-linux-x64
./hankweave-linux-x64 --helpWindows
- x64:
hankweave-windows-x64.exe
.\hankweave-windows-x64.exe --help