{"slug": "your-claude-code-worktree-subagent-can-t-see-your-feature-branch-set-baseref-to", "title": "Your Claude Code Worktree Subagent Can't See Your Feature Branch. Set baseRef to head", "summary": "A developer documented that Claude Code subagents configured with `isolation: worktree` branch from the repository's remote default branch (usually `origin/main`) rather than the parent session's HEAD, so a subagent asked to test a function on a local feature branch reports the function doesn't exist. The fix is setting `baseRef` to `head` in the subagent's frontmatter, after committing work and adding `.claude/worktrees/` to `.gitignore`; the walkthrough is assembled from Claude Code and git documentation rather than hands-on testing.", "body_md": "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.\n\nIt isn't wrong. In the checkout it was given, the function doesn't exist.\n\n[Claude Code](https://code.claude.com/docs/en/sub-agents) 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](https://code.claude.com/docs/en/worktrees) 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.\n\nThe 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](https://code.claude.com/docs/en/worktrees) are the source of truth.\n\nYou 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.\n\nTake a small Node project (`\"type\": \"module\"` in `package.json`) whose `main` is pushed. Cut a branch and add a function:\n\n```\n// src/orders.js (added on feature/refund)\nexport function refund(order) {\n  if (order.status !== \"paid\") {\n    throw new Error(\"only paid orders can be refunded\");\n  }\n  return { ...order, status: \"refunded\" };\n}\ngit switch -c feature/refund\ngit add src/orders.js\ngit commit -m \"Add refund() for paid orders\"\n```\n\nCommit before you delegate. A new [git worktree](https://git-scm.com/docs/git-worktree) is checked out from a commit, so edits you haven't committed stay in your checkout whatever the base setting is.\n\nWhile 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.\n\nProject subagents live in `.claude/agents/`. Save this as `.claude/agents/test-writer.md`:\n\n```\n---\nname: test-writer\ndescription: Writes node:test tests for code named in the request\ntools: Read, Write, Edit, Bash, Grep, Glob\nisolation: worktree\n---\n\nFirst run `git log --oneline -3` and `git branch --show-current`\nand include both outputs in your reply.\n\nIf the function you were asked to test does not exist in this\ncheckout, say so and stop without changing any file.\n\nOtherwise write tests under test/ with node:test, run\n`node --test`, and commit the tests on your current branch.\nReply with the branch name and the commit hash.\n```\n\n`name` and `description` are the two required fields. `isolation: worktree` is the line that matters here. Spell it exactly: the [frontmatter reference](https://code.claude.com/docs/en/sub-agents) 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.\n\nClaude 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.\n\nStart 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:\n\n```\n@agent-test-writer add tests for refund() in src/orders.js\n```\n\nThe 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.\n\nThe 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:\n\n```\ngit remote set-head origin --auto   # cache origin/HEAD if missing\ngit rev-parse --abbrev-ref origin/HEAD\ngit merge-base --is-ancestor feature/refund origin/HEAD\necho $?\n```\n\nThe second command names the branch a default worktree starts from, usually `origin/main`. Per the [git-merge-base manual](https://git-scm.com/docs/git-merge-base), `--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.\n\nCompare 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.\n\nOne 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.\n\n`worktree.baseRef` accepts [two values](https://code.claude.com/docs/en/worktrees#choose-the-base-branch):\n\n`\"fresh\"` (the default): branch from the repository's default branch on the remote.`\"head\"`: branch from your current local `HEAD`, carrying your unpushed commits and feature-branch state. It's the documented choice for \"isolating subagents that need to operate on in-progress work.\"\nYou can't set it to a branch name. For a specific existing branch, create the worktree with git yourself.\n\nPut 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:\n\n```\n{\n  \"worktree\": {\n    \"baseRef\": \"head\"\n  }\n}\n```\n\nThis 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.\n\nStart 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.\n\nSubagent 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.\n\nSo 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:\n\n```\ngit worktree list\n```\n\nLook 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:\n\n```\nAGENT_BRANCH=<branch from git worktree list>\ngit merge-base --is-ancestor feature/refund \"$AGENT_BRANCH\"\necho $?\ngit log --oneline feature/refund..\"$AGENT_BRANCH\"\n```\n\nA `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.\n\nMerge from your main checkout, still on `feature/refund`:\n\n```\ngit merge --ff-only \"$AGENT_BRANCH\"\ngit worktree remove .claude/worktrees/<name>\ngit branch -d \"$AGENT_BRANCH\"\n```\n\n`--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.\n\nIf `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.\n\nI 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.\n\n*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.*\n\nThe 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](https://code.claude.com/docs/en/settings) 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.\n\nThe 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.\n\n*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.*\n\nHermes 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](https://hermes-ide.com/download) if you want to try the task-level version.\n\nA 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](https://www.amazon.com/dp/B0GYLH38X4), covering agents, RAG, prompts, observability, events, databases and system design. If you run several agents on one repo, [Hermes IDE](https://hermes-ide.com/download) is free to try, and the code is on [GitHub](https://github.com/hermes-hq/hermes-ide).", "url": "https://wpnews.pro/news/your-claude-code-worktree-subagent-can-t-see-your-feature-branch-set-baseref-to", "canonical_source": "https://dev.to/gabrielanhaia/your-claude-code-worktree-subagent-cant-see-your-feature-branch-set-baseref-to-head-4ljn", "published_at": "2026-10-24 15:02:38+00:00", "updated_at": "2026-10-24 15:12:35.107638+00:00", "lang": "en", "topics": ["ai-agents", "ai-tools", "developer-tools"], "entities": ["Claude Code", "Anthropic", "Git"], "also_reported_by": [], "alternates": {"html": "https://wpnews.pro/news/your-claude-code-worktree-subagent-can-t-see-your-feature-branch-set-baseref-to", "markdown": "https://wpnews.pro/news/your-claude-code-worktree-subagent-can-t-see-your-feature-branch-set-baseref-to.md", "text": "https://wpnews.pro/news/your-claude-code-worktree-subagent-can-t-see-your-feature-branch-set-baseref-to.txt", "jsonld": "https://wpnews.pro/news/your-claude-code-worktree-subagent-can-t-see-your-feature-branch-set-baseref-to.jsonld"}}