Help us shape the future of Go! Take the 2026 Go Developer Survey

holt

module
v0.5.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 27, 2026 License: Apache-2.0

README ΒΆ

🦦 holt

the worktree-lifecycle substrate for parallel coding agents

never loses work Β· never reaps what's in use Β· the registry, not the filesystem, is truth


Every vendor ships worktree creation now β€” claude --worktree, the Claude Agent SDK's isolation: worktree, Cursor, Copilot CLI β€” and every one of them stops there. Nobody owns the rest of the life: the branch still alive after the pane died, the checkout nobody is sitting in, the tree with 40 uncommitted minutes in it, the branch whose PR merged yesterday and has kept committing since.

If you've ever git worktree list'd through a graveyard trying to remember which of those you can safely delete β€” that's the problem holt makes go away.

install

nix run github:hausfold/holt                            # try it
nix profile install github:hausfold/holt                # keep it
go install github.com/hausfold/holt/cmd/holt@latest     # or, with Go 1.23+

Needs git. gh and lsof are optional and make it sharper β€” gh proves a branch landed, lsof proves nobody's standing in a checkout; without them holt degrades toward keep, never toward delete. On haus it's already on PATH, wired to βŒ˜β†΅.

a lane

One agent's branch, checkout and pane, from create to reaped. Not a "worktree" β€” a parked lane has no checkout on disk, only a branch. Not a "session" β€” that's your multiplexer's word.

cd "$(holt new fix-flaky-test)"  # a lane on this repo: new checkout, new branch, path on stdout
holt new fix --open        # …or hand the pane straight to your agent (--open codex, --cmd 'nvim')
holt                       # every lane you've got going, live or parked, across every repo
holt fix-flaky-test        # back later β€” rebuild the checkout, reopen the agent, where you left off
holt reap                  # sweep every lane whose branch landed and nobody's standing in
cd "$(holt child ../api)"  # a lane on a DIFFERENT repo β€” never a raw `git worktree add`

And never git stash again. The stash stack lives in the shared .git dir, so every worktree of a repo and the main checkout push and pop the same one β€” parallel agents routinely pop each other's work into a tree that never asked for it. holt park commits your dirty tree as a single wip: commit on the branch only this pane has checked out; holt unpark puts it back.

holt park "mid-refactor on the retry logic"
holt unpark

the promise

Not "makes worktrees" β€” every vendor does that. holt's product is the state machine and three invariants, in this priority order:

  1. Never lose work. Every destructive path parks first. The failure direction is always a branch lingers, never a tree vanished.
  2. Never reap what's in use. Occupied, dirty, or not provably landed β‡’ keep. Uncertainty resolves to keep β€” including when GitHub is unreachable.
  3. The registry is truth. Not the filesystem, not git worktree list β€” those are derived, and they lie.

So a command exiting 2 β€” refused for safety is holt working, not holt failing. Don't reach for git worktree remove; ask it why.

the verbs

holt list every live/parked lane, across all repos Β· --json for machines
holt <name> resume one β€” rebuild its checkout, reopen its agent
holt focus <name> go to the window a lane is already running in β€” [hooks] focus, resume without one
holt new [name] a lane on this repo β€” prints its path Β· --open [agent] / --cmd '…' to run something in it
… --prompt '<task>' open it on a first turn instead of a blank pane Β· --prompt-file <file|-> for a brief Β· --image <file>
holt child <repo> a lane on another repo, as a child of this pane
holt spawn <repo> <name> a named lane, for a spawner with no pane of its own β€” --prompt/--prompt-file opens it through [hooks] open
namer = "claude" opt-in: a lane opened on a task and given no name takes its name FROM that task β€” hud-draft-color, not cozy-otter. One config line; holt runs the client already on PATH, never a model of its own
holt park [label] / unpark set the tree aside as a wip: commit, and put it back
holt reap sweep every landed, unoccupied lane
holt reaped what went, why, and the SHA to get it back
holt drop <name> retire a lane that will never land β€” recorded, undoable
holt reship [name] push a branch that outran its merged PR, open the follow-up
holt heartbeat [path] hold the occupancy lease, so reap spares this lane
holt watch --json lifecycle events on stdout, one NDJSON object per line
holt runtime up|enter|down <name> hand a lane to an isolation backend, and take it back Β· --backend <id> every time, never automatic Β· tart is built in β€” a headless macOS per lane, so an agent can drive a desktop without taking yours
holt runtime eject tart print the built-in backend as an adapter file, to edit and override it with
holt hook create / remove client-hook entry points (this is what claude --worktree calls)
holt hook notify client events β†’ a trill banner for the lane: Notification hangs an ask on the ledge when a lane blocks on its user, Stop replaces it with a done when the turn finishes, and UserPromptSubmit / PostToolUse take an answered ask back down β€” the session moved again, so the question did too Β· every banner is keyed by lane, so one lane never hangs two Β· clicking it runs holt focus on that lane Β· exit 0 always, silent no-op without trill

holt --help is exhaustive. Config, exit codes, and the --json lane payload are in docs/reference.md.

SDKs

Five clients over the same CLI, sharing one version number β€” list, watch as a native async stream, child/spawn, park/unpark/reap/reship, and occupancy leases.

TypeScript bun add @hausfold/holt sdk/ts
Python uv add hausfold-holt sdk/python
Rust cargo add hausfold-holt sdk/rust
Go go get github.com/hausfold/holt/sdk/go sdk/go
Swift hausfold/holt-swift sdk/swift

⚠️ Go: the module path moved on 2026-08-16. v0.2.8 and earlier stay resolvable on Go's immutable proxy under the previous owner forever; everything since is at github.com/hausfold/holt/sdk/go, so an existing importer edits its import line. Β· Swift ships from a generated mirror β€” send changes to sdk/swift here, never to the mirror.

more

  • Lifecycle β€” states, landing rules, occupancy, and how to disagree with holt
  • Reference β€” config, exit codes, the --json payload, building from source
  • ai/SKILL.md β€” the agent-facing surface: drop it in and your agent drives holt correctly first try
  • ai/handoff/SKILL.md β€” the companion skill: write a brief a cold session can act on, and holt spawn --prompt-file it into its own lane
  • SPEC.md β€” the design of record, and the contracts that are frozen
  • Releasing β€” how the CLI and all five SDKs are cut from one number

pre-1.0 Β· Nothing here takes something it can't give back β€” a dirty tree is parked as a commit, and only merged, unoccupied lanes are ever reaped. That's the intent, not a warranty: keep a backup, and tell us what breaks.

Apache-2.0 Β· one of the hausfold repos β€” haus rebuilds the Mac, this is what its agent panes stand on

βŒ‚ hausfold

Directories ΒΆ

Path Synopsis
cmd
scruff command
Command scruff manages LANES β€” one coding agent's branch, checkout and pane β€” for any git repo.
Command scruff manages LANES β€” one coding agent's branch, checkout and pane β€” for any git repo.
internal
compat
Package compat carries holt's old name through the rename to scruff.
Package compat carries holt's old name through the rename to scruff.
config
Package config is holt's machine-wide configuration and, through it, holt's policy seams.
Package config is holt's machine-wide configuration and, through it, holt's policy seams.
exitcode
Package exitcode defines holt's public exit-code contract (SPEC.md Β§2.4).
Package exitcode defines holt's public exit-code contract (SPEC.md Β§2.4).
gitx
Package gitx is holt's git layer: subprocess calls to the real `git`, never a reimplementation of it.
Package gitx is holt's git layer: subprocess calls to the real `git`, never a reimplementation of it.
occupancy
Package occupancy answers the one question the reap is forbidden to guess at: is somebody standing in this checkout?
Package occupancy answers the one question the reap is forbidden to guess at: is somebody standing in this checkout?
registry
Package registry is holt's source of truth.
Package registry is holt's source of truth.
ui
Package ui is holt's only writer of human-facing text.
Package ui is holt's only writer of human-facing text.
sdk
go module

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL