Skip to content

chore(source-control): upstream draft — worktree isolation blocked writes at a non-repo root where the docs say it skips #2208

Description

@kyle-sexton

This is a DRAFT for a human to file upstream against anthropics/claude-code. It is not work for this repository. Nothing here is fixable in plugins/source-control; the rows are collected so the drafts are not lost, and so nobody re-opens the plugin-side hunt that this batch closed.

Claude Code's documented behavior at a directory that is not a git repository is: attempt isolation, and if the WorktreeCreate hook fails, skip isolation and edit the working directory in place. What was observed instead was writes blocked at a non-repo root — including a write to a temp path outside any checkout — with a refusal message that describes a checkout that does not exist. That is a divergence from documented behavior, and the changelog shows no entry that would have corrected it.

Rows

  • I9 SC-F1 (deadlock half only)plugins/source-control/hooks/hooks.json, plugins/source-control/scripts/worktree-create.sh:258-261 — the gate exits non-zero at a non-repo root (by design); the docs say the session should then skip isolation and edit in place, and it did not. Only the deadlock half is carried here — the plugin-side registration-scope half is filed separately (see cross-links).
  • I9 SC-F8 — no file in this repo — the background-isolation write refusal is blanket, not path-scoped, and its message is self-contradicting. HIGH. Packet-sourced; NOT reproduced by the verifier.
  • I9 SC-F9 — no file in this repo — two secondary upstream items: a docs anchor that does not exist, and no channel for a WorktreeCreate hook to signal "not applicable" inside a git repository.

Evidence

The doc sentence that settles ownership

https://code.claude.com/docs/en/agent-view, section "How file edits are isolated", fetched 2026-08-11:

"When the hook fails in a directory that isn't a git repository, the session skips isolation for that directory and edits the working directory in place. Inside a git repository, writes stay blocked until the session isolates."

Same page, the skip-bullet list, confirms the no-hook case: isolation is skipped up front when "The working directory isn't a git repository and no WorktreeCreate hook is configured". The two statements are consistent, and together they mean the documented outcome at a non-repo root is writes proceed, whether or not a hook is configured.

Path-scoping is documented separately — https://code.claude.com/docs/en/worktrees, "How Claude Code enforces isolation", fetched 2026-08-11:

"Claude Code blocks an Edit, Write, or NotebookEdit that targets a path in the main checkout"

The observation (packet-sourced, unreproduced)

Session 5559b694-…, background job (CLAUDE_CODE_CHILD_SESSION=1), cwd C:\Users\KyleSexton, win32. git -C … rev-parse --show-toplevelfatal: not a git repository. Subagent-side refusal, verbatim:

This subagent's parent bg session hasn't isolated yet, so writes to the shared checkout are
blocked. Re-spawn this agent with isolation: "worktree", or have the parent call EnterWorktree
before spawning.

The message is self-contradicting on its own terms: it says "writes to the shared checkout are blocked" while refusing a write to a temp path outside any checkout, at a root that is not a checkout at all. That sentence should lead the upstream report. The main-thread variant refused with the same shape and named worktree.bgIsolation as the remedy. Cost of the incident: a discovery:researcher run lost ~113k tokens of completed work.

Reproduction status — read before filing upstream

The observation has not been reproduced. It is packet-sourced; the auditor states plainly they could not reproduce it, and the verification pass did not either. Reproduction is currently foreclosed on the observing machine: ~/.claude/settings.local.json gained {"worktree":{"bgIsolation":"none"}} at 22:11:48 on 2026-08-10, applied mid-session, and the packet's write-block observations straddle that edit. No duty-cycle claim is made. The setting must be reverted (or a second machine used) before the original behavior can be observed at all. Whoever files upstream should present this as an observation with a verbatim refusal message and an explicit "not yet reproduced" note, not as a confirmed repro.

Version window — the bug is live, not already fixed

https://code.claude.com/docs/en/changelog, fetched 2026-08-11. Newest version listed: 2.1.227 — the same version captured on 2026-08-10. No entry between 2.1.220 and 2.1.227 mentions non-repo isolation, WorktreeCreate fallback, or bgIsolation. The only worktree-isolation entries in that range (2.1.222, 2.1.224) widen isolation to Bash in every session type; 2.1.226 is the opaque "Bug fixes and reliability improvements" stanza. Nothing indicates the observed behavior was corrected after the audit, so this should be written as a live divergence report.

SC-F9 — the two secondary items

  1. Missing docs anchor. Two pages link to settings#worktree-settings, which does not exist. Checked by the auditor on 2026-08-10; the settings page was NOT re-fetched during verification — unconfirmed at the current docs revision. Re-check before filing.
  2. No "not applicable" channel — narrower than originally filed. At a non-repo root a failing hook now has a documented benign outcome (the agent-view sentence above), so a hook can effectively cede control there by failing. What remains true is the narrower claim: inside a git repository there is no documented channel for a WorktreeCreate hook to say "not applicable" — any non-zero exit fails creation, and exit-0-without-a-path is undocumented in either direction. https://code.claude.com/docs/en/hooks, fetched 2026-08-11, verbatim: "WorktreeCreate | Exit code or hookSpecificOutput.worktreePath | Any non-zero exit code fails creation."

What this settles in our own tracker

Handoff-inbox item 20260811-020411's disposition — "Not this repo — harness, recorded so nobody chases it" — is UPHELD, not reversed. Item 20260811-021645's title claims the deadlock is "probably plugin-owned"; that framing does not survive the docs above. There is no plugin-side deadlock fix, and none should be attempted.

Provenance

Severity: HIGH · Provenance: AUDITOR_VERIFIED — SC-F8 is packet-sourced and was NOT independently reproduced; the SC-F9 docs-anchor leg is auditor-only and unconfirmed at the current docs revision.
Origin: handoff-inbox item 20260811-021645-plugin-audit-four-components-and-guard-deadlock-ownership
Ledger: .work/handoff-inbox-batch-4/ledgers/I9-021645-four-components.md § "Lane D — source-control / worktree-create-gate" (and § "READ FIRST")
Verified against repo HEAD 685dd381.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    priority: needs-triageDefault until a priority tier is assigned.upstream-draftUpstream plugin draft tracked before marketplace promotion.

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions