[Bug] Duplicate slash commands from symlinked source files

Resolved 💬 3 comments Opened Dec 24, 2025 by klueless-io Closed Dec 27, 2025

Bug Description
Title

Duplicate slash commands appear when symlinks point to same source file

---
Description

When using symlinks to share command files across multiple project directories, the same command appears multiple times in the command palette. Claude Code does not deduplicate based on resolved symlink paths.

Environment

  • OS: macOS (Darwin 24.6.0)
  • Claude Code version: December 2024
  • Shell: zsh

Steps to Reproduce

Directory structure:
/flivideo/
├── .claude/commands/
│ ├── po.md # Original file
│ ├── dev.md
│ ├── brainstorm.md
│ └── ...
├── flideck/.claude/commands/
│ ├── po.md → ../../.claude/commands/po.md # Symlink
│ ├── dev.md → ../../.claude/commands/dev.md
│ └── ...
└── flihub/.claude/commands/
├── po.md → ../../.claude/commands/po.md # Symlink
└── ...

  1. cd /flivideo/flideck
  2. Run claude
  3. Type /po

Actual Result

/brainstorm Brainstorm (project)
/dev /dev — Developer Subagent (project)
/idea-capture Idea Capture (project)
/po /po — Product Owner Subagent (project)
/po /po — Product Owner Subagent (project)
/progress Quick Status (project)
/po /po — Product Owner Subagent (project)
/progress Quick Status (project)
/po /po — Product Owner Subagent (project)

/po appears 4 times. /progress appears 2 times.

Expected Result

Each command should appear once, regardless of how many symlinks point to the same source file.

Context

I'm aware of the Plugin Marketplace and will likely migrate to plugins for proper command distribution. However, symlinks are a common filesystem pattern, and Claude Code should handle them correctly regardless.

The broader issue: symlinked files pointing to the same source should be deduplicated. This applies not just to commands, but potentially to any file discovery (skills, configs, etc.).

Suggested Fix

Before registering a command, resolve the symlink to its canonical path and check if that path is already registered:

const resolvedPath = fs.realpathSync(commandPath);
if (!registeredPaths.has(resolvedPath)) {
registeredPaths.add(resolvedPath);
registerCommand(command);
}

---

Environment Info

  • Platform: darwin
  • Terminal: iTerm.app
  • Version: 2.0.76
  • Feedback ID: 338b9167-e6ab-4136-89c6-1ee7f35b19d1

Errors

[]

View original on GitHub ↗

This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗