[BUG] ~/.claude/commands/ (symlinked onto Windows drvfs) entirely invisible to non-interactively-launched sessions
Environment
- Claude Code v2.1.238
- WSL2 (Ubuntu on Windows 11), NTFS via drvfs
~/.claude/commandsis a symlink to a Windows-side path:/mnt/c/Users/<user>/.claude/commands(a common WSL2 setup — the Windows-side Claude Code install and the WSL2-side one share one.claudeprofile via symlink)
Summary
The entire ~/.claude/commands/*.md directory is invisible to command loading for sessions launched non-interactively (via tmux new-session -d ... claude ..., no TTY attach at launch). Neither /help → Custom commands, nor direct autocomplete (/housekeeping, /xyz), nor fuzzy-match finds any file in that directory — including a brand-new, minimal, correctly-frontmattered test file added specifically to rule out a content-specific trigger.
This may be a different manifestation of the same root cause as #85786 (case-insensitive SKILL.md lookup on Windows filesystems swallowing sibling commands) — same environment class (Windows-mounted, case-insensitive .claude/commands/) — but the exact trigger differs: there is no skill.md/SKILL.md file anywhere in the affected directory, and the failure is total (every top-level file), not a "phantom package + hidden siblings" pattern.
Repro
# On the WSL2 side, ~/.claude/commands is a symlink onto the Windows-side profile:
$ stat ~/.claude/commands
File: /home/<user>/.claude/commands -> /mnt/c/Users/<winuser>/.claude/commands
# Add a minimal, valid command file:
$ cat > ~/.claude/commands/probe.md <<'EOF'
---
description: Minimal probe command.
---
Reply with PROBE_OK.
EOF
# Launch a session non-interactively (no TTY at launch, as a driver/automation would):
$ tmux new-session -d -s probe-test -c /some/project/dir claude --dangerously-skip-permissions
# (accept the one-time Bypass Permissions dialog if prompted)
# Attach or send-keys to check:
$ tmux send-keys -t probe-test '/probe' Enter
# → "No commands match" — /probe is not found.
$ tmux send-keys -t probe-test '/help' Enter
# → Custom commands tab lists zero entries from ~/.claude/commands/.
A project-level .claude/commands/probe.md (a real, non-symlinked directory under the launched session's project_dir, on the same drvfs mount) loads correctly in the same environment, is found by both /help and direct autocomplete, and executes correctly — ruling out drvfs/case-insensitivity as a blanket explanation and pointing specifically at how the symlinked, user-level ~/.claude/commands is (or isn't) resolved/scanned.
What I've ruled out
- Not file-count-limited: only 27 of 28 files were missing; the one survivor (
/close-session) turned out to be shadowed by an unrelated project-level override, not actually loaded from~/.claude/commands/at all. - Not a stale index from before the file existed: reproduced with a session spawned after the probe file was created.
- Not YAML/frontmatter malformation: probe file frontmatter is minimal and valid; other pre-existing files in the same directory have valid frontmatter too (verified
name:/description:present on all but one unrelated file). - Not the exact #85786 trigger: no
skill.md/SKILL.mdfile exists anywhere in the directory.
Possibly relevant
- The symlink target itself is fully readable/valid from the WSL2 side —
cat,ls, and file timestamps all work normally on~/.claude/commands/*.mdfrom a shell. The failure is specific to whatever Claude Code's own command-discovery step does with that path. - This is a very recently (same-day) auto-updated install (2.1.237 → 2.1.238 via background auto-update); I don't have a clean A/B on whether 2.1.237 exhibited the same behavior for non-interactively-launched sessions specifically, since a separate, unrelated bug (a stuck one-time "Bypass Permissions" confirmation dialog) was independently blocking this exact class of launch until immediately before this was found.
Expected
~/.claude/commands/*.md should be discovered and loaded the same way for a tmux-launched, --dangerously-skip-permissions session as for a normal interactive terminal launch, regardless of whether the directory is reached via a symlink onto a case-insensitive filesystem.
Workaround in use
Mirroring the affected command files into the session's project-level .claude/commands/ (which loads reliably) instead of relying on the user-level directory.