[FEATURE] Add PostWorktreeCreate hook (or setup command) for environment initialization in worktrees

Status Fixed / completed
Maintainer reply None cached
Activity 10 comments · opened Feb 22, 2026 · closed Aug 17, 2026

Preflight Checklist

  • [x] I have searched existing requests and this feature hasn't been requested yet
  • [x] This is a single feature request (not multiple features)

Problem Statement

When using --worktree, isolation: worktree (subagents), or Agent Teams, Claude Code creates a new git worktree via git worktree add. This correctly copies all tracked files but does not carry over gitignored state — most critically:

  • .venv/ — Python virtual environment with all project dependencies
  • .env — environment variables (DB credentials, API keys, service URLs)
  • node_modules/ — (less critical, npm install is fast and safe)

For Python projects, this means agents in worktrees cannot execute code, run tests, or use linters — the core value proposition of worktree isolation is lost.

Why this matters

The worktree feature is designed for parallel agent execution. But in a typical Python project:

  1. Agent starts in a fresh worktree
  2. Agent tries to run pytest, ruff, mypy, or any Python script
  3. Fails — no .venv, no dependencies installed
  4. Agent must either:
  • pip install into system Python (unsafe, contaminates host)
  • Create a new venv + install all deps (slow: 30-120s depending on project size, wastes disk)
  • Fail and report it cannot complete the task

This affects all three worktree use cases:

| Use case | Can user manually set up env? | Automated? |
|---|---|---|
| claude --worktree (CLI) | ✅ Yes, before running claude | ❌ No hook |
| isolation: worktree (subagents) | ❌ No, agent creates worktree automatically | ❌ No hook |
| Agent Teams (teammates) | ❌ No, worktrees created automatically | ❌ No hook |

For subagents and Agent Teams — the primary use case for parallel development — there is no way for the user to intervene between worktree creation and agent start.

Current workarounds and why they're insufficient

Workaround 1: CLAUDE.md instructions

# CLAUDE.md
When working in a worktree, first run: python -m venv .venv && source .venv/bin/activate && pip install -e ".[dev]"

Problems:

  • Unreliable — Claude often ignores venv instructions (see #273, #2709, #9368)
  • Slow — full dependency installation on every worktree creation
  • Wastes tokens on environment setup instead of actual work
  • Not deterministic — hooks exist precisely because LLM compliance isn't guaranteed

Workaround 2: Hijack WorktreeCreate hook

#!/bin/bash
set -e
INPUT=$(cat)
NAME=$(echo "$INPUT" | jq -r '.name')
DIR="$CLAUDE_PROJECT_DIR/.claude/worktrees/$NAME"

# Reproduce default git behavior
git worktree add "$DIR" -b "worktree-$NAME" HEAD >&2

# Set up environment
ln -s "$CLAUDE_PROJECT_DIR/.venv" "$DIR/.venv" >&2
ln -s "$CLAUDE_PROJECT_DIR/.env" "$DIR/.env" >&2

echo "$DIR"

Problems:

  • Fragile — reproduces internal Claude Code logic (git worktree add -b worktree-$NAME HEAD). If the default behavior changes (branch naming, base ref, worktree path), the hook silently creates incompatible worktrees
  • WorktreeCreate is documented as a replacement for non-git VCS, not a post-creation hook
  • Symlinked .venv is unsafe if agent runs pip install — it modifies the shared venv

Workaround 3: Use uv instead of pip/venv

uv sync && uv run pytest is fast and doesn't require a pre-existing venv. But:

  • Requires the project to adopt uv (not always possible)
  • Still doesn't solve .env files
  • Still relies on CLAUDE.md instructions (non-deterministic)

Proposed Solution

Add a PostWorktreeCreate hook event that fires after the standard git worktree add completes successfully.

Hook specification

Event name: PostWorktreeCreate

When it fires: After Claude Code's built-in git worktree add creates the worktree, but before the agent session starts in it.

Input (stdin JSON):

{
  "session_id": "abc123",
  "hook_event_name": "PostWorktreeCreate",
  "cwd": "/Users/dev/my-project",
  "worktree_path": "/Users/dev/my-project/.claude/worktrees/feature-auth",
  "worktree_name": "feature-auth",
  "branch_name": "worktree-feature-auth",
  "base_ref": "HEAD"
}

Key fields:

  • worktree_path — absolute path to the created worktree (critical for setup scripts)
  • worktree_name — the slug identifier
  • branch_name — the branch created by git worktree add
  • base_ref — the ref the worktree was branched from

Output: Standard allow/block decision model (or no output required — just run the command).

On failure: Warning only, do not block worktree creation. The agent should still start — it can attempt to set up the environment itself or report the issue. This is environment optimization, not a gate.

Example usage

.claude/settings.json:

{
  "hooks": {
    "PostWorktreeCreate": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "bash \"$CLAUDE_PROJECT_DIR/.claude/hooks/post-worktree-setup.sh\"",
            "timeout": 60
          }
        ]
      }
    ]
  }
}

.claude/hooks/post-worktree-setup.sh:

#!/bin/bash
set -e
INPUT=$(cat)
WORKTREE_PATH=$(echo "$INPUT" | jq -r '.worktree_path')
PROJECT_DIR=$(echo "$INPUT" | jq -r '.cwd')

# Symlink Python venv (fast, no disk overhead)
if [ -d "$PROJECT_DIR/.venv" ] && [ ! -e "$WORKTREE_PATH/.venv" ]; then
  ln -s "$PROJECT_DIR/.venv" "$WORKTREE_PATH/.venv" >&2
  echo "Symlinked .venv" >&2
fi

# Copy .env (not symlink — agent might modify it)
if [ -f "$PROJECT_DIR/.env" ] && [ ! -e "$WORKTREE_PATH/.env" ]; then
  cp "$PROJECT_DIR/.env" "$WORKTREE_PATH/.env" >&2
  echo "Copied .env" >&2
fi

Alternative: worktreeSetupFiles configuration

If a new hook event is too heavy, a simpler alternative: a configuration option in settings.json that specifies files/directories to symlink or copy into new worktrees:

{
  "worktree": {
    "setupFiles": [
      { "path": ".venv", "strategy": "symlink" },
      { "path": ".env", "strategy": "copy" },
      { "path": "config/local.yaml", "strategy": "copy" }
    ]
  }
}

This would cover 90% of use cases without requiring users to write shell scripts.

Related Issues

  • #273 — Claude doesn't detect .venv/ automatically
  • #2709 — Claude uses global pip instead of venv
  • #8855 — No persistent venv activation across commands
  • #9368 — Claude ignores CLAUDE.md instructions about venv/uv
  • #19938 — Missing instructions for environment file setup in worktree workflow
  • #20905 — Dependency installation guidance buried in Tips, not in Steps
  • #21613 — No Python support in official devcontainer

Additional Context

Scope of impact

Python is one of the most popular languages for Claude Code users (acknowledged in #21613). Every Python project using venv/virtualenv (which is effectively all of them) is affected when using worktree isolation.

What other tools do

  • claude-worktree (PyPI) — third-party wrapper that auto-symlinks .venv and node_modules, supports configurable copy-files. Validates the need exists.
  • git-worktree-runner (coderabbitai) — supports copy_patterns and run_hooks_in() post-creation.
  • worktrunk — supports post-start hooks for dependency installation.

The ecosystem has independently converged on the same solution: a post-creation setup step. Claude Code is the only tool in this space that lacks it.

Why WorktreeCreate is not sufficient

Per the docs: "For other version control systems like SVN, Perforce, or Mercurial, configure WorktreeCreate and WorktreeRemove hooks to provide custom worktree creation and cleanup logic. When configured, these hooks replace the default git behavior."

WorktreeCreate replaces git worktree add — it's a VCS adapter, not a setup hook. Using it for environment setup requires reproducing Claude Code's internal git worktree logic, which is undocumented, may change, and creates a maintenance burden for users.

View original on GitHub ↗

7 Comments

github-actions[bot] · 6 months ago

Found 3 possible duplicate issues:

  1. https://github.com/anthropics/claude-code/issues/19938
  2. https://github.com/anthropics/claude-code/issues/26697
  3. https://github.com/anthropics/claude-code/issues/20905

This issue will be automatically closed as a duplicate in 3 days.

  • If your issue is a duplicate, please close it and 👍 the existing issue instead
  • To prevent auto-closure, add a comment or 👎 this comment

🤖 Generated with Claude Code

nikitaCodeSave · 6 months ago

This is not a duplicate of the flagged issues. Here's why:

#19938 — [DOCS] Missing instructions for environment file setup

That issue asks to update documentation with a manual cp .env step. It's a docs gap. My issue requests a new hook event (PostWorktreeCreate) because manual copying is impossible when worktrees are created automatically by subagents and Agent Teams.

#26697 — [Feature Request] Configurable untracked file copying

Closest in spirit, but different in scope:

  • #26697 targets Claude Code Desktop and proposes copyUntrackedFiles for simple files (.env, .env.local)
  • My issue targets CLI subagents and Agent Teams — the automated use cases where users cannot intervene between worktree creation and agent start
  • My issue identifies the architectural gap in the hook system: WorktreeCreate replaces git worktree add (it's a VCS adapter), so there's no post-creation hook for environment setup
  • My issue covers Python .venv/ — a directory that should be symlinked (not copied), because copying a full venv is slow and wastes disk, while symlinking is instant

#20905 — [DOCS] Dependency installation buried in Tips

Pure documentation ordering issue. No feature request.

What makes this issue unique

  1. The hook gap is the core problem. For isolation: "worktree" subagents and Agent Teams, the user has zero opportunity to set up the environment. No amount of documentation fixes this — it requires a programmatic hook.
  1. WorktreeCreate cannot solve this. Per the docs, it replaces git worktree add. Using it for post-creation setup requires reproducing Claude Code's internal git worktree logic — fragile and undocumented.
  1. Two concrete solutions proposed:
  • PostWorktreeCreate hook (fires after git worktree add, receives worktree_path)
  • worktreeSetupFiles config with symlink/copy strategies (simpler alternative, covers 90% of cases — similar to #26697's copyUntrackedFiles but with symlink support for directories like .venv)

I do reference #19938 and #20905 as related issues in my submission. They describe symptoms of the same underlying problem — but my issue proposes the fix at the right abstraction level (hooks/config, not docs).

eoliphan · 6 months ago

i was just about to file this :)

coreh · 5 months ago

Would fix our monorepo worktrees where node_modules workspace symlinks resolve to the main checkout instead of the worktree — a post-create bun install (combined with #27282 for external placement) would solve it. Related: #27282

echarrod · 5 months ago

Our current alternative is to use gtr (https://github.com/coderabbitai/git-worktree-runner/) to manage worktrees.
Then we have:

  1. Worktree instructions in AGENTS.md (can also use a skill I guess, although they're not as reliable at the moment):
- Worktrees: **always** use `git gtr` to manage git worktrees — never use raw `git worktree add` or built-in agent worktree tools (e.g. Claude Code's `EnterWorktree`), as these bypass `.gtrconfig` hooks (`postCreate`, `postCd`, file copying, etc.). Common commands:
  - `git gtr new <branch>` — create a new worktree
  - `git gtr list` — list worktrees
  - `git gtr rm <branch>` — remove a worktree
  1. Have a .gtrconfig that can handle executing scripts when you run gtr cd, the ones it sounds like we're looking for in this thread are postCd and postCreate:
[copy]
    # Files to copy to new worktrees
    include = config.local.json

    # Directories to copy to new worktrees
    includeDirs = .vscode
    includeDirs = .claude

    # Exclude submodule paths so postCreate hook can clone them cleanly
    excludeDirs = sharedproto/*
    excludeDirs = blobs/*
    # Exclude Claude Code worktrees directory to avoid copying nested worktree data
    excludeDirs = .claude/worktrees
    excludeDirs = .claude/worktrees/*

[hooks]
    postCd = source ./vars.sh
    postCreate = git submodule update --init --force --depth 1 --progress && npm ci
shoffeepeng · 2 months ago

Also ran into this. Wrote about it (along with the broader worktree isolation model) here:

https://my.feishu.cn/docx/O1O0daR6SoSiKsxksiecFjk7nKc

The article covers the .venv/.env problem as one of the real-world cracks in the worktree isolation design, alongside stale cleanup and build cache collisions across languages.

rohansx · 1 month ago

+1 to this — the "ecosystem has independently converged on the same solution" point is right, and it's worth adding workz to that list alongside claude-worktree and git-worktree-runner. It's a standalone binary that does exactly the symlink-venv/copy-env step described here (project-aware — .venv, node_modules, target, etc.), plus optionally allocates a unique port range, database name, and Docker Compose project per worktree, so parallel worktrees don't collide on top of not having deps.

For the claude --worktree CLI case, WorktreeCreate already works as the seam today:

{
  "hooks": {
    "WorktreeCreate": [
      { "hooks": [ { "type": "command", "command": "workz sync --isolated --quiet" } ] }
    ]
  }
}

But this issue's real point stands regardless of that workaround: for isolation: "worktree" subagents and Agent Teams, there's no seam at all today, since the worktree is created and populated with an agent before a user (or a project-level hook aimed at the CLI flow) gets a chance to intervene. A PostWorktreeCreate hook (or the simpler worktreeSetupFiles-style config also proposed here) would close that gap — right now it's the one worktree-creation path with zero customization point, which is exactly backwards from the automated/parallel use case the feature is for.

Showing cached comments. Read the full discussion on GitHub ↗