Coding agents (wt)
If you drive Claude Code from a nebelhaus
machine, the rice hands you a small tool called wt — it makes running
several agents at once safe, and makes closing a pane something you never have
to think about. It works on any git repo, not just nebelhaus, and you get it
for free the moment the rice is on your PATH.
The problem it solves
Section titled “The problem it solves”Run two Claude agents in the same checkout and they fight: one switches the
branch out from under the other, uncommitted edits collide, and closing a pane
mid-thought can lose work. wt fixes both by giving every agent its own
checkout.
Press Super c (⌘C) in any repo’s terminal tab and the rice spawns a fresh
Claude Code session in an isolated git worktree:
- its own checkout on a
worktree-<name>branch, branched from the repo’s localHEAD; - living outside the repo, under
~/.cache/claude-worktrees/<repo>/<name>, so your working tree stays clean and no build tool ever trips over it; - so any number of agents can hack in parallel without ever touching each other’s branch — or yours.
Super ⇧c (⌘⇧C) spawns exactly the same isolated agent, but in place of
the focused pane instead of splitting a new one beside it — for when the tab is
already as subdivided as you want it and the pane you’re looking at has done its
job. The pane it replaces is only suspended, never killed: quit the agent and
your shell comes back, focused, scrollback intact.
Ctrl Alt Shift c is the resident variant: the one agent per tab that’s allowed
to edit the checkout you’re actually looking at.
Prefer the launcher? Spawn Agent in Pounce (⌘Space, type “spawn”) does the
same thing from the GUI, for whichever client you’ve made the
default: pick a repo, type
what you want done, and
it creates a worktree named after the task — not the random
luminous-twirling-codd an unattended agent would coin — and drops a session
into that repo’s tab. Naming the branch from the prompt is the whole point; the
palette is just the shortest path to it.
Resuming a session
Section titled “Resuming a session”Because the work lives on the branch (and the chat in your client’s transcript),
a closed pane is never a dead end. Run wt bare to see everything you can pick
back up, across every repo:
wt # list every parked / live agent worktree, all repos🌫 agent worktrees you can resume (wt <name>, or <repo>/<name>) repo name state agent last commit nebelung sparkle parked claude 2 hours ago — wip: auto-saved on pane close pounce quick-emoji live codex 10 min ago — add fuzzy weightsTo pick one back up, name it — wt rebuilds the checkout and reopens the chat
in the same directory, so that worktree’s client resumes with its full history:
wt sparkle # rebuild the checkout + reopen the chat (that worktree's client)wt nebelung/sparkle # qualify with the repo when a name exists in two reposSpawn from Pounce — and choose the default client
Section titled “Spawn from Pounce — and choose the default client”For a named worktree without first finding the right terminal tab, summon Pounce
and run Spawn Agent. Pick a repository, describe the task, and it creates a
worktree-<task-name> checkout before opening the configured client in that
repo’s zellij tab.
Set the client declaratively:
nebelhaus.agents.default = "codex"; # or "claude" (default), or "opencode"wt records that client with the worktree. Changing the option therefore only
changes new spawns: a parked Codex task still reopens through codex resume,
and an OpenCode task through opencode --continue.
The option drives the ⌘C keybinds and the c shell alias too. Only Claude Code
can make its own worktree (its native --worktree flag, which fires wt’s
create hook); for Codex and OpenCode, ⌘C runs wt new instead — the same
checkout, branch, registry entry and parent session, made from the outside.
A separate option says which clients are installed:
nebelhaus.agents.clients = [ "claude" "opencode" ]; # the defaultagents.default must be one of them, and the rebuild says so by name if it
isn’t — which is the point: naming a client you didn’t have used to fail at
spawn time, inside the pane, after the worktree already existed. Pounce’s
Spawn Agent still checks command -v before it creates anything, for the case
the assertion can’t cover (a hand-managed install that moved).
There is also Spawn Agent with Screenshot. It uses macOS’s normal area
selector (screencapture -i) before the repository/prompt flow, then keeps the
PNG under ~/.cache/nebelhaus-agent-screenshots/ for the agent. Codex receives
it as an initial image; Claude and OpenCode receive its file path in the first
prompt so they can inspect it. Keeping it as a separate palette entry matters:
a task whose text happens to contain “screenshot” can never steal Return in the
free-text prompt field.
Cross-repo work: wt child
Section titled “Cross-repo work: wt child”Sometimes an agent working in one repo needs to change another one — say a
session in the workshop that has to touch a sub-repo. Don’t reach for a raw
git worktree add: that skips wt’s registry, so the statusline never learns to
track it and its PR goes invisible. Use wt child instead:
workshop_root="$(dirname "$(git rev-parse --path-format=absolute --git-common-dir)")"cd "$(wt child "$workshop_root/nebelung")"That creates a worktree of the other repo, registers it as a child of your
current pane (so its PR shows up in the statusline where you’re working), and
prints only the new checkout path — hence the cd "$(…)". Resolving the
workshop root through Git keeps the command independent of where you cloned it.
Cleaning up
Section titled “Cleaning up”Most cleanup is automatic: closing a pane reaps a merged branch, and every wt
listing first self-heals by sweeping parked branches whose PR has since merged.
But some things end a pane without the graceful hook — a reboot, a crash, or a
wt child checkout (which the hook never owns, since the pane that made it isn’t
the one it belongs to). For those, sweep on demand:
wt reap # reap every LANDED worktree now — parked ones, plus # clean & merged live checkouts no pane is open inwt reap is deliberately conservative: it leaves anything dirty, anything
unmerged, and any checkout a pane is still open in — not only yours but
any other session’s, because a just-merged branch looks exactly like a finished
one while its agent is still sitting in it. Only landed work that nobody is
standing in gets removed.
Setting work aside: wt park, never git stash
Section titled “Setting work aside: wt park, never git stash”git stash looks like it belongs to the checkout you’re standing in. It doesn’t.
The stash stack lives in the repo’s shared .git dir, so every agent worktree
of a repo — and the main checkout — push and pop the same stack. Two panes
stashing at once means either can pop the other’s entry into a tree that never
asked for it, which is a confusing mess at best and lost edits at worst.
So park instead of stashing:
wt park "half-done refactor" # whole dirty tree → one wip: commit on THIS branchwt unpark # rewind it — changes back, uncommittedwt park commits everything — tracked edits, untracked files, deletions — as a
single wip: commit on the branch only this pane has checked out. It’s the same
thing the pane-close hook does automatically, just on demand. Nothing is shared,
so no other agent can touch it; it survives a pane close; and wt lists it as
that worktree’s last commit. wt unpark puts the changes back in the working
tree, uncommitted, exactly as they were.
Which tab wants you
Section titled “Which tab wants you”Run agents in eight tabs and the question is always the same one: which of them is sitting on a permission prompt? The rice answers it in the tab bar itself — a filled badge beside the name of any tab holding agent panes. The badge carries a count — how many agents live in that tab — on a background coloured by what the most urgent one is doing:
| Badge | Means |
|---|---|
| peach | an agent is blocked on you — a permission prompt, or it’s asking a question |
| sky | an agent is mid-turn, working |
| green | the agent finished its turn; nothing is waiting |
| (no badge) | no agent panes in that tab |
The number is the exact count of agent panes in the tab; the colour is the most urgent state among them, so peach always wins: the tab that needs you never hides behind a tab that’s merely busy. And it’s status, not a notification — a green badge stays green until that agent starts another turn or its pane goes away. Looking at it doesn’t dismiss it.
This is the same signal as the agents bar pill, reported by
the client’s own lifecycle hooks (which is why it’s exact rather than guessed —
the agent says what it’s doing, nothing scrapes the screen for it). The pill is
for when you’re out in the GUI; the badge is for when you’re already in the
terminal. It lights up as soon as an agent pane reports, and stays invisible if
you never run one.
Every client reports through one command, agent-state <working|waiting|idle| remove> <client>, which the rice puts on your PATH:
| Client | Wiring | Who writes it |
|---|---|---|
| OpenCode | ~/.config/opencode/plugin/nebelhaus-agent-state.js | the rice, for you |
| Codex | UserPromptSubmit / PermissionRequest / Stop in ~/.codex/hooks.json | the rice, for you — Codex then asks you to review and trust those hooks the first time it starts, which the rice deliberately doesn’t bypass |
| Claude Code | UserPromptSubmit / Notification / Stop / SessionEnd hooks in ~/.claude/settings.json | you — Claude owns that file and rewrites it, so the rice never touches your hooks |
A pane’s row also disappears on its own once the pane is gone, whether or not its client said goodbye. That matters most for Codex, whose hooks have no session-end event at all — but it’s the same thing that clears the row of a Claude agent you killed, or one that crashed.
The statusline HUD
Section titled “The statusline HUD”The rice points Claude Code’s status bar at a small HUD driven off wt’s
registry, so you can see where every agent stands without leaving the pane.
Row one is this session’s own worktree — its name, a status token, and its
GitHub PR pill. The rows below are the worktrees this session spawned (across
whatever repos they live in), each with its repo, name, token, and PR state. The
cross-repo GitHub lookups run detached and cached, so the bar never stalls your
prompt.
The token is one mutually-exclusive slot:
| Token | Means |
|---|---|
⏏ | branch is merged into main — closing the pane reaps the worktree |
N^ | N commits on the branch, not merged yet |
+A -D | uncommitted line changes, when nothing’s committed yet |
| (nothing) | identical to main — no news is good news |
Links — every URL a pane’s session saw
Section titled “Links — every URL a pane’s session saw”The same statusline pass that drives the HUD also notes which Claude transcript each pane is running, and Pounce turns that into a command. Press ⌘L in the terminal (or summon the palette with ⌘Space and run Links) to get every URL from the focused pane’s whole Claude Code session — newest first, including links buried in collapsed tool output or that scrolled away hours ago. ⏎ opens the pick in your browser.
GitHub PR and issue links come back enriched with their real title and
open/closed/merged state — a parallel, cached gh fetch capped at ~2s, so a slow
network degrades to plain links rather than a hung palette. A pane not running
Claude Code falls back to its visible scrollback.
Command summary
Section titled “Command summary”| Command | What it does |
|---|---|
wt | List every parked/live agent worktree across all repos (self-heals first) |
wt <name> | Resume one: rebuild its checkout and reopen its recorded agent chat |
wt resume <name> | The same thing, spelled out |
wt reap | Sweep every landed worktree now (keeps dirty/unmerged/any open pane) |
wt child <repo> | Make a worktree of another repo as a child of this pane (cross-repo) |
wt park [label] | Set the dirty tree aside as a wip: commit on this branch (use instead of git stash) |
wt unpark | Undo the last wip: commit — changes back in the working tree, uncommitted |
wt new [name] | Make a worktree of this repo and open the default client in it — what Super c runs when that client isn’t Claude Code |
wt create / wt remove | The hooks Claude Code’s --worktree fires — you don’t call these by hand |
wt agent default | Print the configured spawn client |
Hacking on nebelhaus itself? The Contributing page
shows how agent worktrees plug into the family’s bench try / PR / ship flow.