[bug] [area:agents] [platform:macos] Agent(isolation: "worktree") post-creation setup silently rewrites...

Open 💬 1 comment Opened Jun 12, 2026 by jsoldner

Preflight Checklist

  • [x] I have searched existing issues and this hasn't been reported yet
  • [x] This is a single bug report (please file separate reports for different bugs)
  • [x] I am using the latest version of Claude Code

What's Wrong?

Environment

  • Platform: macOS Darwin 25.6.0 (Apple Silicon)
  • Claude Code CLI: 2.1.173 (Claude Code) (confirmed by claude --version)
  • Transport: CLI / local subprocess
  • Repository type: Private repository with core.hooksPath = .githooks configured (custom hook directory for pre-commit/pre-push security controls)

Summary

When the Claude Code Agent tool is invoked with isolation: "worktree", its post-creation setup step writes .git/config in the shared (parent) repository, overwriting core.hooksPath from the operator-configured value (.githooks) to the default (.git/hooks). This silently disables any custom git hook security controls in the shared repo. All subsequent commits and pushes from the shared repo run with dead hooks and no observable indication of failure — the hooks appear to pass (default .git/hooks stubs exit 0).

Reproduction Steps

  1. Configure a git repository with a custom core.hooksPath:

``
git config core.hooksPath .githooks
``

  1. Place security-control scripts in .githooks/pre-commit and .githooks/pre-push (executable).
  2. Verify hooks fire correctly: make a commit, confirm hook output appears.
  3. Dispatch an Agent tool call with isolation: "worktree" from within a Claude Code session rooted at this repository.
  4. After the agent completes and its worktree is removed, inspect the shared repo's .git/config:

``
git config core.hooksPath
``

  1. Make a new commit and observe that no hook output appears.

Expected Behavior

The Agent tool's worktree isolation post-creation setup should not modify the shared repository's existing core.hooksPath. At minimum, if the worktree setup must configure core.hooksPath for its own purposes, it should restore the pre-existing value in the shared repo config when the worktree is torn down.

Actual Behavior

After the first Agent(isolation: "worktree") dispatch, core.hooksPath in the shared repository's .git/config is overwritten from .githooks to .git/hooks. The change is silent — no warning or log message indicates it occurred. The sample hook stubs at .git/hooks/ exit 0 unconditionally, so all subsequent commits and pushes appear to succeed normally with no hook feedback at all.

Impact

Security-control class. This affects repositories where git hooks enforce access controls (secret scanning, sensitive-path blocking, credential leak prevention). When core.hooksPath is silently rewritten:

  • All pre-commit and pre-push security controls stop firing with no observable indication
  • The operator cannot distinguish a passing hook from a dead one (silent exit-0 behavior is identical to a live clean pass)
  • An arbitrary number of commits and pushes may bypass security controls before the rewrite is detected by an out-of-band check

In our case, the hooks guard against accidental commits of sensitive paths (memory files, credential files, portfolio data, Plaid API tokens). The hooks were active for approximately two weeks before this incident; the rewrite was not detected until the following session when a manual git config core.hooksPath check was part of a session-open checklist. All pushes between the rewrite event and detection ran unguarded.

Timeline Evidence

The config write was pinned to the exact dispatch timestamp by Time Machine snapshot bisection: two consecutive hourly snapshots (18:14 and 20:15 local EDT) showed the config at the prior .githooks value in the earlier snapshot and at .git/hooks at timestamp 2026-06-09 18:38:43 in the later. This was the first Agent(isolation: "worktree") dispatch since the hook installation, and the config-write timestamp matches the dispatch timestamp to the second. No other process was identified that could have written .git/config in that window.

Manual git worktree add was separately verified to NOT touch the shared repo's core.hooksPath. The behavior is specific to the Agent tool's isolation: "worktree" post-creation setup path.

Workarounds We Use

  1. Standing prohibition on isolation: "worktree" in this repository. Agents needing an isolated tree use manual git worktree add instead (verified not to touch core.hooksPath).
  1. Clobber-resilience symlink shim: .git/hooks/pre-commit and .git/hooks/pre-push are symlinks pointing into .githooks/. If anything rewrites core.hooksPath back to .git/hooks, the hooks still resolve to the live control scripts. Requires re-creating the symlinks post-clone.
  1. Observable-pass output: Every clean hook run prints a versioned confirmation line (e.g., pre-commit guard v2: N paths scanned, 0 blocks). A silent exit-0 is treated as a dead hook, not a clean pass.
  1. Session-open canary: A 3-test suite (test_hooks_canary.py) verifies core.hooksPath value, GUARD_VERSION constant, and executable bit on every session open. Any regression is caught at the next session start.

Suggested Fix

The worktree post-creation setup should not modify the shared repository's existing core.hooksPath. Options:

  • Preferred: Don't write core.hooksPath to the shared repo config at all — the worktree has its own .git/ (or .git file) and can configure itself in isolation.
  • Acceptable: If the shared repo config must be touched, snapshot the prior core.hooksPath value before writing and restore it on worktree removal.
  • Minimum: Document the behavior explicitly in the Agent tool reference so operators know isolation: "worktree" modifies the parent repo's git config.

What Should Happen?

The Agent tool's worktree isolation post-creation setup should not modify the shared repository's existing core.hooksPath. At minimum, if the worktree setup must configure core.hooksPath for its own purposes, it should restore the pre-existing value in the shared repo config when the worktree is torn down.

Error Messages/Logs

Steps to Reproduce

  1. Configure a git repository with a custom core.hooksPath:

``
git config core.hooksPath .githooks
``

  1. Place security-control scripts in .githooks/pre-commit and .githooks/pre-push (executable).
  2. Verify hooks fire correctly: make a commit, confirm hook output appears.
  3. Dispatch an Agent tool call with isolation: "worktree" from within a Claude Code session rooted at this repository.
  4. After the agent completes and its worktree is removed, inspect the shared repo's .git/config:

``
git config core.hooksPath
``

  1. Make a new commit and observe that no hook output appears.

Claude Model

Not sure / Multiple models

Is this a regression?

Yes, this worked in a previous version

Last Working Version

_No response_

Claude Code Version

2.1.173 (Claude Code) (confirmed by claude --version)

Platform

Anthropic API

Operating System

macOS

Terminal/Shell

Terminal.app (macOS)

Additional Information

_No response_

View original on GitHub ↗

This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗