/add-dir writes a persistent, bidirectional project→project link (.session-aliases) that merges an entire other project's sessions into /resume

Open 💬 0 comments Opened Jul 9, 2026 by alberduris

Environment

  • Claude Code v2.1.205 (native installer build)
  • macOS, Darwin 23.6.0
  • Reproduces in a plain terminal and in the VS Code integrated terminal

Summary

The docs state the picker shows, by default, "sessions from the current worktree, plus sessions started elsewhere that added the current directory with /add-dir."

In practice, once you /add-dir B while working in project A — even as a session-only add (not "remember", it doesn't touch settings.local.json) — Claude Code writes a persistent link into a hidden file, and the picker then merges all of B's sessions into A's picker (and, bidirectionally, all of A's into B's). It is per-project, not per-session; persistent, not session-scoped; and bidirectional.

Mechanism / root cause

~/.claude/projects/<sanitized-A>/.session-aliases is a newline-delimited list of other project folders whose sessions get merged into A's resume picker. /add-dir (and resuming a session from another directory) appends the other project's folder path to it. The picker (loadSameRepoMessageLogsgetStatOnlyLogsForWorktrees) then reads those folders wholesale.

Empirical proof via --debug-file, run from project A:

/resume: loading sessions for cwd=/…/project-a, worktrees=[/…/project-a]
/resume: found 600 session files on disk

Project A has 18 own sessions on disk. The other 582 are project B's entire history. Emptying A/.session-aliases and re-running → found 18. So a single shared /add-dir pulled in 582 unrelated sessions, of which exactly one had ever added the current directory.

Steps to reproduce

  1. cd project-a && claude/add-dir /abs/path/to/project-b → exit.
  2. cd project-a && claude --resume → the default view (not Ctrl+A) now lists all of project-b's sessions.
  3. cd project-b && claude --resume → lists project-a's sessions too (bidirectional).
  4. Survives restarts. cat ~/.claude/projects/<sanitized-a>/.session-aliases shows project-b's folder path.

(Sanitized folder = the project's absolute path with non-alphanumeric chars replaced by -.)

Expected

Per the docs, only the specific session(s) that actually added the current directory via /add-dir should surface — not the entire other project.

Problems this causes

  1. Granularity: docs promise "sessions … that added the current directory" (per-session); the code merges the whole project folder (per-project).
  2. Scope: a session-only /add-dir produces a permanent link.
  3. Direction: adding B while in A also makes A appear in B's picker — never requested.
  4. Visibility: stored in a hidden, misleadingly named file (.session-aliases reads like Ctrl+R rename aliases, but it holds folder paths); not surfaced by /add-dir, /permissions, /config, or ~/.claude.json; no UI to inspect or remove it. Effectively undebuggable.
  5. No pruning: links never expire; stale .session-aliases.bak files can even resurrect old links.

Suggested fix (take with a grain of salt, fix it however you want)

  • Key the association by session, not by project folder. Transcripts already record every cwd/added directory per line, so the picker can surface exactly the sessions that touched the current dir — self-cleaning, no side file needed. If a persisted index is wanted for performance, store foreign session references, not foreign project folders.
  • Don't persist a link for a session-only /add-dir.
  • Make it one-directional (or make the reverse an explicit opt-in).
  • Give it a management surface (related: #27935 requests /remove-dir) and an honest filename.

Workaround

rm ~/.claude/projects/<sanitized-project>/.session-aliases

Not a duplicate

Distinct from the "shows ALL projects by default" regression (#46887, #46445, #46688, #46784). This is the specific /add-dir link that merges one other project's sessions wholesale, persistently, and bidirectionally, via .session-aliases.

View original on GitHub ↗