Project picker shows duplicate Recent rows for one folder due to path-casing (case-insensitive APFS): /Dev vs /dev
Summary
The desktop app's project picker ("Recent" list) shows duplicate rows for the same project — one under /Users/<user>/Dev (real, uppercase D) and a ghost under /Users/<user>/dev (lowercase). On a case-insensitive APFS volume these are the same inode (one folder on disk), so the lowercase row points at a path that does not independently exist.
Environment
- macOS, case-insensitive APFS (default)
- Claude desktop app (Electron), project picker / FleetView
Steps to reproduce
- On a case-insensitive volume, at some point open/launch a project using a lowercase path (e.g. typed in chat, a shell
cd, or a tool result that contains/Users/<user>/dev/foo). - Open the project picker.
- The project appears twice: once under
…/Dev/fooand once under…/dev/foo.
What I expected
The picker should normalize path casing (or dedupe by resolved inode) so one on-disk folder yields exactly one row.
What actually happens
Two rows per project. Notably:
- The duplication is per-project and tied to projects that were opened before the casing issue was understood; a newer project only ever opened via the uppercase path shows a single row.
- The ghost rows are not sourced from
~/.claude.json(cleaning theprojectsdict there does not remove them) nor from theclaude-code-sessionsstore (allcwd/originCwdvalues are uppercase). They appear to be persisted in the app's IndexedDB recents store (~/Library/Application Support/Claude/IndexedDB/https_claude.ai_0.indexeddb.*), which is why config-level cleanups never fix it.
Why it's stubborn / data-risk note
On case-insensitive APFS, /Dev and /dev resolve to the same inode. Users (or agents) attempting to "clean up" the lowercase path on disk risk rm -rf-ing the real project folder. Please fix by normalizing/deduping casing in the recents store, not by anything that touches the filesystem. A built-in "these two recents resolve to the same inode, collapse them" pass would prevent both the cosmetic dupes and the footgun.
Suggested fix
- Canonicalize project paths (resolve real-path + case) before writing to the recents object store, and dedupe existing entries by resolved inode on load.
This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗