[BUG] Internal project path key inconsistency in git worktrees inside devcontainers — sessions and memory stored under different keys, /resume finds nothing
Description
When running Claude Code CLI inside a devcontainer that checks out a git worktree (not created by Claude Code), the internal project path key used for session storage differs from the key used for memory storage and /resume lookups. Sessions are written to one ~/.claude/projects/ subdirectory, while /resume and the memory system look in a different one. Result: /resume reports "No conversations found to resume" despite hundreds of valid session .jsonl files on disk.
This appears to be a path resolution inconsistency — some subsystems derive the project key from cwd, others from git rev-parse --git-common-dir (which follows the worktree pointer to the main repo). When these resolve to different filesystem paths (common in containers where mount points differ from host paths), the keys diverge.
Environment
- Claude Code v2.1.74 (CLI)
- Linux (devcontainer on WSL2)
- Git worktree (external, not created by Claude Code)
Reproduction
Setup
A devcontainer where:
- The workspace is mounted at
/workspaces/myproject - The main repo's
.gitdir is bind-mounted at its host path/home/alice/repos/myproject/.git(required so the worktree.gitpointer resolves correctly inside the container) /workspaces/myproject/.gitis a worktree pointer file containing:
````
gitdir: /home/alice/repos/myproject/.git/worktrees/feature-branch
This is a standard setup for running git worktrees in devcontainers — the main .git dir must be mounted at its original host path because git worktree .git pointer files contain absolute paths written by git worktree add.
Git's own path resolution (inside the container)
$ git rev-parse --show-toplevel
/workspaces/myproject # ← cwd-based (correct)
$ git rev-parse --git-common-dir
/home/alice/repos/myproject/.git # ← main repo (host path)
Git itself resolves --show-toplevel correctly to the container workspace path.
What Claude Code does
| Subsystem | Project key | Derived from | Has data? |
|-----------|------------|-------------|-----------|
| Session writer | ~/.claude/projects/-workspaces-myproject/ | cwd | 199 .jsonl files |
| Memory system | ~/.claude/projects/-home-alice-repos-myproject/ | git-common-dir parent | Only memory/ dir, 0 sessions |
| /resume picker | ~/.claude/projects/-home-alice-repos-myproject/ | (same as memory) | Finds 0 conversations |
Steps
- Create a git worktree on the host, open it in a devcontainer
- Start Claude Code CLI, have a conversation, exit
- Start a new session, type
/resume - Expected: Previous sessions appear in picker
- Actual: "No conversations found to resume"
Evidence
# Sessions exist under the cwd-keyed directory
$ ls ~/.claude/projects/-workspaces-myproject/*.jsonl | wc -l
199
# But the git-resolved directory has no sessions
$ ls ~/.claude/projects/-home-alice-repos-myproject/
memory/ # ← only memory files, zero .jsonl
# The session files are valid and recent
$ ls -lt ~/.claude/projects/-workspaces-myproject/*.jsonl | head -3
-rw------- ... 15:01 f14a6c88-....jsonl # current session
-rw------- ... 14:41 81202388-....jsonl # previous session today
-rw------- ... 14:20 81486591-....jsonl # earlier today
Root cause hypothesis
Claude Code uses at least two different algorithms to compute the project directory key:
cwd-based (used by session writer): Slash-encodes the current working directory →-workspaces-myprojectgit-common-dir-based (used by memory,/resume, permissions per #28248): Follows the worktree.gitpointer to the main repo's.gitdir, derives the parent as the project root →-home-alice-repos-myproject
In a normal (non-worktree) repo, or when the workspace mount path matches the host path, these resolve to the same directory. In a git worktree inside a container where the main repo's .git is mounted at its host path (different from cwd), they diverge.
Note: The devcontainer setup is correct. The main .git dir must be mounted at its original host path because git worktree .git pointer files contain absolute paths written by git worktree add. Git itself handles this correctly — --show-toplevel returns the workspace cwd, not the host path.
Suggested fix
The project directory key should be computed consistently across all subsystems. git rev-parse --show-toplevel is the most correct source — it already handles worktrees correctly and returns the workspace path that matches user expectations, even inside containers with remapped mount points.
Related issues
- #28248 — Permission scoping uses main worktree path instead of current worktree path (confirms
git-common-dircode path exists) - #28019 — Sessions not discoverable across worktrees (session discovery is path-scoped)
- #15776 — Session state lost when worktree deleted
- #19995 —
/resumereports no conversations despite files on disk (may share root cause) - #26123 — General
/resumebugs since v2.1.31 (may be a compounding factor)
Workaround
Symlink the git-resolved project dir to the cwd-keyed one. Add to devcontainer postStartCommand or setup_env.sh:
if command -v git &> /dev/null && [ -f "$WORKSPACE/.git" ]; then
CLAUDE_PROJECTS="$HOME/.claude/projects"
CWD_KEY="${CLAUDE_PROJECTS}/$(echo "$WORKSPACE" | tr '/' '-')"
GIT_COMMON_DIR="$(cd "$WORKSPACE" && git rev-parse --git-common-dir 2>/dev/null)" || true
if [ -n "$GIT_COMMON_DIR" ]; then
GIT_ROOT="$(cd "$GIT_COMMON_DIR/.." && pwd)"
GIT_KEY="${CLAUDE_PROJECTS}/$(echo "$GIT_ROOT" | tr '/' '-')"
if [ "$CWD_KEY" != "$GIT_KEY" ]; then
mkdir -p "$CWD_KEY"
if [ -d "$GIT_KEY" ] && [ ! -L "$GIT_KEY" ]; then
cp -rn "$GIT_KEY"/. "$CWD_KEY"/ 2>/dev/null || true
rm -rf "$GIT_KEY"
fi
[ ! -L "$GIT_KEY" ] && ln -s "$CWD_KEY" "$GIT_KEY"
fi
fi
fiThis issue has 6 comments on GitHub. Read the full discussion on GitHub ↗