Skip to content

Plugin marker hooks follow the shell's cwd, so a cd mid-session marks the wrong repository #3921

Description

@max-sixty

The six marker hooks in plugins/worktrunk/hooks/hooks.jsonmarker set on
UserPromptSubmit, Notification, PreToolUse, PermissionRequest and Stop,
and marker clear on SessionEnd — run without -C:

bash "$CLAUDE_PLUGIN_ROOT/hooks/wt.sh" config state marker set 💬 || true

So the marker resolves against the hook process's working directory. That is the
agent's shell cwd, and an agent moves it during a turn — reading files out of a
second checkout, for instance. The two hooks in the same file that do reach for a
directory both scope it: WorktreeRemove passes -C "$p", and WorktreeCreate
cds to CLAUDE_PROJECT_DIR.

Three consequences, all silent:

  • A cd into another repository marks that repository's branch instead, and the
    session's own marker stops updating. The statusline then carries a stale
    marker on the branch being worked on and a spurious one somewhere else.
  • A session that ends while the shell sits in another repository clears that
    repository's marker on SessionEnd, and leaves its own set.
  • In a directory that is not a repository the command prints
    ✗ git rev-parse --git-common-dir failed (exit 128) and exits 1. The trailing
    || true turns that into a success, so nothing surfaces.

Repro, given a worktree of one repo and any second repo:

cd /tmp/repo-a.feature && wt config state marker set 🧪
# ✓ Set marker for feature to 🧪

cd /tmp/repo-b && wt config state marker set 🧪
# ✓ Set marker for main to 🧪      <- repo-b's branch, from a session on `feature`

cd /tmp/not-a-repo && wt config state marker set 🧪
# ✗ git rev-parse --git-common-dir failed (exit 128), rc 1

The marker should track the worktree the session belongs to rather than wherever
its shell currently is. -C <path> would carry that, but the value to pass isn't
obvious: CLAUDE_PROJECT_DIR is the launch directory and goes stale once the
session moves to another worktree mid-run, and the hook payload's cwd is the
same directory that drifted. Pinning the worktree at session start is one route;
resolving it from the session record is another.

Seen on worktrunk e4238e8.

This was written by Claude Code on behalf of max-sixty

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions