[BUG] Internal project path key inconsistency in git worktrees inside devcontainers — sessions and memory stored under different keys, /resume finds nothing

Resolved 💬 6 comments Opened Mar 12, 2026 by stephs-repos Closed Apr 14, 2026

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:

  1. The workspace is mounted at /workspaces/myproject
  2. The main repo's .git dir is bind-mounted at its host path /home/alice/repos/myproject/.git (required so the worktree .git pointer resolves correctly inside the container)
  3. /workspaces/myproject/.git is 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

  1. Create a git worktree on the host, open it in a devcontainer
  2. Start Claude Code CLI, have a conversation, exit
  3. Start a new session, type /resume
  4. Expected: Previous sessions appear in picker
  5. 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:

  1. cwd-based (used by session writer): Slash-encodes the current working directory → -workspaces-myproject
  2. git-common-dir-based (used by memory, /resume, permissions per #28248): Follows the worktree .git pointer to the main repo's .git dir, 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-dir code path exists)
  • #28019 — Sessions not discoverable across worktrees (session discovery is path-scoped)
  • #15776 — Session state lost when worktree deleted
  • #19995 — /resume reports no conversations despite files on disk (may share root cause)
  • #26123 — General /resume bugs 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
fi

View original on GitHub ↗

This issue has 6 comments on GitHub. Read the full discussion on GitHub ↗