Skip to content

Open a git worktree as a Herdr space

By default a new worktree opens in your editor. If you work in Herdr, a terminal workspace manager, you can have it land as a Herdr space instead — labelled by branch, optionally with an agent already running in it.

The worktree itself is created exactly as before. Only the final step changes.

  • The herdr CLI on your PATH.
  • A running Herdr server.

Without the herdr CLI, worktree config neither lists nor prompts for any of the keys below, and its opener question does not offer herdr — the feature is invisible until Herdr is installed. You can still set one explicitly by name, which is what to do if you are configuring a machine ahead of installing Herdr:

Terminal window
worktree config opener herdr # works whether or not herdr is installed yet
worktree config --missing --names opener # prompts for it regardless
Terminal window
worktree config opener herdr

opener accepts editor, herdr, rex, auto or none. Unset means editor, so nothing changes for anyone who does not set it.

auto opens the worktree where the command runs: as a Herdr space when the shell is inside a Herdr pane and the herdr CLI is installed, as a Rex session when it is inside Rex and rex is installed, otherwise in your editor. A tool whose CLI is not found is skipped, not an error. If the shell is inside both, Herdr wins: Herdr can run inside Rex but Rex does not run inside Herdr, so Herdr is the inner one. A fixed opener overrides it. A shell started in a Herdr pane keeps its HERDR_* variables after Herdr quits, so auto can pick a Herdr that is no longer running: the open then fails with a warning and the worktree path, as it would for opener herdr. Set opener to a fixed value to avoid that.

The key is stored in local Git config under northguild.worktree.opener, so it applies to one repository. Set it again in each repository you want it in.

Now worktree branch, worktree checkout and worktree open all hand the finished worktree to Herdr:

Terminal window
worktree branch feature/add-bulk-actions

The space is labelled with the branch name — feature/add-bulk-actions, not the repository name — so several worktrees of the same repository stay distinguishable in the sidebar.

Re-opening a worktree that already has a space reuses it rather than creating a second one, and switches to it unless you have turned focus off below.

When the worktree is removed, its space is closed again — see When the worktree goes.

The space comes to the front by default, because every command that opens a worktree is you asking to be taken to it. To leave it in the background:

Terminal window
worktree config herdr.focus false

Optional, and off unless you set it (or give worktree branch a brief, below). worktree config offers it when you set up the coding agent: once opener is herdr and you have given agent.command, it asks “Start it in every new Herdr space, even without --agent?”. Yes sets herdr.agent to the command’s first word, unless herdr.agent already has a value, which it keeps; no leaves it empty. A first word that is not a valid kind, such as a path, is not stored: the wizard says so instead of asking. To choose the kind yourself:

Terminal window
worktree config herdr.agent claude

The value is the agent kind Herdr should start — claude, codex, gemini and so on. Run herdr agent start --help for the kinds your Herdr accepts; worktree does not keep its own list, so a kind added by a Herdr release works immediately, and an unknown one is rejected by Herdr with its own message.

The agent starts only for a space this command just opened. Re-opening a worktree does not start a second agent, because the one you left running is still in that pane.

Herdr’s name for the agent is derived from the branch and coerced to what Herdr accepts, which includes a 32-character cap. A new pane’s shell can still be starting when the space opens, and Herdr refuses an agent until the shell reaches its prompt (agent_pane_busy). That refusal is retried for up to about two seconds before it counts as a failure. If the start fails — most often a name already taken by a live agent from another repository, or a pane still busy after those retries — you get a warning, and the space is still open and correct.

This is the agent for the worktree: worktree branch --agent "<prompt>" does not start a second one beside it. Whenever Herdr starts an agent:

  • agent.command’s arguments are passed to it when it names the same program, with --bg and --background dropped, because the agent runs in the pane.
  • For claude, --name <repo>-<branch> is added, lowercased and never shortened, and printed on stderr.

With a brief (--agent, --agent-file or --agent-stdin):

  • The kind is herdr.agent, or else the program agent.command names, so you can leave herdr.agent unset. With a brief and neither, worktree branch exits 2 before it creates anything and names the key to set. Without a brief, only herdr.agent starts an agent.
  • The brief is submitted with herdr agent prompt once the agent is ready, never as part of herdr agent start.

--no-agent opens the space without an agent, and --no-open skips Herdr for the run.

worktree remove and worktree cleanup delete a checkout. With opener herdr they also close the Herdr space that was built around it, so a space does not outlive the worktree it belongs to. With opener auto, both commands ask every installed tool and close the space wherever it is held, whatever terminal they run from.

Terminal window
worktree remove feature/add-bulk-actions
✔ Worktree feature/add-bulk-actions was removed.
✔ Closed Herdr space feature/add-bulk-actions

Only worktrees that were actually removed. A branch that was not found, a confirmation you declined, a removal that failed, any worktree cleanup held back — for uncommitted changes, a live agent, or unpushed commits it could not count — none of those close anything. Their checkouts are still on disk, and a space with no window into a checkout that still exists is worse than one left open.

Only this repository’s spaces. The lookup is scoped to the repository you are in, and the space your own checkout is open in — the window you are sitting in — is never one of the candidates.

A worktree with no space open is not an error and prints nothing. Neither is a repository you have never opened in Herdr.

worktree cleanup --ignore-agents is sharper than it was. The flag looks up the agent sessions but does not let them hold anything back, so a stale worktree an agent is living in is removed unless something else holds it, such as uncommitted changes — and closing its space now takes down the panes that agent is working in. cleanup names each such worktree under Removing <n> worktree branch(es) despite a live agent session: before it asks, and under --force, but it does not stop, and what it removes now includes those panes. Without the flag, an agent that is working holds its worktree back, and its space with it. One that is only idle does not.

worktree rename moves a worktree’s directory and renames its branch. With opener herdr, or opener auto with Herdr installed, the space follows: Herdr lists a worktree’s space from git’s worktrees, so it is found at the new path with the same id and panes, and worktree relabels it to the new name with herdr workspace rename.

✔ Renamed Herdr space feature/x to bugfix/y

The space is looked up before the directory moves and relabelled only once both the move and the branch rename have succeeded. A worktree with no space open prints nothing. If Herdr cannot be reached or refuses the label, that is a warning and the command still exits 0. rename --json lists the id under herdrSpacesRenamed.

The agent Herdr started in the space keeps the name it was given, and so does a Claude --name session: both are set when the agent starts and keep the old branch name.

Every call to Herdr is bounded, so a Herdr that accepts the connection and then never answers fails with a line saying so rather than hanging the command. Ten seconds for an open, a lookup or a close; longer for starting an agent, because Herdr itself holds that request open while the agent boots.

If herdr is not installed, the server is not running, or the open fails, worktree prints what Herdr said and where the worktree is:

✖ Herdr: `herdr` was not found on your PATH.
The worktree is at /path/to/repo.worktrees/feature/add-bulk-actions

A call that times out reads the same way, naming the command and how long it waited:

✖ Herdr: `herdr worktree open --path /path/to/repo.worktrees/feature/add-bulk-actions --cwd /path/to/repo --label feature/add-bulk-actions --focus` did not answer within 10s.

It does not fall back to your editor. Setting opener herdr is a deliberate choice, and an unexpected editor window is not a useful consolation prize.

The command still exits 0. By the time the opener runs, the branch, the worktree and the copied env files all exist — the only thing that failed is the last step. The exception is a run given a brief (--agent): if no agent ends up with it, the run exits 1, because the agent working on it was part of what was asked for.

A failed close is a warning and nothing more — including a timeout, which is a warning here rather than the error it would be on the way in:

⚠ Herdr: workspace wQ not found (workspace_not_found)
⚠ Herdr: `herdr workspace close wQ` did not answer within 10s.

The command still exits 0, but for a different reason than above, and the difference is worth knowing. At open time the last step failed and everything before it succeeded. At close time the worktree is already deleted, the branch is gone and git no longer records the worktree — so there is nothing to retry and nothing to undo. A non-zero exit would claim the removal did not happen when it did.

What is left behind is a space with no checkout under it, which you can close from Herdr’s own sidebar. Each space is closed independently, so one failure does not take the rest of a worktree cleanup with it. If the lookup itself fails, you get one warning and no spaces are closed — the removals still happen.

Key Values Default
opener editor, herdr, rex, auto or none editor
herdr.focus true or false true
herdr.agent an agent kind, such as claude unset — no agent