Repository navigation
Releases: sprayberry-archive/hands
Release list
v0.26.1
Auto-released from merge of PR #170.
Patch bump: dependency and CI-action maintenance only — no runtime behavior change (#167, #168, #169).
Changed
@anthropic-ai/sdk^0.115.0→^0.117.1.- Pinned action digests refreshed:
actions/attest-build-provenancev4.1.1 → v4.2.2 (the release-provenance attestation inauto-release.yml), and the threegithub/codeql-actionsteps (init,autobuild,analyze) moved together toff2f1c6— init and analyze have to land on the same version or the CodeQL run fails.
Built + tested by auto-release.yml on this run; npm publish is tokenless via publish.yml (OIDC trusted publishing), dispatched by this run.
v0.26.0
Auto-released from merge of PR #166.
Minor bump: new -e/--effort flag on hands run and hands config (#166).
Fixed
- CLI mode pins model and effort instead of inheriting the human's interactive default.
buildClaudeArgsnever passed--modelor--effort, so every unattended run took whatever was set in the device owner's~/.claude/settings.json. Two consequences, both found while auditing 30 days of local Claude Code transcripts to explain fast subscription burn. First,-m/--modelwas advertised but dead in Claude Login mode —config.model(claude-sonnet-5) only ever reached SDK mode, which is why one box's hands sessions spansonnet-5,opus-5andopus-4-8with nobody having chosen that; they were tracking the human's interactive default as it drifted week to week. Second, inherited effort compounds: thinking blocks were the largest single contributor to context in the heaviest session audited (1.3MB of thinking vs 400KB for all tool results combined), and a session's context is re-read on every later turn, so an inheritedxhighis paid again each turn rather than once. A human switching to a 1M-context Opus at xhigh for their own work silently re-priced every headless run on the same machine. Both flags now ride along with--resumetoo — the CLI does not persist them across resumes, so a continued session would otherwise drop back to the inherited default.
Added
effortconfig key, defaulting tomedium— dispatch work is mostly mechanical. Override per-run withhands run -e high, persist withhands config --effort high;hands statusshows the effective value. Unknown levels are rejected at parse time rather than passed through: a bad level kills theclaudechild before a single turn, and persisting one would break every later run identically — the same reasoning as the existing NaN-budget guard.
Built + tested by auto-release.yml on this run; npm publish is tokenless via publish.yml (OIDC trusted publishing), dispatched by this run.
v0.25.0
Auto-released from merge of PR #154.
The daemon's --do task actions — the fully unattended form, no TTY, running whatever a job's trigger fires — can now be gated through warden's policy firewall. Minor bump: new --warden/--judge capability on a previously ungated execution path (#153).
Added
--warden/--judgenow reach a--dotask action's own tool calls, in bothhands watch --do --wardenandhands job add --do ... --warden(the daemon's unattended, durable form). Previously--wardenon a job was only wired to--play --heal's repair step —validateJoboutright rejected--wardenon a task action, so a daemon job's LLM-driven--doexecution had no policy-gating path at all, by construction rather than by omission.--judge(warden's gray-zone deobfuscator) is new alongside it, valid only with--wardenon a task action. Both fail closed on red-tier the same wayhands run --wardenalready does when unattended (no TTY).
Built + tested by auto-release.yml on this run; npm publish is tokenless via publish.yml (OIDC trusted publishing), dispatched by this run.
v0.24.0
Auto-released from merge of PR #152.
Default model moves to Sonnet 5, and the pieces that keep a run inside its
--budget get corrected. Minor bump: default-model change + new pricing-table
entries + a behavior change in how an unrecognized model prices (#151).
Changed
- Default model:
claude-sonnet-4-6→claude-sonnet-5(was one generation
behind). Verified live in oauth mode before the change. - SDK-mode pricing table corrected against current published rates. Two
entries were wrong independent of Claude 5:claude-opus-4-6was priced at
Opus-4.1-era$15/$75— actual is$5/$25;claude-haiku-4-5was
$0.8/$4— actual is$1/$5. Added the Claude 5 family (Fable 5, Opus 5,
Sonnet 5 at its introductory$2/$10rate through 2026-08-31) and the
missing 4.x entries. - An unrecognized model no longer silently prices at Sonnet 4.6's rate for
--budgetaccounting — it falls back to the most expensive known tier
instead (can only make the cutoff more conservative, never less) and warns
once per run. The table gates a real safety check
(if (currentCost >= maxBudgetUsd) break), so this was a correctness gap,
not a cosmetic one. (#151)
Fixed
--wardenpointed at@askalf/warden, which is a 404 on npm — the package
was renamed to@askalf/redstamp. The import specifier,--warden's help
text, and the error message now all say so; the error message also points
atHANDS_WARDEN_PATHas the path verified working today, since npm's
published@askalf/redstampis currently a stale snapshot missing the
subpath exports this integration needs. (#150)
Built + tested by auto-release.yml on this run; npm publish is tokenless via publish.yml (OIDC trusted publishing), dispatched by this run.
v0.23.0
Auto-released from merge of PR #136.
Auto-crystallize now works on a Claude subscription. v0.22.0 made explicit --record work in Claude Login mode; this completes the loop — the automatic learning that promotes a repeated task into a free macro (a 3rd similar run → auto-<slug>) was still SDK-mode only, because the CLI branch called the learning hook without a shadow trajectory. Now a hands run --once on your subscription shadow-captures its effectful steps from the same stream feed and hands them to the learner, so the flagship "the AI did it three times, here's the $0 replay" behavior fires for Claude Login users too.
Added
- CLI-mode shadow capture for auto-crystallize: the
--oncescripting path records its successful effectful tool calls (unnamed — never saved as a macro on its own) and feeds them torecordRunAndMaybeLearn, so repeated subscription runs auto-promote a macro exactly like SDK runs. Off viaHANDS_NO_LEARN=1/config learn:false, same as before.powershellsteps captured this way are correctly treated as replay-safe (they replay via-EncodedCommand), so a Windows subscription run promotes rather than being held back like multiline bash.
Fixed
- Stale docs from v0.22.0: the
--recordoption was still documented as "SDK mode only," and the CLI learning path claimed shadow trajectories "stay SDK-only." Both now describe the two-mode behavior.
Built + tested by auto-release.yml on this run; npm publish is tokenless via publish.yml (OIDC trusted publishing), dispatched by this run.
v0.22.0
Auto-released from merge of PR #134.
hands run --record now works on a Claude subscription. Recording was SDK-mode only — the capture hook lived at the SDK dispatch site, so the flagship crystallize-to-$0-macro flow demanded an API key (or a dario proxy) that most Claude Login users don't have. The stream-json feed CLI mode already parses carries every tool_use block with its full, un-truncated input, so the recorder now rides the stream instead: run a task on your subscription, and the successful effectful steps crystallize into a macro you replay free with hands play. Minor bump for the new powershell macro step type.
Added — --record in Claude Login mode
hands run --record <name> "<task>"captures from the stream-json feed when you're on Claude Login (oauth):Bash→bashsteps,Write/Edit→ edit steps, and Claude Code's WindowsPowerShelltool → a new first-classpowershellstep. Capture commits a step only after itstool_resultcomes back successful — failed or hook-blocked calls never crystallize (the v0.18 lesson, now enforced on both capture paths). The macro saves on clean session exit (--oncecompletion,exit, or Ctrl+C); a hard crash saves nothing, matching SDK behavior. Macro name validity and collisions are now refused up front in both modes, before the model does any work.- New
powershellmacro step: replays viapowershell -NoProfile -EncodedCommand(base64/UTF-16LE), which survivescmd's line-splitting — so multiline PowerShell replays reliably where multiline bash (execSync → cmd) famously does not, and the win32 replay-safety gate correctly ignores it. Guardrails check the raw command text, never the opaque encoded form.--exportkeeps these steps native in a.ps1and shells out via-EncodedCommandfrom an.sh.
Fixed
- The post-record hint pointed at
hands macro export, a subcommand that doesn't exist — it now points at the real surface,hands play <name> --export <file>.
Built + tested by auto-release.yml on this run; npm publish is tokenless via publish.yml (OIDC trusted publishing), dispatched by this run.
v0.21.1
Auto-released from merge of PR #130.
Supply-chain hardening release — no runtime behavior change. hands' three untrusted input streams get continuous fuzzing, and the release/CodeQL workflow tokens drop to read-only at the top level. Patch bump so the hardening (and the current README) ships to npm.
Added — continuous fuzzing of the trust-boundary parsers (ClusterFuzzLite)
- Three Jazzer.js targets pin the fail-safe contracts at the boundaries where hands consumes input it doesn't control.
fuzz/hook_decide.fuzz.js: the PreToolUse guardrail hook never throws on an arbitrary payload and never denies without a reason — the enforcement seam matters most, because the runtime deliberately fails open and a crash there would silently disable the hard-block list.fuzz/cli_stream.fuzz.js: the Claude Code JSONL stream parser yields[]on malformed lines and unknown event shapes, never a throw.fuzz/recipe_parse.fuzz.js: the recipe frontmatter/step parser never throws, the name validator never accepts a path-traversal shape (recipe names become filenames), and a parsed Recipe survivesserializeRecipe→ reparse. - ClusterFuzzLite runs the targets weekly in CI (
cflite.yml, batch mode);npm run fuzzis the fast local repro loop (FUZZ_SECONDSoverrides the 30s default). The OSS-Fuzz base image is digest-pinned, with a dependabotdockerentry keeping the pin fresh. Closes the OpenSSF Scorecard Fuzzing check.
Changed — workflow tokens drop to read-only at the top level
auto-release.ymlandcodeql.ymldeclared their write scopes (contents,actions,security-events, …) at the workflow level, so every job inherited them. The scopes now live on the single job that uses them and the top level iscontents: read— closing the three open Scorecard Token-Permissions findings. Same steps, same effective scopes, narrower blast radius.
Built + tested by auto-release.yml on this run; npm publish is tokenless via publish.yml (OIDC trusted publishing), dispatched by this run.
v0.21.0
Auto-released from merge of PR #122.
hands doctor stops reporting green on dependencies it never actually checked, and --ui semantic targeting crosses from Windows to macOS. Two doctor probes now back promises the README already made: the Wayland ydotoold input daemon and the voice recording backend were both assumed present — reported healthy when they could be missing, then turning into a hang-to-timeout or a runtime ENOENT the moment you used input or --voice. And the accessibility-tree targeting that lets the agent click a control by name instead of by pixel — Windows-only since v0.14.0 — now walks the macOS AX tree too, with zero changes downstream of enumeration. Minor bump for the new macOS platform surface.
PRs in this release: #119 (ydotoold probe), #120 (voice recorder check), #121 (macOS AX targeting).
Fixed — hands doctor now probes the ydotoold daemon on Wayland, not just the ydotool binary
- On Wayland,
ydotoolis a thin client to theydotoolddaemon: the binary can be onPATHwhile the daemon isn't listening, in which case every mouse/keyboard call hangs until the 15s exec timeout.doctorpreviously checked only the binary and reported input ok — the README already promised it "reports whether the daemon is reachable", but it didn't. It now emits aydotooldcheck that probes the daemon socket ($YDOTOOL_SOCKET→$XDG_RUNTIME_DIR/.ydotool_socket→/tmp/.ydotool_socket), reportingwarnwith a start hint when the daemon is down. The probe is an existence check only — it synthesizes no input — and is Wayland-only, so X11 / macOS / Windows reports are unchanged. A missing daemon iswarn, notfail, so it doesn't flip the exit code.
Fixed — hands doctor now reports the voice recording backend, not just whisper
- Voice needs two separate installs: whisper (transcribes a WAV) and a recording backend (captures the mic).
doctorchecked only whisper, so a user who ranhands voice-setup, got whisper, then ran--voiceon macOS without SoX hit a runtimeENOENT— the exact failure doctor exists to pre-empt. The README promised "doctor reports it"; now it does. Avoice.recordercheck reports the platform's backend, matchinggetMicCommand()'s selection so doctor and the runtime never disagree: macOSrec(SoX), Linuxarecord(ALSA), Windowsffmpeg/soxwith the native PowerShell waveIn fallback. Missing on macOS/Linux iswarnwith the install hint (brew install sox/sudo apt install alsa-utils); Windows never fails (native fallback).warndoesn't flip the exit code — voice is opt-in — and--skip-whisperskips the recorder probe too.
Added — --ui semantic targeting now works on macOS (AX), not just Windows
hands run --uilets the agent read the OS accessibility tree and click a control by name and role instead of by pixel. It was Windows-only (UIAutomation); it now works on macOS too. A new AX enumerator walks the frontmost app's Accessibility tree viaosascript/JXA System Events (no native code, mirroring the keyboard path) and emits the same JSON shape the Windows enumerator does — soparseUiElements, the matcher, and theelementCenter → mouseClickclick path (already cross-platform viacliclick) light upui_tree/click_elementend-to-end with no changes downstream of enumeration.- Missing Accessibility permission yields an actionable grant message (System Settings → Privacy & Security → Accessibility) instead of an opaque failure. The Windows path is byte-identical. Linux (AT-SPI) remains unwired and rejects with a clear message. Tool descriptions,
--uihelp, the README platform table + Semantic UI section reflect macOS support.
Built + tested + npm-published inline by auto-release.yml on this run.
Release notes backfilled after #123 fixed the empty-body extraction bug; the artifact + npm publish are unchanged.
v0.20.0
Auto-released from merge of PR #111.
Built + tested + npm-published inline by auto-release.yml on this run.
v0.19.0
Auto-released from merge of PR #110.
Built + tested + npm-published inline by auto-release.yml on this run.