- Book: AI Agents Pocket Guide
- The series: Pocket Guides for Developers — 8 short books on agents, RAG, prompts, observability, events, databases and system design — the whole series
- My project: Hermes IDE | GitHub — an IDE for developers who ship with Claude Code and other AI coding tools
- Me: xgabriel.com | GitHub
You wrote refund() an hour ago. It's committed on feature/refund. You hand it to a subagent: "add tests for refund() in src/orders.js." The subagent comes back and tells you there is no refund() in that file.
It isn't wrong. In the checkout it was given, the function doesn't exist.
Claude Code lets a custom subagent run in its own git worktree with one frontmatter line, isolation: worktree. The subagent docs say that worktree is "branched by default from your default branch rather than the parent session's HEAD." The worktree docs are more precise: the default base is the repository's default branch on the remote, usually origin/main. Your feature branch isn't in it. Neither are commits on your local main that you haven't pushed.
The fix is one setting. Checking that you need it takes a few git commands. I haven't run this walkthrough myself: it's built from the current Claude Code and git docs, so if a step behaves differently on your version, the worktree docs are the source of truth.
Step 1: a feature branch the remote doesn't have
You need a repo with an origin remote. That part matters. When no remote is configured, or origin/HEAD isn't cached and can't be fetched, Claude Code falls back to your local HEAD. A throwaway repo with no remote won't reproduce the problem.
Take a small Node project ("type": "module" in package.json) whose main is pushed. Cut a branch and add a function:
// src/orders.js (added on feature/refund)
export function refund(order) {
if (order.status !== "paid") {
throw new Error("only paid orders can be refunded");
}
return { ...order, status: "refunded" };
}
git switch -c feature/refund
git add src/orders.js
git commit -m "Add refund() for paid orders"
Commit before you delegate. A new git worktree is checked out from a commit, so edits you haven't committed stay in your checkout whatever the base setting is.
While you're here, add .claude/worktrees/ to .gitignore. That's where Claude Code creates worktrees, and you don't want them showing up as untracked files in your main checkout.
Step 2: the subagent file
Project subagents live in .claude/agents/. Save this as .claude/agents/test-writer.md:
---
name: test-writer
description: Writes node:test tests for code named in the request
tools: Read, Write, Edit, Bash, Grep, Glob
isolation: worktree
---
First run `git log --oneline -3` and `git branch --show-current`
and include both outputs in your reply.
If the function you were asked to test does not exist in this
checkout, say so and stop without changing any file.
Otherwise write tests under test/ with node:test, run
`node --test`, and commit the tests on your current branch.
Reply with the branch name and the commit hash.
name and description are the two required fields. isolation: worktree is the line that matters here. Spell it exactly: the frontmatter reference says Claude Code ignores a field it doesn't recognize without reporting an error, so a typo gives you a subagent that quietly edits your main checkout.
Claude Code picks up edits to .claude/agents/ within seconds, except the first agent file in a new agents directory: restart Claude Code once to load it.
Start Claude Code on feature/refund and call the subagent by name so Claude doesn't pick a different one. You can type @agent-<name> by hand:
@agent-test-writer add tests for refund() in src/orders.js
The prompt above asks the subagent to print its own git log first. If its top commit is your pushed main tip and not "Add refund() for paid orders", you've reproduced it.
Step 3: check the base with git
The first run changes nothing, so it leaves no worktree behind, and the subagent's printed git log is the only record of where it started. Git tells you whether that record fits. The default base is origin/HEAD, so check whether your feature commit is in it:
git remote set-head origin --auto # cache origin/HEAD if missing
git rev-parse --abbrev-ref origin/HEAD
git merge-base --is-ancestor feature/refund origin/HEAD
echo $?
The second command names the branch a default worktree starts from, usually origin/main. Per the git-merge-base manual, --is-ancestor exits with status 0 if the first commit is an ancestor of the second, and 1 if it isn't. A 1 here means your feature tip isn't in the branch the subagent started from.
Compare hashes too. Run git log --oneline -1 origin/HEAD and put it next to the top line of the subagent's own git log. They should match.
One more detail: when the repository hasn't been fetched in the last 24 hours, Claude Code fetches the default branch before creating the worktree, capped at five seconds, and uses the cached ref if that fetch fails. So the base can be newer than the origin/main you last pulled.
Step 4: set worktree.baseRef to "head"
worktree.baseRef accepts two values:
-
"fresh"(the default): branch from the repository's default branch on the remote. -
"head": branch from your current localHEAD, carrying your unpushed commits and feature-branch state. It's the documented choice for "isolating subagents that need to operate on in-progress work."
You can't set it to a branch name. For a specific existing branch, create the worktree with git yourself.
Put it in .claude/settings.local.json to try it for yourself, or in the committed .claude/settings.json if your team wants every worktree to start from the current work:
{
"worktree": {
"baseRef": "head"
}
}
This setting covers every worktree Claude Code creates, so claude --worktree sessions branch from HEAD too. That's the trade-off. "fresh" is the better default for unrelated tasks that should start clean. "head" is for extending work that hasn't merged yet.
Start a new Claude Code session on feature/refund and send the same @agent-test-writer line. This time the subagent should find refund(), write tests and commit them on its own branch.
Step 5: the cleanup rule, then merge it back
Subagent worktrees follow two rules. A subagent that finishes without changes has its worktree removed right away. One with changes stays on disk; a periodic sweep tied to your cleanupPeriodDays setting removes it later, but skips any worktree that still holds changed or untracked files or unpushed commits.
So if the first run stopped without touching a file, as the prompt told it to, nothing is left behind, and git worktree list shows only your main checkout. If the second run committed tests, its worktree is still there. Find it:
git worktree list
Look for the row under .claude/worktrees/. The name in brackets at the end is the subagent's branch. Its naming scheme isn't documented, so read it from this output rather than guessing:
AGENT_BRANCH=<branch from git worktree list>
git merge-base --is-ancestor feature/refund "$AGENT_BRANCH"
echo $?
git log --oneline feature/refund.."$AGENT_BRANCH"
A 0 means your feature commit is in the subagent's branch. The log with two dots lists only the commits the subagent added on top of it.
Merge from your main checkout, still on feature/refund:
git merge --ff-only "$AGENT_BRANCH"
git worktree remove .claude/worktrees/<name>
git branch -d "$AGENT_BRANCH"
--ff-only works when feature/refund hasn't moved since the subagent started. If you committed in the meantime, use a plain git merge. Remove the worktree before deleting the branch, because git won't delete a branch that's checked out in a worktree.
If git worktree remove refuses because the worktree is locked, check who holds the lock. Claude Code holds a git worktree lock while the agent runs and releases it when the agent finishes, and the sweep also releases a lock left by a session whose process exited. If one is still in place, run git worktree unlock .claude/worktrees/<name> first. Don't reach for --force unless you've checked there's nothing in that folder you want.
The same rule, one level up, in Hermes
I build Hermes IDE, so weigh this section with that in mind. Hermes works at the task level rather than the subagent level: ⌘N (Ctrl+Shift+N on Windows and Linux) starts each task on its own hermes/<name> branch in its own worktree, with the task as the agent's first prompt. When the work is done, the Land action commits, opens a pull request or merges locally into the branch the task started from, and it can be undone.

The ⌘N New task sheet in Hermes 2.3.4: the task typed, chips for Claude Code, the orders-api project, a new hermes/ worktree, Accept edits, model and effort, and the "Hermes will run" preview of the claude command.
The two layers stack. If Claude Code runs inside a Hermes task and spawns your test-writer subagent, the same worktree.baseRef rule applies. The worktree docs say that inside a worktree, "head" resolves to that worktree's HEAD, not the main checkout's. With "head" set, the subagent branches from the hermes/<name> task branch. Any of three files works: your user-level ~/.claude/settings.json, a .claude/settings.json committed on the branch the task started from, or the main checkout's .claude/settings.local.json, which the settings docs say Claude Code reads even from inside a worktree on macOS and Linux. With the default, the subagent branches from the remote's default branch, same as before.
The Review Desk's Worktrees tab lists the task worktrees Hermes made, with branch, age and disk size, which helps when you're deciding what to merge and what to throw away.

The Review Desk's Worktrees tab: one Hermes worktree each for orders-api, web-app and orders-types under ~/code, with each worktree's hermes/ branch, task, age and disk size, and the free disk space.
Hermes is free, source-available under BSL 1.1, and runs on macOS, Windows and Linux. It isn't affiliated with Anthropic, OpenAI, Nous Research or any agent vendor. Download Hermes if you want to try the task-level version.
If this was useful
A subagent is only as useful as the context you hand it, and the checkout it starts from is part of that context. The AI Agents Pocket Guide covers the patterns around delegation, isolation and handing work between agents. It's one of 8 short books in the Pocket Guides for Developers series, covering agents, RAG, prompts, observability, events, databases and system design. If you run several agents on one repo, Hermes IDE is free to try, and the code is on GitHub.

Top comments (0)