Skip to content

Worktree-isolation Agent dispatch: undocumented hook contract + misleading error in standard git repos #20

@UpstateNate

Description

@UpstateNate

Issue draft: Worktree-isolation Agent dispatch — undocumented hook contract

Repo target: ed3d-plugins (or whichever surface owns Agent-dispatch worktree isolation)
Filed by: NicheFinder MVP execution session, 2026-05-14
TL;DR: Agent({ isolation: "worktree" }) errors with a "configure WorktreeCreate hooks" message in a perfectly fine git repo, the hook contract isn't documented, and the contract that one documentation source gives is wrong.


Repro

  1. Standard git repo (git rev-parse --is-inside-work-treetrue).
  2. Call any subagent via Agent with isolation: "worktree":
    Agent({
      subagent_type: "...",
      isolation: "worktree",
      description: "...",
      prompt: "..."
    })
    
  3. Tool returns:
    Cannot create agent worktree: not in a git repository and no
    WorktreeCreate hooks are configured. Configure WorktreeCreate/
    WorktreeRemove hooks in settings.json to use worktree isolation
    with other VCS systems.
    

The error implies (a) the harness can't detect we're in git, and (b) the workaround is hooks designed for non-git VCS. Neither expectation matched reality.

What actually works

After two hours of probing, the working .claude/settings.local.json is:

{
  "hooks": {
    "WorktreeCreate": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "tee /tmp/wt_create_stdin.json | jq -r '.name' | { read -r name; mkdir -p /tmp/nf-worktrees; path=\"/tmp/nf-worktrees/$name\"; git worktree add \"$path\" HEAD >&2 && echo \"$path\"; }"
          }
        ]
      }
    ],
    "WorktreeRemove": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "tee /tmp/wt_remove_stdin.json | jq -r '.worktree_path // .path // empty' | { read -r path; [ -n \"$path\" ] && git worktree remove --force \"$path\" >&2 2>&1 || true; }"
          }
        ]
      }
    ]
  }
}

Where the contract differs from what's documented (or what we were told)

Stdin to WorktreeCreate

One Claude Code documentation source we were pointed at said:

Input (stdin): JSON with base_path (parent directory) and worktree_name (identifier)

What we actually observed on stdin:

{
  "session_id": "7ff4206e-9800-4240-b787-74ec8f1386bd",
  "transcript_path": "/home/nate/.claude/projects/.../7ff4206e-....jsonl",
  "cwd": "/home/nate/Projects/NicheFinder",
  "hook_event_name": "WorktreeCreate",
  "name": "agent-aa41eeb6b7a17bfd8"
}

No base_path. No worktree_name. The only useful identifier is name. The hook has to invent its own base path.

Stdout from WorktreeCreate

The hook must echo the absolute path of the created worktree on stdout (and only that — diagnostics go to stderr). Documenting this isn't obvious from the schema either.

Stdin to WorktreeRemove

We didn't fire it yet, but .worktree_path is a plausible field name based on the one source we found. The hook above falls back to .path as well, just in case.

Other gotchas we hit

1. Watcher startup-only behavior

If .claude/settings.local.json does NOT exist at session start, creating it mid-session has no effect — the settings watcher doesn't pick up the file. This is mentioned in the update-config skill docs but easy to miss.

  • Workaround: /hooks (a user-only UI menu) forces a reload, OR restart Claude Code.
  • After restart, subsequent edits to the same file DO hot-reload. So once the file is established, edits work.

2. The error message points at the wrong fix

"to use worktree isolation with other VCS systems"

Reads like "this is for jj/fossil users; if you're on git you shouldn't need it." But in fact you absolutely do need hooks for git too — the harness doesn't auto-detect a git repo from where Agent runs.

Suggested fixes for the harness/plugin

  1. Document the WorktreeCreate / WorktreeRemove stdin shape in the public hooks docs alongside other event-stdin shapes (PreToolUse, PostToolUse, etc.). Include a worked example for git.
  2. Auto-detect git and skip the hook requirement when .git/ exists. The error message currently says "not in a git repository" when we are, in a worktree, in a git repo. Either the detection is broken or the wording is misleading.
  3. Ship a ready-made git WorktreeCreate hook as part of the default config (or a one-line snippet operators can paste). Right now everyone hitting this has to reverse-engineer it.
  4. Fix the error message wording if hooks really are required even for git: "Configure WorktreeCreate hooks; see [link] for the git template" rather than "with other VCS systems".

Suggested fixes for the ed3d-plan-and-execute skill

The executing-an-implementation-plan skill encourages parallel agent dispatch but never mentions worktrees. The using-git-worktrees skill exists separately. Connect them:

  • When the orchestrator decides to fan out (e.g., 3+ subcomponents in parallel), nudge: "Consider worktree isolation via isolation: \"worktree\" to prevent commit-history bleed." (We hit a real bug in Phase 2 where parallel implementors all ran git add . and one swept up the others' files; the eventual fix took two extra review cycles.)
  • Or include the worktree hook template by default in using-plan-and-execute setup, so it's available from the first session.

Evidence

  • git worktree list after two successful probe dispatches:
    /home/nate/Projects/NicheFinder            dff3c28 [main]
    /tmp/nf-worktrees/agent-a9d0724d7de7df156  dff3c28 (detached HEAD)
    /tmp/nf-worktrees/agent-aa41eeb6b7a17bfd8  dff3c28 (detached HEAD)
    
  • /tmp/wt_create_stdin.json captured the stdin payload (shape above).
  • The probe agent's report confirmed it ran from the worktree path:
    /tmp/nf-worktrees/agent-a9d0724d7de7df156
    HELLO_FROM_WORKTREE
    

Severity

Medium. Parallel dispatch works without worktrees if you instruct agents to git add <paths> carefully — we shipped Phases 1–5 of a 7-phase plan that way. But worktree isolation is the right primitive for parallel work, and the current onboarding for it is a two-hour scavenger hunt.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions