You lead. hand runs the crew.
Secondhand turns one coding-agent session into a supervisor for a fleet of coding agents.
You talk to one agent. It plans the work, writes briefs, dispatches workers into isolated git worktrees, watches them, steers them when needed, and brings the results back to you.
hand is the CLI underneath that workflow. It owns lifecycle, state, isolation, and process supervision so the supervising agent can focus on judgment and coordination.
The canonical cross-cutting terms for this workflow are defined in Hand orchestration vocabulary.
flowchart LR
user["You"] --> supervisor["Supervising agent"]
supervisor --> hand["hand"]
hand --> shipTask["Task: ship"]
hand --> scoutTask["Task: scout"]
shipTask --> worker1["Worker"]
scoutTask --> worker2["Worker"]
worker1 --> pr1["PR / branch"]
worker2 --> report["Report"]
pr1 --> supervisor
report --> supervisor
Secondhand was inspired by firstmate, rebuilding the same agent-fleet idea as a focused Go CLI.
Coding agents are good at working on a task. Running several of them reliably is a different problem.
Someone still has to:
- give each worker enough context
- keep concurrent work isolated
- know which worker is running, blocked, or done
- steer a worker without restarting it
- preserve task state across supervising sessions
- decide when work is ready to merge or hand off
- clean up worktrees and processes without losing unfinished work
Secondhand splits those responsibilities cleanly: the supervisor handles judgment; hand handles mechanics.
From a release:
curl -fsSLO https://github.com/atqamz/hand/releases/latest/download/hand-linux-amd64.tar.gz
tar xzf hand-linux-amd64.tar.gz
install -m755 hand ~/.local/bin/handOr with Nix:
nix profile install github:atqamz/handSee Installation for every supported option.
A fleet home is the directory where the supervising agent lives and where Secondhand keeps fleet state.
mkdir ~/fleet
cd ~/fleet
hand inithand init is non-interactive. It creates the fleet structure and writes a managed block into AGENTS.md telling any supervising harness to run hand session start before acting, with a CLAUDE.md reference when that name is otherwise absent. This is a symlink on Unix and an @AGENTS.md pointer file on Windows.
hand project add https://github.com/you/projectSecondhand clones the repository under the fleet home and prepares it for isolated worker worktrees.
For Claude Code:
cd ~/fleet
claudeThe generated AGENTS.md block tells the harness to run hand session start before responding or acting; that command loads bounded fleet context and reports the first next action, and refuses outright inside a worker's isolated worktree. Any other supported harness reads the same instructions from AGENTS.md directly.
On the first session, the supervisor inspects hand config, asks only unresolved configuration policy questions, and persists accepted profile and route choices through the CLI.
Talk to the supervisor normally:
Fix the login regression. Also investigate why the integration tests are flaky, but do not change anything for that investigation yet.
The supervisor can dispatch the fix as a ship task and the investigation as a scout task, then coordinate both while you keep talking to one agent.
flowchart TD
request["Your request"] --> brief["Supervisor writes a brief"]
brief --> spawn["hand spawn"]
spawn --> worktree["Worker in an isolated worktree"]
worktree --> supervise["Watch and steer"]
supervise --> outcome{"Task kind"}
outcome -->|ship| ship["PR or local branch"]
outcome -->|scout| scout["Investigation report"]
ship --> finish["Merge or deliver"]
scout --> finish
finish --> teardown["hand teardown"]
Ship tasks make changes. A Task is durable logical work and its worker run is an Attempt with its own disposable execution identity. A worker receives its own git worktree, works independently, and produces a pull request or local branch according to the project's delivery mode.
Scout tasks investigate without being expected to ship code. They return data/<id>/report.md, and a completed scout can later be promoted into a ship task. Promotion preserves the scout Attempt and starts a new ship Attempt.
Task kind describes the intended deliverable: scout produces an investigation or report, while ship produces a change that must be landed or explicitly delivered.
Execution class describes how much implementation judgment remains after supervisor planning:
| Class | Meaning |
|---|---|
mechanical |
The plan is decision-complete; the worker applies the specified changes and verifies them. |
standard |
Architecture is decided; ordinary reversible local implementation judgment remains. |
deep |
Substantial implementation reasoning remains with the worker. |
Task kind and execution class are orthogonal.
For example, ship + mechanical, ship + standard, ship + deep, and scout + deep are meaningful combinations.
Execution classes describe remaining judgment, not task size, line count, file count, worker role, model, or cost.
A supervisor-created execution-class brief records the project revision it was planned against:
---
execution_class: mechanical
planned_against: <full commit ID>
---planned_against is the full commit ID of the registered project's verified local default branch in <home>/projects/<project>.
For mechanical, Hand refuses dispatch when that project base no longer matches exactly, before provisioning begins.
For standard and deep, the value is provenance only and does not trigger the mechanical exact-match refusal.
Because Treehouse may refresh a leased worktree during acquisition, Hand also verifies the acquired worktree HEAD against the same commit and refuses to launch when it differs.
Mechanical dispatch also requires a harness capable of carrying the shared mechanical worker guidance; unsupported harnesses fail as a precondition before lifecycle mutation.
The supervisor must re-check the plan and rewrite or revalidate it before recording a new revision.
These fields are optional, so briefs without them and legacy model/effort front matter retain their existing behavior.
Execution-ready body sections such as goal, verified current state, locked decisions, implementation steps, invariants, tests, verification, non-goals, and stop conditions are recommendations for mechanical briefs, not required syntax.
Classified briefs use the configured execution-profile route for their Task kind and execution class.
The supervisor inspects hand config, creates profiles with hand config profile set, and binds each kind-and-class combination with hand config route set.
Every worker operates in a git worktree leased through treehouse. Workers never edit the registered project clone directly.
Workers run interactively inside herdr, so the supervisor can observe semantic agent state, send follow-up instructions with hand send, and react to fleet events with hand watch without scraping a terminal for meaning.
Send outcomes are recorded against the Attempt and visible in hand status <id>; unresolved outcomes require operator judgment before steering again.
The terminal submission uncertainty decision record owns the outcome and recovery contract.
Machine state lives in SQLite while operator context, briefs, reports, backlog history, and learnings remain plain files. The fleet survives the supervising agent's session, so a later session can pick up where the previous one stopped.
SQLite is durable intent and history, while Git, treehouse, herdr, and worker processes are observed reality.
hand reconcile compares those independently owned facts and records needs-repair when safe convergence cannot be proven.
The deterministic reconciliation decision record owns the recovery invariants.
hand status remains read-only and displays repair markers without attempting cleanup.
hand fails closed around destructive or irreversible transitions. Teardown refuses unlanded work unless it was explicitly delivered, and the generated supervisor rules prohibit merging without operator authorization.
hand is designed primarily for agent callers rather than as a terminal dashboard. Commands return compact structured TOON documents with named fields, aggregates, machine-readable states, and suggested next actions. Read commands that support it retain --json as an alternative.
Each registered project has a delivery mode:
| Mode | Workflow |
|---|---|
direct-pr |
Workers produce normal branches and pull requests. This is the default. |
no-mistakes |
Delivery uses no-mistakes as a gate. |
local-only |
Work stays local instead of using a remote pull-request workflow. |
no-mistakes is a delivery gate, not a Hand Task kind.
Its internal review, test, documentation, lint, PR, and CI stages remain owned by no-mistakes rather than becoming Hand Task kinds.
Choose a mode when registering a project:
hand project add https://github.com/you/project --mode direct-prFor a fork, declare the upstream repository that receives pull requests:
hand project upstream project-name upstream-owner/projectIf the repository is renamed or transferred, repoint the registered project without changing its local identity:
hand project set-url project-name https://github.com/you/renamed-project.gitThis keeps the project name and projects/<name> clone path stable, updates both the registry URL and clone origin, and preserves tasks and completion history.
hand project sync can also repair a recognized GitHub rename when GitHub reports the canonical repository.
Secondhand can launch workers through:
- Claude Code (
claude) - Codex (
codex) - Grok (
grok) - Pi (
pi) - OpenCode (
opencode)
Without an override, workers inherit the harness detected as the current supervisor; only when none can be detected does hand config report the harness as missing. Inspect and configure fleet defaults with:
hand config
hand config set harness claude
hand config set model claude-opus-5
hand config profile set claude --harness claude
hand config route set ship standard claudeThe harnesses table lists supported harnesses and whether each is installed on PATH.
Model and effort support depends on the harness: hand config reports each as native-default, configured, or unsupported instead of silently storing a setting a harness cannot carry.
Overrides are stored per harness, so switching harnesses never hands a worker a model or effort chosen for a different tool.
Normally, a task brief omits model and effort front matter so its configured route controls execution. Use those values as explicit overrides only for a genuine task-specific need; explicit spawn or promote flags win over brief values, which win over profile values.
A fleet home is deliberately separate from the repositories being worked on.
~/fleet/
├── AGENTS.md
├── CLAUDE.md
├── config/
├── data/
│ ├── backlog.md
│ ├── operator.md
│ ├── learnings.md
│ └── ...
├── projects/
└── state/
The important pieces are:
AGENTS.md- operating instructions for the supervising agentdata/operator.md- your standing constraints and preferencesdata/backlog.md- the supervisor's task queuedata/learnings.md- durable operational knowledge discovered by the fleetprojects/- registered project clonesstate/hand.db- authoritative machine state
You normally do not manage these by hand. The supervisor and hand own the workflow.
Every command resolves the fleet home from HAND_HOME when set, otherwise from the current directory or the nearest ancestor containing state/hand.db.
hand itself is a self-contained Go binary. Operating a fleet relies on a few external tools:
- herdr - interactive worker sessions and semantic agent state
- treehouse v2.1.0 or newer - isolated git worktree pools
- gh - GitHub pull-request and release operations
- at least one supported coding-agent harness
Optional:
sh- a POSIX-compatible shell, required when a non-emptyconfig/notifyis configured, including on Windows- no-mistakes - required only by projects using
no-mistakesmode - qmd - semantic search over historical fleet context beyond
hand search
hand init reports checked tools it cannot find on PATH. hand doctor checks the fleet home's generated agent instructions and related drift.
Building from source additionally requires Go 1.26.5 or newer.
Release tar archives are available for Linux and macOS on AMD64 and ARM64. A ZIP archive is available for Windows AMD64. Every release includes checksums.txt.
curl -fsSLO https://github.com/atqamz/hand/releases/latest/download/hand-linux-amd64.tar.gz
tar xzf hand-linux-amd64.tar.gz
install -m755 hand ~/.local/bin/handOn Windows, download hand-windows-amd64.zip, extract hand.exe, and place it on PATH.
See the releases page for every asset.
Edge is a rolling GitHub prerelease for maintainers and contributors who want the newest CI-verified main build.
It is intentionally mutable and may contain unreleased behavior or state/schema changes.
Stable users should continue using the normal release assets above.
Install the Linux AMD64 edge asset directly:
curl -fsSLO https://github.com/atqamz/hand/releases/download/edge/hand-linux-amd64.tar.gz
tar xzf hand-linux-amd64.tar.gz
install -m755 hand ~/.local/bin/handOpt into edge from an existing installation:
hand update --channel edgeCheck for an edge update without installing it:
hand update --check --channel edgeAfter an edge binary is installed, plain hand update continues tracking edge.
Switch back explicitly with hand update --channel stable.
That switch is a downgrade from unreleased development state, so it may not be runtime-compatible with every future migration performed while using edge.
Install into your profile:
nix profile install github:atqamz/handOr run it without installing:
nix shell github:atqamz/hand -c hand --versionThe flake covers aarch64-darwin, aarch64-linux, and x86_64-linux. On Intel macOS, use a release binary or go install.
go install github.com/atqamz/hand@latestgo install does not embed release-version metadata, so the binary reports dev and never checks for updates. Prefer a release binary or Nix installation for a versioned build.
To build a checkout for contributing to Secondhand itself, see CONTRIBUTING.md.
Configure notifications by writing a text file at config/notify.
The file contains a POSIX shell snippet, and the notification text is available as $HAND_MESSAGE.
For every supported operating system, the execution contract is:
config/notify -> POSIX sh -c
This applies on Linux, macOS, and Windows.
On Windows, Hand does not reinterpret the template as cmd.exe batch syntax, PowerShell, or WSL shell syntax, and it does not invoke wsl.exe automatically.
A POSIX-compatible sh executable must be directly resolvable from the Windows process's PATH.
Git for Windows and MSYS2 are examples of environments that may provide such an executable, but installing WSL alone does not satisfy this requirement.
Literal Windows paths are still part of POSIX shell source. For example, users should not assume this is safe template source:
C:\some\path\notifier.exe
Backslashes have meaning to POSIX shells, so quote or escape literal paths according to POSIX shell rules, or use a shell-compatible representation such as a forward-slash Windows path when supported. Hand does not rewrite paths or automatically escape arbitrary template source.
You normally let the supervising agent drive the CLI. The main lifecycle is:
| Command | Purpose |
|---|---|
hand init |
Create or refresh a fleet home. |
hand project add |
Register a repository with the fleet. |
hand project set-url <name> <repo-url> |
Recover a registered project after a repository rename or transfer while preserving its local identity and task history. |
hand spawn |
Dispatch a worker into an isolated worktree. |
hand reopen <id> |
Reopen a terminal Task by creating a new Attempt. |
hand status |
Read fleet or task state. |
hand reconcile [id] |
Reconcile one Task or the bounded fleet candidate set with observed external reality. |
hand watch |
Wait for actionable fleet events. |
hand send |
Steer a running worker. |
hand merge |
Merge completed work after authorization. |
hand deliver |
Mark work as handed off when landing is someone else's decision. |
hand teardown |
Clean up a completed task safely while preserving Task and Attempt history. |
Other commands cover session bootstrap, configuration, project sync and upstreams, holds, scout promotion, search, notifications, diagnostics, PR recording, and self-update.
Run hand --help for the authoritative command reference.
Running bare hand returns the resolved fleet home, worker configuration, and live fleet overview rather than a generic help screen.
Release installations can update themselves:
hand updateCheck without installing:
hand update --checkWithout --channel, the installed build determines the target channel.
| Installed build | hand update target |
|---|---|
| stable | stable |
| edge | edge |
| dev | stable |
Use --channel stable or --channel edge for an explicit target or channel switch.
The edge channel compares embedded commit identities, while stable compares release SemVer versions.
When run inside a fleet home, an update also refreshes the generated section of AGENTS.md without overwriting your own additions. Other commands check the installed build's channel for a newer build at most once a day and print a one-line notice when one is available.
Secondhand deliberately separates judgment from mechanics.
flowchart LR
user["You<br/>requests and irreversible decisions"] --> supervisor["Supervising agent<br/>planning and coordination"]
supervisor --> hand["hand<br/>lifecycle, state, isolation, supervision"]
hand --> shipTask["Task: ship"]
hand --> scoutTask["Task: scout"]
shipTask --> worker1["Worker"]
scoutTask --> worker2["Worker"]
worker1 --> tree1["treehouse worktree"]
worker2 --> tree3["treehouse worktree"]
tree1 --> pr1["PR / branch"]
tree3 --> report["Report"]
pr1 --> supervisor
pr2 --> supervisor
report --> supervisor
supervisor --> user
The supervisor owns planning and judgment. hand owns lifecycle, state, isolation, and supervision. Workers own individual tasks. You remain the authority for irreversible decisions.
For durable architectural rationale, see docs/adr/. Behavioral command contracts live with their implementation, help, and focused tests.
See CONTRIBUTING.md.
The short path is:
git clone https://github.com/atqamz/hand
cd hand
nix develop
make build
make lint
make testRun make e2e when changing CLI behavior. Secondhand uses conventional commits and release-please for versioning and changelogs.