Skip to content
overterm
Documentation

Worktrees and tasks

New Task makes a worktree, a branch and an agent in one step — and Overterm notices when the branch is merged.

A task in Overterm is a git worktree on its own branch with a tab in it, usually with an agent started. Making one by hand is four commands; here it is one sheet. The other half of the feature is the end: knowing which of your nine worktrees are finished with, and removing them without losing work.

New Task

⇧⌘N, or File ▸ New Task…, or the palette’s New Task….

The sheet asks three things:

  • Branch — the branch to work on. An existing branch is checked out as it is; a new one is created at the base below. The name is validated with git check-ref-format --branch, so an invalid name is refused before anything is created.
  • From — the base the new branch starts at. Prefilled from Settings (see below); empty means HEAD.
  • Start — Claude, Codex or Shell only, prefilled from Settings ▸ Agents.

Under the fields the sheet shows the exact path the worktree will take, so you see where it is going before you press Create.

Then:

⇧⌘N  →  branch, base, agent
        ↳ git worktree add (-b <branch> … <base>)
        ↳ a tab in the new worktree, named after the branch
        ↳ the agent typed into its shell

The tab’s name is the branch. The checkout it shows in the sidebar, the changes pane and the ± badge is the new worktree, because that is where its agent works.

Where the worktree goes

Settings ▸ Agents ▸ Worktrees go (agents.worktreeLocation):

Value Path Example
sibling (default) <repo>-wt-<branch> ~/code/app-wt-feat-auth
inside <repo>/.worktrees/<branch> ~/code/app/.worktrees/feat-auth

The branch name is slugged for the path: everything outside letters, digits, ., _ and - becomes a dash, runs of dashes collapse, and the result is lowercased. feat/Cosign signing becomes feat-cosign-signing.

With inside, Overterm adds .worktrees/ to the repository’s local exclude file (.git/info/exclude) the first time, under a comment naming itself. No tracked file is changed, and nothing is added to .gitignore.

Settings ▸ Agents ▸ New branches start from (agents.newTaskBase) prefills the From field. Left empty, the base is the main worktree’s branch.

Worktrees in the sidebar

⌘B opens the sidebar; the Worktrees section lives in Overgit. Each row shows the worktree’s name, a house glyph for the main checkout, and on a line beneath it what its tabs are doing — named and coloured when an agent in it is blocked (“Agent waiting · …”). On the right of the row:

  • a pin when the worktree is attached to the selected tab, or the agent’s own glyph when an agent is working there;
  • its branch’s pull request — the number in its state’s colour with a CI glyph — through your own gh;
  • a purple merge mark when the worktree is finished with, a folder-question glyph when its directory is gone, a lock when it is locked.

Clicking a row opens it. Right-clicking gives:

Attach to This Tab / Detach from This Tab · New Tab Here · New Claude Tab Here · New Codex Tab Here · Show Pull Request #N · Open #N on GitHub · Reveal in Finder · Copy Path · Remove Worktree… · Clean Up Merged Worktrees…

Attaching pins a checkout to a tab: the sidebar, the changes pane and the ± badge then follow that checkout rather than guessing from the tab’s agent or shell directory.

Merged-worktree detection

Overterm marks a worktree as finished with when any one of these is true of its branch:

  1. Its upstream is [gone] and every commit is pushed. This is GitHub’s delete-on-merge: the branch was pushed, then deleted on the remote. Overterm checks the tip really is on some remote ref — a gone branch carrying commits no remote has (work done after the merge) is never treated as merged on that alone.
  2. It has an upstream and its tip is reachable from the default branch — origin/HEAD, else the main worktree’s branch.
  3. gh reports a merged pull request whose head is exactly the branch’s tip. This is how a squash merge is recognised, where the branch’s commits never appear in main at all. A reused branch name with new work on it does not match, because the tip has moved.

A branch that was never pushed never counts, however reachable it looks: a brand-new task branch with no commits is reachable from main too.

A worktree whose folder was deleted by hand (git calls it prunable) is cleanable as well.

Clean Up Merged Worktrees

The Worktrees header shows a count — “Clean up 3 merged” — which runs Clean Up Merged Worktrees…. It is also in the File menu, the palette and a worktree row’s menu.

It runs git fetch --prune first (ssh in batch mode, so it never hangs on a passphrase prompt), then shows one sheet listing what goes and what stays. A worktree is kept, and the sheet says so, when:

  • a tab is working in it — a shell’s directory, or where its agent works;
  • it has uncommitted changes;
  • it is locked.

Removal is git worktree remove without --force, so git itself still refuses anything surprising. Deleting the branch is a tick box and uses git branch -D, because -d refuses a squash-merged branch — which is exactly the case this feature exists for.

The Worktrees reload button fetches too, so the marks are current without running the clean-up.

Pull requests

Everything GitHub goes through your own gh, already logged in. There is no token in Overterm and no GitHub app.

One gh pr list --state all per repository, cached for a minute and refreshed each minute while the app is active, feeds the worktree rows, the title-bar chip for the current branch, and Overgit’s Pull Requests section. View ▸ Pull Request opens the right-hand pane on the current branch’s PR: its checks, description, comments and review threads, with inline comments grouped into threads. A thread’s file:line opens in the editor, and you can comment and reply from the pane.

Without gh, or without a login, the pull request pane stays empty and nothing else changes. See Requirements.

Claude sessions

The sidebar’s Sessions panel lists every Claude conversation ever run in the repository’s worktrees — read from ~/.claude/projects — newest first, with the session’s own title. Clicking one selects the tab it is running in, or opens a new tab with claude --resume <id> in the directory it ran in. Only well-formed session ids are used, because the command is typed into a shell.