CLAUDE_CODE_TASK_LIST_ID set via .claude/settings.json is silently shared across ALL worktrees of a repo, with no per-worktree opt-out, and cross-worktree sync appears non-real-time
Summary
Since v2.1.63, project config (.claude/settings.json, CLAUDE.md, skills,
custom agents) is deliberately shared across every git worktree of the same
repository — the settings file lives at the git-common-dir-resolved project
root, so any worktree session reads the same one. That's the right behavior
for hooks/skills/conventions. But CLAUDE_CODE_TASK_LIST_ID rides along as
an ordinary env entry in that same file, and task-list scoping is a
different kind of concern than config sharing: worktrees are specifically
used to isolate concurrent, unrelated work, and a persistent task list is
exactly the kind of state you'd want isolated per feature/worktree, not
pooled repo-wide.
The result: setting CLAUDE_CODE_TASK_LIST_ID (directly, or via a tool that
suggests it — see below) to get task persistence across sessions has the
side effect of making every worktree of the project — including ones for
completely unrelated, concurrently-running features — share one task list,
permanently, with no way to scope it narrower short of unsetting the
variable for the whole project.
How this was hit
A settings-scaffolding tool (a Claude Code plugin, not part of Claude Code
itself) prompts: *"No persistent Task List ID configured. For a project this
size, tasks won't survive across sessions. Add one?"* and on "yes" writes{"env": {"CLAUDE_CODE_TASK_LIST_ID": "<repo-name>"}} into.claude/settings.json. The prompt frames this purely as "persistence across
sessions" — it does not disclose that the same change also collapses task
isolation across every worktree of the repo, forever, with no per-worktree
override available. A user reasonably expecting only persistence got
persistence + forced repo-wide pooling as an undisclosed bundle.
In practice: two completely unrelated features were being developed
concurrently in two different worktrees of the same repo (one an in-progress
implementation, one a separate planning/spec-writing session). A third
session, working directly in the primary checkout on a small, unrelated bug
fix, started seeing the other worktree's task list (status, in-progress
markers, everything) in its own TaskList tool results and status line —
despite never having created or touched any of those tasks. Confirmed via a
direct TaskList tool call (not just passive status-line display) that this
is real shared backing state, not a rendering artifact.
Additional symptom: cross-worktree sync does not appear to be real-time
Separately, and possibly related: a user running multiple worktree-based
sessions against the same shared task list reports the status line
appearing to "stick" on one task for an extended period, then several tasks'
statuses changing at once in a burst — rather than updating incrementally as
they actually happen. This is consistent with the shared list being read
lazily (on next poll/render/tool-call) rather than genuinely pushed live to
every session watching it, and that lazy-catch-up behavior being more
noticeable specifically when the writer and reader sessions are in
different worktrees rather than the same working directory (where
filesystem-level watching may behave differently than across a linked
worktree's separate directory). This wasn't independently instrumented/
reproduced with certainty — noting it as a related observation from the same
incident, not a confirmed root cause.
Expected behavior
Either:
CLAUDE_CODE_TASK_LIST_ID(and task-list state generally) should default
to worktree-scoped, with an explicit, separate mechanism to opt into
repo-wide sharing when that's actually wanted (the inverse of current
behavior) — since config/hooks/skills sharing and task-coordination
sharing are different concerns with different natural defaults; or
- At minimum, some documented way to set a per-worktree override (e.g. a
magic value like ${worktree} that resolves to the current worktree's
directory/branch name at session start, distinct from a literal string)
so a project can have persistence and per-worktree isolation
simultaneously, rather than being forced to choose one or the other
project-wide.
- If genuine cross-worktree sharing is intended and working as designed, the
broadcast/sync mechanism should be verified to actually propagate updates
promptly across worktree boundaries, not just within a single working
directory.
Actual behavior
- One
.claude/settings.json(shared by design across all worktrees of a
repo, confirmed since v2.1.63) is the only place to set
CLAUDE_CODE_TASK_LIST_ID, so any value set there is necessarily
repo-wide — there is no worktree-relative interpolation available.
- A session with no awareness of, or connection to, another worktree's work
sees that worktree's full task list and live status through its own
TaskList tool calls.
- Updates from one worktree's session to a shared list appear to surface in
batches on another session's view rather than incrementally in real time.
Environment
- Claude Code 2.1.212
- Reproduced via:
.claude/settings.jsonwith `{"env":
{"CLAUDE_CODE_TASK_LIST_ID": "<repo-name>"}} at a repo's primary checkout.claude/worktrees/<name>` linked worktrees nested underneath,
root, with
multiple concurrent sessions across the primary checkout and two different
worktrees.
Related issues
Not a duplicate of any of these as far as I can tell, but closely adjacent —
same general "worktree isolation has surprising gaps" territory:
- #29083 — subagent file paths resolve to the main tree instead of the
active worktree (file-edit isolation, not task-list/config sharing)
- #27343 —
CLAUDE_PROJECT_DIRresolves to the main repo inside a worktree - #34437 — "Worktrees should share the same project directory as the main
repo" (argues the opposite direction — that config sharing is desirable;
this issue isn't disputing that for config/hooks/skills, only for
task-list coordination state specifically)
- #4963 — Feature Request: Integrated Parallel Task Management and Worktree
Orchestration (closed, not planned; proposed a different UX — /tasks,
/fork — doesn't address CLAUDE_CODE_TASK_LIST_ID scoping specifically)
None of the above, nor anything else found searching the changelog/issue
tracker, specifically addresses CLAUDE_CODE_TASK_LIST_ID scoping across
worktrees, or the sync-latency observation above.
This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗