[BUG] Custom skills via symlinked ~/.claude/skills/ directory fail validation but execute correctly
Preflight Checklist
- [x] I have searched existing issues and this hasn't been reported yet
- [x] This is a single bug report (please file separate reports for different bugs)
- [x] I am using the latest version of Claude Code
What's Wrong?
Preflight Checklist
- I have searched existing issues to avoid duplicates
- I have tested with the latest version of Claude Code
- I can reproduce this issue consistently
Environment
- Claude Code version: 2.1.39
- OS: Ubuntu 24.04 (Linux 6.8.0-100-generic x86_64)
- Node.js: v25.1.0
- Shell: bash
Description
When invoking a custom skill defined in ~/.claude/skills/ via slash command (e.g., /jira), Claude Code shows an initialization error Error: Unknown skill: jira before proceeding to execute the skill correctly anyway. The skill directory is symlinked
from a dotfiles repository.
Setup
The ~/.claude/skills/ directory is a symlink to a dotfiles-managed directory:
~/.claude/skills -> /home/user/dotfiles/.claude/skills
Other symlinked configs (CLAUDE.md, settings.json) work without issues. Only skills trigger the error.
Directory structure:
~/.claude/
├── CLAUDE.md -> ~/dotfiles/.claude/CLAUDE.md # ✅ works
├── settings.json -> ~/dotfiles/.claude/settings.json # ✅ works
├── skills -> ~/dotfiles/.claude/skills/ # ⚠️ symlink
│ ├── jira.md
│ ├── outlook.md
│ ├── security.md
│ └── teams.md
└── (no commands/ symlink — source dir exists but is empty)
The skills are referenced in CLAUDE.md under a "Skills Disponibles" section and Claude's system prompt correctly lists them as available (e.g., keybindings-help built-in + custom skills).
Expected Behavior
The skill should be discovered and initialized without errors:
● Skill(jira)
⎿ (skill loads and executes normally)
Actual Behavior
An error is shown during initialization, but the skill executes correctly afterward:
● Skill(jira)
⎿ Initializing…
⎿ Error: Unknown skill: jira
After the error, Claude reads ~/.claude/skills/jira.md and performs the task as expected. This suggests the skill discovery/validation phase does not resolve symlinks, but the execution phase (which reads the file directly) does.
Hypothesis
The skill registry likely uses a method that doesn't follow symlinks when scanning ~/.claude/skills/ for available skills (e.g., fs.readdirSync without { withFileTypes: true } + symlink resolution, or a check using fs.existsSync on the canonical path).
The file read during execution works because it resolves the symlink transparently.
Workaround
Copy the skills directory instead of symlinking:
cp -r ~/dotfiles/.claude/skills ~/.claude/skills
This is not ideal for dotfiles workflows where symlinks are the standard approach for managing configurations across machines.
Related Issues
- #19212
- #18754
---
What Should Happen?
When invoking /jira (or any custom skill), Claude Code should:
- Discover the skill by scanning ~/.claude/skills/, resolving symlinks transparently
- Initialize without errors — recognizing jira.md as a valid skill
- Read the file contents and execute the skill instructions
Currently step 1 fails (Error: Unknown skill: jira) but steps 2 and 3 work correctly after the error. This confirms the file is accessible — the issue is only in the discovery/registration phase which does not resolve the symlink.
Error Messages/Logs
Steps to Reproduce
- Create a dotfiles directory with custom skills:
mkdir -p ~/dotfiles/.claude/skills
echo "# Skill: /jira\nCustom skill content..." > ~/dotfiles/.claude/skills/jira.md
- Symlink the skills directory:
ln -s ~/dotfiles/.claude/skills ~/.claude/skills
- Reference the skill in ~/.claude/CLAUDE.md:
## Skills Disponibles
| Comando | Descripción |
|---------|-------------|
| /jira [tipo] | Generar ticket JIRA |
- Start Claude Code and invoke the skill:
/jira req
Claude Model
Opus
Is this a regression?
I don't know
Last Working Version
_No response_
Claude Code Version
2.1.39
Platform
Anthropic API
Operating System
Ubuntu/Debian Linux
Terminal/Shell
Other
Additional Information
wezrterm terminal
This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗