Auto-memory creates duplicate project directories when path contains underscores
Description
The auto-memory system creates duplicate project directories under ~/.claude/projects/ when the working directory path contains underscores. This causes memory fragmentation — some memories are saved to one directory, some to the other — with no mechanism to detect or reconcile the split.
Root Cause
The project slug function (found in both cli.js and extension.js) correctly normalizes paths:
function projectSlug(path) {
let slug = path.replace(/[^a-zA-Z0-9]/g, "-");
if (slug.length <= 200) return slug;
let hash = hashFunction(path).toString(36);
return `${slug.slice(0, 200)}-${hash}`;
}
This replaces all non-alphanumeric characters — including underscores — with hyphens. Session .jsonl files are always stored under the correctly slugged directory.
However, the LLM's Write tool calls for auto-memory sometimes compute their own path from the raw cwd (preserving underscores) instead of using the slug-derived path provided in the system prompt. This creates a second project directory containing only a memory/ subdirectory.
Evidence
Working directory: /Users/<user>/code/new_dir/code-review-agents
Two project directories exist:
| Directory slug | Created | Contents |
|---|---|---|
| -Users-...-code-new-dir-code-review-agents (correct, hyphenated) | Mar 9 | 102 items: sessions + memory |
| -Users-...-code-new_dir-code-review-agents (underscore preserved) | Mar 19 | Only memory/ (no sessions) |
This pattern repeated for all 4 projects under the new_dir/ parent:
| Project | Underscore dir | Hyphen dir |
|---|---|---|
| code-review-agents | memory/ only | 102 items (sessions + memory) |
| PM-Local | memory/ only | 68 items |
| expo-apps | memory/ only | 18 items |
| microservice-project | memory/ only | 50 items |
The underscore directories contain only memory/ — no session files — confirming they were created by the LLM's Write tool, not by Claude Code's internal file I/O.
Steps to Reproduce
- Create a working directory with underscores in the path (e.g.,
~/code/my_project/my-repo) - Open Claude Code in that directory
- Interact across multiple sessions so auto-memory writes files
- Inspect
~/.claude/projects/— two directories may exist for the same project
Expected Behavior
A single project directory using the canonical slug, with all sessions and memories co-located.
Actual Behavior
Two project directories:
- Hyphenated slug (correct): contains sessions and some memories
- Underscore-preserving slug (incorrect): contains only
memory/
Memories are fragmented across both. Which directory gets loaded depends on the session, causing inconsistent context. The additionalDirectories setting in .claude/settings.json can further entrench the split by hardcoding one path.
Batch operations like the "dream" consolidation command compound the problem — they write output to one directory while the active session reads from the other, silently losing work.
Impact
- Split-brain memory: sessions see incomplete history, leading to repeated questions and lost preferences
- Silent data loss: consolidation/cleanup operations affect only one directory
- User confusion: no warning when duplicates are created, no tooling to detect or merge them
- Scales with underscores: every project under a parent directory with underscores gets its own duplicate
Suggested Fix
Option A (system prompt): Ensure the memory path surfaced to the LLM always uses the slug function output, so Write tool calls target the canonical directory.
Option B (server-side validation, more robust): When a Write tool call targets ~/.claude/projects/, canonicalize the path segment through the slug function before executing the write:
function canonicalizeProjectPath(writePath) {
const match = writePath.match(/\.claude\/projects\/([^/]+)/);
if (match) {
const canonical = projectSlug(/* resolve slug back to original path or re-slug */);
return writePath.replace(match[1], canonical);
}
return writePath;
}
Option B is more robust since it does not depend on the LLM faithfully copying a path from the system prompt.
Environment
- OS: macOS (Darwin 24.6.0)
- Shell: zsh
- Interface: VS Code extension + CLI
- Claude Code: Latest as of 2026-03-26
This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗