Skip to content
This repository was archived by the owner on Sep 6, 2026. It is now read-only.

Releases: sprayberry-archive/hands

v0.26.1

Choose a tag to compare

@github-actions github-actions released this 23 Aug 04:03
8547362

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-provenance v4.1.1 → v4.2.2 (the release-provenance attestation in auto-release.yml), and the three github/codeql-action steps (init, autobuild, analyze) moved together to ff2f1c6 — 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

Choose a tag to compare

@github-actions github-actions released this 07 Aug 13:50
6f8ed17

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. buildClaudeArgs never passed --model or --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/--model was 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 span sonnet-5, opus-5 and opus-4-8 with 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 inherited xhigh is 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 --resume too — the CLI does not persist them across resumes, so a continued session would otherwise drop back to the inherited default.

Added

  • effort config key, defaulting to medium — dispatch work is mostly mechanical. Override per-run with hands run -e high, persist with hands config --effort high; hands status shows the effective value. Unknown levels are rejected at parse time rather than passed through: a bad level kills the claude child 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

Choose a tag to compare

@github-actions github-actions released this 02 Aug 19:34
a87332d

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/--judge now reach a --do task action's own tool calls, in both hands watch --do --warden and hands job add --do ... --warden (the daemon's unattended, durable form). Previously --warden on a job was only wired to --play --heal's repair step — validateJob outright rejected --warden on a task action, so a daemon job's LLM-driven --do execution 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 --warden on a task action. Both fail closed on red-tier the same way hands run --warden already 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

Choose a tag to compare

@github-actions github-actions released this 02 Aug 18:32
822d828

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-6 was priced at
    Opus-4.1-era $15/$75 — actual is $5/$25; claude-haiku-4-5 was
    $0.8/$4 — actual is $1/$5. Added the Claude 5 family (Fable 5, Opus 5,
    Sonnet 5 at its introductory $2/$10 rate through 2026-08-31) and the
    missing 4.x entries.
  • An unrecognized model no longer silently prices at Sonnet 4.6's rate for
    --budget accounting — 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

  • --warden pointed 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
    at HANDS_WARDEN_PATH as the path verified working today, since npm's
    published @askalf/redstamp is 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

Choose a tag to compare

@github-actions github-actions released this 19 Jul 17:22
098f25b

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 --once scripting path records its successful effectful tool calls (unnamed — never saved as a macro on its own) and feeds them to recordRunAndMaybeLearn, so repeated subscription runs auto-promote a macro exactly like SDK runs. Off via HANDS_NO_LEARN=1 / config learn:false, same as before. powershell steps 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 --record option 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

Choose a tag to compare

@github-actions github-actions released this 19 Jul 03:10
67923e2

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 → bash steps, Write/Edit → edit steps, and Claude Code's Windows PowerShell tool → a new first-class powershell step. Capture commits a step only after its tool_result comes 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 (--once completion, 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 powershell macro step: replays via powershell -NoProfile -EncodedCommand (base64/UTF-16LE), which survives cmd'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. --export keeps these steps native in a .ps1 and shells out via -EncodedCommand from 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

Choose a tag to compare

@github-actions github-actions released this 12 Jul 14:34
39d03b2

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 survives serializeRecipe → reparse.
  • ClusterFuzzLite runs the targets weekly in CI (cflite.yml, batch mode); npm run fuzz is the fast local repro loop (FUZZ_SECONDS overrides the 30s default). The OSS-Fuzz base image is digest-pinned, with a dependabot docker entry keeping the pin fresh. Closes the OpenSSF Scorecard Fuzzing check.

Changed — workflow tokens drop to read-only at the top level

  • auto-release.yml and codeql.yml declared 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 is contents: 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

Choose a tag to compare

@github-actions github-actions released this 11 Jul 03:48
ba6afc9

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, ydotool is a thin client to the ydotoold daemon: the binary can be on PATH while the daemon isn't listening, in which case every mouse/keyboard call hangs until the 15s exec timeout. doctor previously 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 a ydotoold check that probes the daemon socket ($YDOTOOL_SOCKET → $XDG_RUNTIME_DIR/.ydotool_socket → /tmp/.ydotool_socket), reporting warn with 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 is warn, not fail, 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). doctor checked only whisper, so a user who ran hands voice-setup, got whisper, then ran --voice on macOS without SoX hit a runtime ENOENT — the exact failure doctor exists to pre-empt. The README promised "doctor reports it"; now it does. A voice.recorder check reports the platform's backend, matching getMicCommand()'s selection so doctor and the runtime never disagree: macOS rec (SoX), Linux arecord (ALSA), Windows ffmpeg/sox with the native PowerShell waveIn fallback. Missing on macOS/Linux is warn with the install hint (brew install sox / sudo apt install alsa-utils); Windows never fails (native fallback). warn doesn't flip the exit code — voice is opt-in — and --skip-whisper skips the recorder probe too.

Added — --ui semantic targeting now works on macOS (AX), not just Windows

  • hands run --ui lets 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 via osascript/JXA System Events (no native code, mirroring the keyboard path) and emits the same JSON shape the Windows enumerator does — so parseUiElements, the matcher, and the elementCenter → mouseClick click path (already cross-platform via cliclick) light up ui_tree / click_element end-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, --ui help, 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

Choose a tag to compare

@github-actions github-actions released this 03 Jul 02:19
f78fc36

Auto-released from merge of PR #111.


Built + tested + npm-published inline by auto-release.yml on this run.

v0.19.0

Choose a tag to compare

@github-actions github-actions released this 03 Jul 00:02
65f1549

Auto-released from merge of PR #110.


Built + tested + npm-published inline by auto-release.yml on this run.