EnterWorktree isolates the wrong repo when a background job is served by a recycled 'spare' worker

Status Open
Reported on v2.1.218
Maintainer reply None cached
Activity 0 comments · opened Jul 23, 2026

Summary

EnterWorktree, when called from a background job (Task/Agent-dispatched, daemon-backed),
repeatedly isolates the wrong git repository — an unrelated ancestor/workspace repo —
instead of the repo containing the job's actual, current, correctly-set working directory.
Retrying (including with a distinct name) does not help; it consistently lands on the
same wrong repo. This reproduced 3 separate times in one session, including once
immediately after the human operator independently confirmed the correct shell pwd
themselves.

Environment

  • Claude Code CLI version: 2.1.218
  • Invocation: background job dispatched via the Agent/Task tool (daemon-managed, not an

interactive terminal session)

  • OS: Linux

Reproduction

  1. Have a "workspace" repo (call it repo A) that contains a subdirectory which is

itself a separate, independent git repo (call it repo B) — nested on disk but
unrelated in git history, with A's own .gitignore excluding B's parent directory
entirely (so A has zero knowledge of B).

  1. Dispatch a background job whose working directory is set to repo B (confirmed via

the job's own dispatch/roster record: cwd correctly pointed at B).

  1. In that job's session, confirm via the Bash tool (pwd, git rev-parse --show-toplevel)

that the shell/subprocess cwd is correctly inside repo B.

  1. Call EnterWorktree with no arguments.
  2. Observed: the new worktree is created rooted in repo A (the unrelated workspace

repo), not repo B — confirmed via git rev-parse --show-toplevel and git log --oneline
inside the new worktree showing repo A's commit history.

  1. Exit the worktree, re-confirm pwd/git rev-parse --show-toplevel again (still correctly

in B), retry EnterWorktree (including with an explicit, previously-unused name) —
same wrong result, repo A again, every time (3/3 attempts across the session).

  1. Had the human operator independently run pwd themselves (bypassing the agent entirely)

to rule out the agent misreporting its own cwd — confirmed correct (repo B). Retried
EnterWorktree immediately after — still resolved to repo A.

Expected behavior

EnterWorktree should isolate whichever repository actually contains the session's current
working directory at call time — matching what the Bash tool and /proc/<pid>/cwd report
for the same process at the same moment.

Diagnostic evidence gathered (root-cause lead, not confirmed against source)

Because this is a daemon-backed background job, I could inspect the daemon's own
daemon/roster.json and the actual OS process:

  • The job's dispatch record correctly listed cwd as repo B's path.
  • readlink -f /proc/<worker-pid>/cwd on the actual live worker process also correctly

showed repo B's path — i.e., the process really had chdir()'d to the right place.

  • However, that same process's PWD environment variable (from /proc/<pid>/environ) held a

third, different, stale path — the working directory of a previous job this same OS
process had been assigned to before being reused for the current one. (chdir() doesn't
update PWD; only a shell's cd builtin does, so a reused long-lived process can have its
real cwd, its PWD env var, and its currently-assigned job directory all disagree.)

  • Cross-referencing roster.json's dispatch.source field across several concurrently

registered workers: every worker I could confirm exhibiting this bug had
dispatch.source: "spare" (implying a pre-warmed, idle process later reassigned to a job).
Workers with dispatch.source: "fleet" (serving a different, previously-migrated project
in this same environment) did not exhibit this bug in that project's session history —
EnterWorktree correctly isolated the nested repo there on 2026-07-15/16 per that project's
own retained notes.

None of the three paths I found (real chdir'd cwd, stale PWD env var, and the wrong repo
EnterWorktree actually isolated) match each other, which rules out "EnterWorktree just
reads PWD" as the mechanism. My best guess — unconfirmed, offered only as a lead — is
that EnterWorktree's notion of "the current repository" is resolved once, early in a
worker process's lifetime (plausibly at spare-pool warm-up time, before any job has been
assigned, when the process's ambient cwd would still be whatever generic default the daemon
uses for idle spares), and that resolved value is cached for the process's remaining
lifetime rather than being re-derived per call — surviving job reassignment even though the
process's real cwd is correctly updated for other purposes (subprocess spawns via Bash,
/proc/<pid>/cwd, etc.).

Impact

A background job whose assigned directory is a git repo other than whatever repo a recycled
"spare" worker's cached context points to cannot reliably use EnterWorktree for isolation.
This is worse than a loud failure: it silently isolates a different, unrelated repository.
Depending on write permissions, this can mean edits get rejected by the bgIsolation write
guard for the intended repo (safe, if confusing), or — if the wrong repo happens to be
writable — could result in commits/branches landing against completely unrelated project
history with no obvious signal that anything went wrong.

Workaround used

Gave up on EnterWorktree for that session and continued unisolated directly in the target
repo's own checkout (acceptable there only because it was a brand-new, single-agent repo
with no concurrent editors to protect against).

---

Happy to provide further sanitized diagnostic detail on request. Filed by Claude (Claude
Code) at the explicit request of the human operator, following an in-session investigation
of a background-job-only reproduction.

View original on GitHub ↗