Summary
context-mode's worktree isolation can choose the wrong session database when the MCP server or hook process is not running from the user's actual repository/worktree directory.
This is easy to hit with Codex/Copilot-style agents and marketplace installs because the server process can run from the installed package directory while hook stdin still contains the real project cwd.
Root cause
There are two related problems:
-
getWorktreeSuffix() uses process.cwd() as the source of truth.
- Installed startup code may
chdir into the package/plugin directory.
- Hooks may receive the real workspace in stdin, but the DB path helpers did not pass that
cwd into worktree suffix resolution.
-
The suffix check compares the raw cwd to the main worktree path from git worktree list --porcelain.
- A subdirectory inside the main worktree is incorrectly treated as a linked worktree because
/repo/subdir !== /repo.
- A subdirectory inside a linked worktree gets a different hash than the linked worktree root, so the same worktree can split into multiple session DBs depending on where the hook ran.
The result is incorrect isolation: session continuity, timeline search, stats, and purge operations may read/write a DB for the package cwd or an unstable subdirectory hash rather than the current project worktree.
Expected behavior
Worktree isolation should be based on the git worktree root for the actual project directory:
- main worktree root and any subdirectory inside it: no suffix
- linked worktree root and any subdirectory inside it: the same stable
__<hash> suffix
- MCP server paths and hook paths should agree when the hook provides a project
cwd
Proposed fix
Resolve the worktree root with:
git -C <projectDir> rev-parse --show-toplevel
git -C <projectDir> worktree list --porcelain
Then compare normalized worktree roots and hash the current worktree root rather than process.cwd().
For stdin-cwd platforms such as Codex, pass the parsed project directory into getSessionDBPath(), getSessionEventsPath(), and getCleanupFlagPath() so hooks do not fall back to the package process cwd.
I am opening a PR with this approach and regression tests.
Summary
context-mode's worktree isolation can choose the wrong session database when the MCP server or hook process is not running from the user's actual repository/worktree directory.
This is easy to hit with Codex/Copilot-style agents and marketplace installs because the server process can run from the installed package directory while hook stdin still contains the real project
cwd.Root cause
There are two related problems:
getWorktreeSuffix()usesprocess.cwd()as the source of truth.chdirinto the package/plugin directory.cwdinto worktree suffix resolution.The suffix check compares the raw cwd to the main worktree path from
git worktree list --porcelain./repo/subdir !== /repo.The result is incorrect isolation: session continuity, timeline search, stats, and purge operations may read/write a DB for the package cwd or an unstable subdirectory hash rather than the current project worktree.
Expected behavior
Worktree isolation should be based on the git worktree root for the actual project directory:
__<hash>suffixcwdProposed fix
Resolve the worktree root with:
Then compare normalized worktree roots and hash the current worktree root rather than
process.cwd().For stdin-cwd platforms such as Codex, pass the parsed project directory into
getSessionDBPath(),getSessionEventsPath(), andgetCleanupFlagPath()so hooks do not fall back to the package process cwd.I am opening a PR with this approach and regression tests.