Skip to Content
DocumentationConfiguration

Configuration

worktree stores config in local Git config under northguild.worktree.*.

Common Keys

  • defaultSourceBranch (example: origin/main) — see Default source branch
  • opener (editor, herdr or none, default editor)
  • codeEditor (example: code)
  • herdr.focus (true or false, default true)
  • herdr.agent (example: claude; the agent kind that starts in every new Herdr space. Unset means no agent, unless worktree branch or checkout is given a brief, which falls back to agent.command’s program)
  • agent.command (the command --agent runs to hand a brief to a coding agent, example: claude --bg)
  • postCreate (a command to run in each new worktree, example: pnpm install; unset means infer from the lockfile)
  • github.token (GitHub personal access token)
  • github.autoAssign (true or false, unset means you are asked, or assigned when non-interactive)
  • jira.host (Your Jira workspace URL, example: https://company.atlassian.net)
  • jira.email (Your Jira email address)
  • jira.apiToken (Jira API token)
  • branchPrefix.feature (example: feature/)
  • branchPrefix.bugfix (example: fix/)
  • branchPrefix.chore (example: chore/)

Default source branch

defaultSourceBranch answers two questions, and they are not the same one.

Where a new branch starts. worktree branch uses it when you pass no --source, and prompts if it is unset.

What counts as unpushed work. list, cleanup and remove compare each worktree against a base to decide how many commits it carries that nowhere else has. That base is origin/HEAD — the repository’s own record of its default branch — and defaultSourceBranch is the fallback when origin/HEAD is not set, which happens in clones made before git began recording it.

It is also the base a merged branch is recognised against. Where a worktree is ahead of it, the change it carries is compared with what that base already holds — so a squash-merged or rebased branch, whose commits survive under new identities, is seen for what it is rather than counted as work at risk. See cleanup for what that does and does not permit.

origin/HEAD is asked first deliberately. If the config key were read first, setting it to origin/develop because that is where you branch from would also change which commits count as unpushed, and a worktree could be classified as safe to delete on the strength of a preference about branching.

If neither resolves, no count is taken. Nothing is guessed and nothing is treated as zero, and a worktree whose directory still exists is never classified as safe to remove — an unanswered question is not an answer of “nothing”.

All three commands say so rather than leaving you to guess. list and remove’s picker name such a worktree as uncountable, and cleanup reports it under its own heading rather than sweeping it or passing over it in silence. To fix it, set the key or restore the ref:

worktree config defaultSourceBranch origin/main # or, to let git record it again: git remote set-head origin --auto

Editor Command

codeEditor is a command line, not just a program name. It is split on whitespace: the first word is the program to launch, and anything after it is passed to that program as arguments, ahead of the worktree path.

worktree config codeEditor code # runs: code <worktree-path> worktree config codeEditor "code -n" # runs: code -n <worktree-path>

The worktree path is always passed as a single argument, so a project or branch whose path contains a space opens correctly.

Quotes group, so an argument containing a space survives:

worktree config codeEditor 'open -a "Sublime Text"' # runs: open -a "Sublime Text" <worktree-path>

Quote characters are removed by the split and never reach the program. Nothing else is interpreted: no shell parses this value, so ~ and $EDITOR are passed through literally rather than expanded, and a backslash is an ordinary character rather than an escape. Quote an argument like this instead of writing an\ argument\ like\ this, and use an absolute path or a wrapper script on your PATH rather than relying on expansion.

Agent Command

agent.command is the command that --agent runs to hand a brief to a coding agent. It does not start an agent on its own: without a brief, only herdr.agent does. The agent that starts in every new Herdr space, brief or not, is herdr.agent. Like codeEditor it is a command line, not just a program name, and it is split the same way: the first word is the program to launch, and anything after it is passed to that program as leading arguments.

worktree config agent.command claude worktree config agent.command "claude --bg" worktree config agent.command "codex exec"

Only the first word is checked when you set the value, so flags and subcommands do not have to resolve to anything on their own:

worktree config agent.command "claude --bg" # accepted — only `claude` is looked up worktree config agent.command "nope --bg" # rejected — Command not found: nope

worktree does not assume a particular agent. There is no default value, and nothing about this key is specific to one vendor — any agent CLI of the same shape works. The same rules as Editor Command apply: no shell parses the value, quotes group an argument containing a space, and ~ and $VAR are not expanded.

The key is optional and unset by default.

When the worktree opens as a Herdr space, the agent is started by Herdr instead, and agent.command only supplies what to start: its program is the agent kind when a brief is given and herdr.agent is unset, and its arguments are reused when the program is that kind — without --bg or --background, which would take the agent out of the pane. For claude, --name <repo>-<branch> is added. See Agent Dispatch.

Post-create Command

postCreate is the command worktree branch runs in a new worktree to install its dependencies. It is a command line, split and validated exactly like agent.command: the first word is the program and has to be on PATH when you set it, quotes group an argument containing a space, and no shell parses the value.

worktree config postCreate "pnpm install" worktree config postCreate "make setup"

When it is set it is used as written, and it also turns the install on for a terminal run. When it is unset, branch infers the command from the new worktree’s lockfile (pnpm-lock.yaml, package-lock.json, yarn.lock, then bun.lock) and installs by default only when non-interactive. --no-install skips it for one run. See branch.

The key is optional and unset by default.

Platform Support

worktree is developed and tested on macOS and Linux. Windows is not supported. Nothing here is launched through a shell, so a .cmd or .bat shim — which is what code is on Windows — cannot be started, and Herdr is a unix-socket application.

Commands

worktree config --list worktree config --missing worktree config --missing --names defaultSourceBranch,github.token worktree config defaultSourceBranch origin/main worktree config codeEditor code worktree config opener herdr worktree config herdr.focus false worktree config herdr.agent claude worktree config agent.command "claude --bg" worktree config postCreate "pnpm install" worktree config github.token <token> worktree config jira.host https://company.atlassian.net worktree config jira.email your-email@example.com worktree config jira.apiToken <api-token> worktree config branchPrefix.feature feature/ worktree config branchPrefix.bugfix fix/ worktree config branchPrefix.chore chore/

Opener Notes

  • opener selects where a finished worktree is handed off: editor uses codeEditor, herdr opens it as a Herdr space — and closes that space again when the worktree is removed, and none opens nothing: the command prints Worktree created at <path> and stops. Unset means editor.
  • codeEditor is used only by the editor opener — see Editor Command above and the Editor Integration guide.
  • herdr.focus and herdr.agent apply only when opener is herdr. See Herdr Spaces.
  • herdr.focus and herdr.agent are shown by worktree config only when the herdr CLI is on your PATH. Without it they are neither listed nor prompted for, so the feature stays out of the way. This gating never hides a key that already holds a value, and setting opener to herdr un-hides both whether or not the CLI is found. opener itself is always shown. Naming a key with --names, or setting it directly, always works.

GitHub Integration Notes

  • worktree branch --github <issue-number> reads issues from the current repository remote.
  • Branch prefix keys are optional. If missing, worktree uses no prefix.
  • If github.token is missing, worktree can attempt to use gh auth token and then prompt.
  • github.autoAssign decides whether reading an issue also assigns it to you. It has three states, not two: true always assigns, false never does, and leaving it unset means you are asked, once, and your answer is saved to this key. A non-interactive run does not ask: it assigns and saves nothing. Assigning needs a token with push access to the repository.
  • worktree branch --assign and --no-assign override the key for a single run, whatever it holds. See branch.
  • If you answered no and want the offer back, set the key directly:
worktree config github.autoAssign true
  • github.token and github.autoAssign are prompted together, behind one confirm, so worktree config costs a single yes/no to anyone who does not use GitHub issues.

Jira Integration Notes

  • worktree branch --jira <issue-id> reads issues from your configured Jira workspace.
  • All three Jira config keys (jira.host, jira.email, jira.apiToken) are required.
  • Branch prefix keys are optional. If missing, worktree uses no prefix.
  • Issue IDs are case-insensitive (both dev-123 and DEV-123 work).
  1. Agree on one source branch (origin/main for most teams).
  2. Standardize branch naming conventions.
  3. Keep editor command consistent across local setups.
  4. For Jira integration, share workspace URL and branch prefix conventions.
Last updated on