Skip to content

[BUG] Symlinked .md files in .claude/commands/ are silently dropped from autocomplete #55791

Closed as duplicate

Description

@logiqum

Environment

  • Claude Code: 2.1.126
  • Platform: linux (Ubuntu 22.04, Node bundled in binary)
  • Terminal: gnome-terminal / zsh

Bug

Custom slash commands stored as symlinks in .claude/commands/ (or ~/.claude/commands/) never appear in /-autocomplete. Real .md files in the same directory work normally. There is no warning or error in any log — the symlinks are silently dropped during command discovery.

The skill loader handles symlinks correctly. Only the command loader is affected.

Steps to reproduce

mkdir -p /tmp/repro/.claude/commands
cd /tmp/repro

# Real file — appears in autocomplete
cat > .claude/commands/realfile.md <<'MD'
---
description: a real file
---
hello from real file
MD

# Symlink — does NOT appear in autocomplete
echo "hello from symlinked file" > /tmp/source-cmd.md
ln -s /tmp/source-cmd.md .claude/commands/symlinked.md

claude
# type \`/\` and look for slash commands:
#   \`/realfile\`    → present
#   \`/symlinked\`   → MISSING

Expected

Both /realfile and /symlinked should appear, since both resolve to valid .md files.

Actual

Only /realfile appears. /symlinked is silently dropped.

Root cause (verified against 2.1.126 bundle)

The directory walker used by the command loader (cmH, called via _m_ with logLabel: \"commands\") iterates Dirent entries from readdir(..., { withFileTypes: true }) and filters with:

if (O.isFile() && O.name.toLowerCase().endsWith(\".md\")) return $(M, Y)

Dirent.isFile() returns false for symbolic links — even when the target is a regular .md file. So every symlinked command hits the implicit return at the end of the iterator and is skipped silently.

Empirical verification with stock Node:

$ node -e \"
const fs = require('fs');
for (const d of fs.readdirSync('.claude/commands', { withFileTypes: true }))
  console.log(d.name, 'isFile=' + d.isFile(), 'isSymbolicLink=' + d.isSymbolicLink());
\"
realfile.md   isFile=true   isSymbolicLink=false   ← passes filter
symlinked.md  isFile=false  isSymbolicLink=true    ← dropped

Why I'm confident this is an oversight rather than intent

The neighbouring skill loader (Ym7) in the same file uses the correct check:

if (!D.isDirectory() && !D.isSymbolicLink()) return

So the codebase already knows the right pattern — cmH just didn't get it.

Suggested fix (one line)

In cmH, accept symlink dirents the same way the skill loader does. Either:

// Option A — explicit symlink branch, no extra syscalls in the common case
if (O.isFile() || O.isSymbolicLink()) {
  if (O.name.toLowerCase().endsWith(\".md\")) return $(M, Y)
}

Or follow the link with stat to handle symlinked subdirectories too:

// Option B — handles symlinked directories as well
const real = O.isSymbolicLink() ? await K.stat(M).catch(() => null) : O
if (!real) return
if (real.isDirectory()) return A(M, [...Y, O.name])
if (real.isFile() && O.name.toLowerCase().endsWith(\".md\")) return $(M, Y)

Workaround for users hitting this today

Replace the symlinks with real file copies:

cd .claude/commands
for f in *.md; do
  if [ -L \"\$f\" ]; then
    target=\$(readlink -f \"\$f\")
    rm \"\$f\" && cp \"\$target\" \"\$f\"
  fi
done

Trade-off: edits to the source file no longer auto-propagate.

Activity

  1. github-actions commented on May 3, 2026

    @github-actions

    Found 2 possible duplicate issues:

    1. Support symlinks in .claude/commands/ (same as .claude/rules/) #39475
    2. [BUG] Slash commands/skills in .claude/commands/ not discovered when using symlinks (regression) #45547

    This issue will be automatically closed as a duplicate in 3 days.

    • If your issue is a duplicate, please close it and 👍 the existing issue instead
    • To prevent auto-closure, add a comment or 👎 this comment

    🤖 Generated with Claude Code

  2. added
    duplicateThis issue or pull request already exists
    and removed
    bugSomething isn't working
    has reproHas detailed reproduction steps
    platform:linuxIssue specifically occurs on Linux
    on May 7, 2026
  3. github-actions commented on May 7, 2026

    @github-actions

    This issue has been automatically closed as a duplicate of #39475.

    If this is incorrect, please re-open this issue or create a new one.

    🤖 Generated with Claude Code

  4. github-actions commented on Jun 26, 2026

    @github-actions

    This issue has been automatically locked since it was closed and has not had any activity for 7 days. If you're experiencing a similar issue, please file a new issue and reference this one if it's relevant.

  5. locked as resolved and limited conversation to collaborators on Jun 26, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    duplicateThis issue or pull request already exists

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions