Skip to content

trace-claude-code: record-only WorktreeCreate/WorktreeRemove hooks break Agent(isolation:"worktree") and --worktree #29

Description

@rdamienc

Summary

The trace-claude-code plugin registers its record-only telemetry hook (hooks/record_event.sh) on the WorktreeCreate and WorktreeRemove events:

"WorktreeCreate": [{ "hooks": [{ "type": "command",
  "command": "bash ${CLAUDE_PLUGIN_ROOT}/hooks/record_event.sh WorktreeCreate", "async": false }] }],
"WorktreeRemove": [{ "hooks": [{ "type": "command",
  "command": "bash ${CLAUDE_PLUGIN_ROOT}/hooks/record_event.sh WorktreeRemove", "async": false }] }]

But per the Claude Code worktrees doc, a configured WorktreeCreate hook "replaces the default git worktree logic entirely" (https://code.claude.com/docs/en/worktrees, "Non-git version control"). record_event.sh is explicitly record-only — it reads stdin, optionally records, and always exit 0 with no stdout. So once this plugin is enabled, the harness treats the telemetry hook as the authoritative worktree creator, it returns no path, and worktree creation fails with:

WorktreeCreate hook failed: hook succeeded but returned no worktree path
(command: echo the path to stdout; http/callback: return hookSpecificOutput.worktreePath)

This breaks all worktree isolation while the plugin is enabled: claude --worktree <name>, EnterWorktree, and Agent(isolation:"worktree") (subagent worktrees). It is not path-dependent (we initially misattributed it to a spaces-in-path repo; native git worktree add works fine from the CLI because the CLI bypasses the hook — the breakage is purely the hook shadowing native creation).

Repro

  1. Enable trace-claude-code in any git repo.
  2. Run claude --worktree test (or dispatch Agent(isolation:"worktree")).
  3. Observe the "returned no worktree path" error. Native git worktree add from a shell still works.

Impact

Silent capability loss: worktrees work until the plugin is enabled, then break with a confusing error that points at "WorktreeCreate hook" with no configured hook visible in settings.json (it's the plugin's hooks/hooks.json). Cost real debugging time.

Suggested fix

A record-only/observability hook should not register on WorktreeCreate/WorktreeRemove, since the harness treats those as the authoritative creator/remover (they replace native git), not as passive lifecycle notifications. Options:

  • Drop WorktreeCreate/WorktreeRemove from record_event.sh's registration; or
  • If telemetry on those events is desired, have the hook do the real git worktree add/remove and echo the path (i.e. be a true creator), guarded so it only acts when no other creator is present — but the simplest correct fix is to not claim these events for a record-only hook.

Workaround (for others hitting this)

Add a project-level WorktreeCreate/WorktreeRemove override hook that does git worktree add/remove (paths quoted) and echoes the worktree path to stdout. Because multiple hooks run and the harness uses the one that returns a path, this restores worktree creation while keeping the plugin's tracing. (Editing the plugin's cached hooks.json also works but reverts on plugin update.)

— Reported from a Claude Code session debugging this in a real project.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions