hands

Docs · Reference

Commands

Three surfaces, one install: slash skills you run in Claude Code, a hands CLI on your Bash PATH, and the hands_* MCP tools the agents use to coordinate.

Slash skills

SkillWhereWhat it does
/hands:expomain checkoutRun the expeditor at the pass: fires tickets, adjudicates questions, reviews returns, calls hands on finished dishes. Run always-on with /loop /hands:expo — its self-paced wakeup (~900s) doubles as the 15-minute utilization beat.
/hands:stationa station paneMake the pane an autonomous, event-driven station: arms a persistent Monitor on its notify file, then drains → works → yields on every wake. Run via /loop /hands:station; the loop timer is only a long fallback heartbeat (20–30 min), never message polling.
/hands:initmain checkoutConversational per-repo setup — asks for the principal, then runs hands init --yes …. The expo also runs this flow itself on first run if no config exists. Nothing to decide about the books: they are a local table, always on.
/hands:sousa dedicated sous paneRun the sous chef on this repo’s bus (agent id sous) — the expo’s first escalation hop, resolving recipe/product judgment itself or bubbling it to the operator already sitting in the pane. Event-driven like a station: run it via /loop /hands:sous.
/hands:cdca dedicated cdc paneRun the chef de cuisine on this repo’s bus (agent id cdc) — the quality role: rules whether a fresh ticket needs a plan, reviews submitted plans and returned PRs, and gates hands. Judge everywhere, producer nowhere. Event-driven like a station: run it via /loop /hands:cdc; gated on cdc.enabled.
/hands:dashboardanywhere in the repoBoots hands serve in the background if it isn’t already running and opens the live dashboard at localhost:4319.
/hands:recipeanywhere in the repoDraft a recipe — a structured menu item (title, description, gherkin-flavoured acceptance criteria). Interviews the principal, writes the file, and can promote it straight onto today’s menu.
/hands:readya station paneThe station-side shift-open: get this station to zero state and attest that it is clean, so the expo can dispatch to it. Covers the leftovers — uncommitted work, stashes, a stale branch, a dead inbox monitor.
/hands:line-checkmain checkout (expo)The expo-driven shift-open: read the previous shift’s page from the books and your own standing role-state page, bring the expo’s checkout current, see which stations are ready, re-confirm today’s menu.
/hands:last-callmain checkout (expo)The end-of-shift close-out: stand down every station, sweep mergeable dishes, distill role-state notes into the efficiency-of-the-pass page, close the books with a digest note, prep tomorrow’s in-flight work.
/hands:railanywhere in the repoPrint the current rail — tickets grouped by dish, menu coverage, the needs-you lane, station on-duty count — in the deterministic format the expo’s own reports use. Not routed through a running expo loop.
/hands:handsanywhere in the repoPrint everything currently waiting on the principal: open to-do items and unanswered needs_human escalations, grouped by priority and terse.
/hands:questionsanywhere in the repoSurface every escalation waiting on the principal through Claude Code’s native AskUserQuestion dialog — recommendation first, batched up to 4 per dialog — and write the answer straight back to the bus.

Five more ship with the plugin and are one-shot utilities rather than part of the daily loop: /hands:feedback (file a bug against hands), /hands:install-cli (put hands on your login shell’s PATH), /hands:login (optional GitHub sign-in), and /hands:low-usage / /hands:normal-usage (the machine-wide economy dial).

The hands CLI

The plugin puts hands on Claude Code’s own Bash PATH; curl -fsSL https://hands-cc.dev/install.sh | sh installs it to ~/.hands/bin for a normal terminal. Requires Node ≥ 22.5 (for node:sqlite). All commands run from anywhere inside the repo — and every one of them works from either install, except where a dev checkout badge below says otherwise: those need a cloned repo and a build step the standalone install has no way to run.

CommandWhat it does
hands init [--yes] [--principal <name>]Scaffold hands.config.json. Interactive on a TTY; --yes is non-interactive. Idempotent — an existing config is left untouched. The books need no setup: this fleet’s namespace in them is your OS username unless you set remote.handle yourself.
hands books [import <dir> [--merge] | verify]With no argument, print where the books are: the machine-wide SQLite file at ~/.claude/hands/books.db, this kitchen’s <project>/<handle> key, its page directory, and the event count. There is nothing to attach — the books stopped being a git repo, so no URL is configurable and journaling is never off. import <dir> reads an older NDJSON tree (journal/<project>/<handle>/log/*.ndjson) in; idempotent, since it replaces each kitchen’s rows rather than appending, and refuses any kitchen whose books already hold newer events — or that has already pushed to the cloud, where --merge appends only what’s missing instead of renumbering. verify compares the local table against the cloud copy seq by seq — the only honest check that a recovery actually took. See The books.
hands station activate <station-1..5>Wake one dormant slot: creates the worktree and branch, launches the session under tmux, or prints a paste-able launch command when tmux isn’t available. Idempotent — an already-open slot comes back described. Stations register with the expo on their first turn.
hands station lsList every slot in the line — activated and dormant alike, with each one's branch.
hands station deactivate <id> [--force]Return a slot to dormant — kills its wake tail and tmux session, removes the worktree and ephemeral branch. The slot stays on the board. --force discards uncommitted work.
hands scale <0..5> [--force]Open the first N slots and close the rest. A kitchen is five stations, so this moves them between activated and dormant rather than creating or destroying slots.
hands uiThe TUI — the whole kitchen in one terminal screen (see /docs/tui). Not in the curl | sh install: it runs dist-tui/main.mjs, which only npm run build:tui in a dev checkout produces, and which resolves ink/react from that checkout’s node_modules at runtime. Anywhere else it exits with the TUI isn’t built here. Dev checkout for now
hands daemon <start|stop|status>The supervisor: one wake watcher, the timers, the managed expo (and, opt-in, managed stations). The fleet that survives the view. Same bundle step as the TUI and the same limit — without npm run build:tui, hands daemon start exits with daemon bundle missing. Dev checkout for now
hands restoreRebuild local bus state — tickets, questions, focus, history — into hands.db by replaying this kitchen’s (project, handle) slice of the books. A local read; nothing is fetched. Scoped on purpose: one table now holds every kitchen on the machine, so an unscoped replay would let another handle’s ticket #7 land on top of yours. Idempotent, and deliberately not journal-wired, so replay never re-appends what it read.
hands recall [--type T]… [--since 7d]Query the books by event type and window. Repeat --type; bound with --since/--until, which take a duration (7d, 12h, 30m) or a bare date; narrow with --project, --handle, --agent, --limit (50), --json. An unreadable bound is a hard failure, not a silently widened window. This is the read the live tables cannot serve: a question escalated Tuesday and answered Thursday reads answered in questions, the escalation overwritten in place — only the books kept the transition.
hands journal read [--previous]Read a rendered page back — the day’s markdown, not raw events. With no flag, the most recent page that exists; --previous is the last page strictly before today, which is the shift-open read (a Monday gets Friday’s close without date arithmetic). Also takes --date, --limit, --json.
hands digest [--date YYYY-MM-DD]Re-render this kitchen’s human-readable pages under ~/.claude/hands/books/ — one <project>/<handle>/<date>.md per day plus a per-handle README index — from the book_events rows. The pages are derived and disposable: the render is deterministic, so deleting the tree and running this rebuilds it exactly. Nothing else renders them, so this is the command that makes the record browsable without hands installed.
hands serveServe the live dashboard at http://localhost:4319 (alias: hands dashboard; port override: HANDS_PORT). Reads stream over SSE, and it is a write surface too — answer escalations, settle the sous’s approvals, and file feedback from it. Those writes are loopback-only unless you start it with --lan --allow-writes. The server and its assets ship in the standalone install; the chat pane alone does not, because it drives the Claude Agent SDK out of a dev checkout’s node_modules — elsewhere POST /api/chat answers chat isn’t available in this install. Chat: dev checkout for now
hands loginOptional GitHub sign-in (browser handoff). Nothing else requires it — every command behaves identically signed in or not — but it is what gates the hosted half: without it nothing leaves the laptop. hands logout and hands whoami round it out.
hands relayThe sync beat against the hosted books (needs hands login): push this kitchen’s unsynced events up, then pull every other kitchen’s down — push-then-pull, so a machine sees its own work reflected in the same tick. See The books for what travels and what deliberately doesn’t.
hands pathsDump where the current directory resolves, as JSON: agent id, repo root, coordination dir, bus DB, notify path, the books file and this kitchen’s page dir, plus how many events are on the books and whether they are writable. For debugging.

MCP tools

The plugin registers a stdio MCP server whose tools all share the hands_ prefix. Agent identity is derived per-directory at runtime, so the same registration serves the expo and every station.

Messaging & awareness

ToolPurpose
hands_sendMessage another agent: to, body, optional subject/thread, and wake (default true — wake: false delivers silently on the next drain).
hands_receiveDrain the inbox. Long-polls up to wait_seconds (default 25, max 120, 250ms poll).
hands_peersList registered agents (online = seen within 15 minutes).
hands_historyRead past messages by peer or thread (limit ≤ 500).
hands_recallQuery the books — every state-changing action ever taken, across every kitchen on this machine: types, since/until (a duration like 7d, or a date), project/handle/agent, limit ≤ 500. hands_questions/hands_tasks answer what is true now and are overwritten in place; this is the only view of the transitions. Not expo-gated.
hands_boardThe bundled standup read. full: true returns active tasks, open questions, and today’s menu in one call; always returns the stateHash used for change detection.
hands_pathsWhere this agent resolves: identity, paths, the books file and page dir, and whether the books are writable.

Questions & escalation

ToolPurpose
hands_askEscalate an open question to the expo (always wakes it).
hands_questionsList questions by state: open, needs_human, answered.
hands_answerResolve a question — by: "expo" (auto-resolved) or by: "human" (the chef decided). Wakes the asker.
hands_escalateBubble a question up to the principal, with a recommendation.
hands_rec_outcomeThe expo’s hindsight self-audit: grade a past call validated or contradicted. Feeds the dashboard’s effectiveness scoring.

Work & focus

ToolPurpose
hands_menuRead today’s menu — the recipes in state menu, ranked, each with its criteria progress — plus whether the menu is unset or stale (24h). Never writes a recipe; confirm: true only re-stamps the current menu as still-current.
hands_recipe_statusRead one recipe: its criteria (checkbox state and latest grade), the overall grade, and the tickets laddering up to it. Re-syncs from the recipe file first, so it is never stale against disk.
hands_recipe_gradeRecord whether a recipe — or one specific acceptance criterion — is met. Append-only; the latest verdict wins and the history is kept. Never edits the recipe’s markdown checkbox: a disagreement between the two is the signal.
hands_delegatePut a ticket on the rail — expo and sous only, each holding one half: the expo assigns (to required — a named station), the sous composes (to dropped — the ticket lands queued for the expo to drain). title, body, recipeSlug (required, and the recipe must be on today’s menu), priority, dish, and force to dispatch past a missing attestation.
hands_tasksList tickets by state, assignee, or active-only.
hands_task_updateAdvance a ticket: in_progress (claims an unassigned one), returned (with result — wakes the expo), done, cancelled.
hands_todos / hands_todo_add / hands_todo_updateThe principal's to-do list: read, add, cross off / dismiss / re-open.
hands_focusSet a station’s lane label (what it’s currently on, ≤80 chars). A station may set its own; the expo may set anyone’s.

Expo-only & gated

ToolGatePurpose
hands_digest_noteexpoRecord a 2–5 line narrative note into today's page, under Notes. No config gate any more: the books are always on, so a note always lands — it shows up on the next page render.
hands_journal_readexpoRead a rendered page back from the books. With no date, the most recent page that exists; previous: true is the last page strictly before today, the shift-open read. Local and read-only — never blocks on the network.
hands_role_noteexpoCapture one raw, undistilled observation about how the pass is moving — a constraint a future session would want at the same moment. Stays pending until a fold pass reads it back.
hands_role_stateexpoRead a role's curated standing page plus every role note still pending a fold. The shift-open resume brief, and the input to the last-call fold.
hands_role_fold_doneexpoMark role notes up through a given id as folded, once you've rewritten the standing page to include them.
hands_obligationsexpoWhat the expo is waiting on: unclaimed tickets, in-flight tickets past a window, unanswered escalations — each with lastChasedAt so a nudge isn’t repeated blindly.
hands_chase_markexpoRecord that you chased a task or question, so the next obligations pass doesn't surface it as un-nudged.
hands_gh_pollexpoPoll GitHub for other engineers’ PRs (warns when gh.poll is off).
hands_station_activateexpo + stations.allowScalingOpen one specific slot (station-1..station-5). Idempotent — an already-open slot comes back described rather than re-created.
hands_station_deactivateexpo + stations.allowScalingReturn one slot to dormant — stops the session, retires the managed workspace, leaves the slot on the board. Refuses on uncommitted work unless forced.
hands_scaleexpo + stations.allowScalingOpen the first N slots (0–5) and close the rest. A kitchen is five stations, so this moves them between activated and dormant rather than creating or destroying slots.

Plans & review — the cdc’s gate

A plan is an artifact in the books, not a conversation: a station authors it, the cdc rules on it, and the plan’s state is the signal — nobody is messaged a verdict.

ToolWhoPurpose
hands_plan_write / hands_plan_submitthe assigned stationAuthor the plan for a ticket, in the station's own words, then submit it for review. The server refuses in_progress while a plan awaits approval or has changes requested.
hands_plan_statusanyoneRead a ticket’s plan state and the cdc’s adjudication — the first thing a station checks on a fresh assignment, since the ticket body may not say a plan was required.
hands_adjudicatecdcRule whether a freshly assigned ticket needs a plan before the station builds. Cheap by design — most tickets don't.
hands_plan_verdictcdcApprove a submitted plan or request changes — editing the plan artifact in place where specifics help.
hands_reviewcdcRecord the review verdict on returned work — the gate between a station's PR and the pass calling hands on it.

Install

in Claude Code
/plugin marketplace add https://hands-cc.dev/marketplace.json
/plugin install hands@hands