Slash-command/skill discovery walks node_modules, polluting context with hundreds of fake skills
Problem
Claude Code's slash-command / skill discovery recursively walks the directory tree of ~/.claude/commands (or wherever commandsDirectory resolves to) and treats every markdown-ish file (README, CHANGELOG, LICENSE, SECURITY) as a candidate skill. There's no exclusion mechanism for node_modules/, dist/, build/, .history/, etc.
This is a real footgun for anyone whose slash commands shell out to a Node/TypeScript tool: their skills directory contains a package.json for the tool, npm install populates node_modules/, and then every npm package's documentation files get exposed as fake skills.
Concrete example
My setup: ~/.claude/commands is a symlink to ~/git/individuals/nickmeinhold/claude-skills/. That repo has ~16 legitimate .md slash-commands (/ship, /cage-match, /consolidate, etc.) and a package.json for the /slides command which is implemented in TypeScript.
After npm install, the available-skills list injected into every system-reminder ballooned with entries like:
- node_modules:is-docker:readme: is-docker
- node_modules:typescript:README: TypeScript
- node_modules:googleapis:README: <img src="https://avatars0.githubusercontent.com/...
- node_modules:vitest:LICENSE: Vitest core license
- node_modules:node-domexception:.history:README_20210527213345: DOMException
... (~315 entries total)
Cost
- ~315 fake skill entries, ~80 chars each = ~6,000 tokens per system-reminder injection
- In a long session with 10+ user turns, that compounds to 60k+ tokens of pure noise
- The legitimate skills (~30 entries) get visually buried beneath the noise
What I checked before filing
~/.claude/settings.json— no skill/command path-exclusion field~/.claude/settings.local.json— same- The skills repo has
node_modules/in.gitignore, but Claude Code's discovery doesn't read.gitignore - Docs at https://code.claude.com/docs/en/skills.md and https://code.claude.com/docs/en/settings.md — no mention of an exclusion mechanism
My workaround
Move the slides build (and its node_modules/) into a sibling git repo (~/git/individuals/nickmeinhold/claude-slides/) outside the symlinked discovery tree. Update the slash-command's npx --prefix to point at the new location.
This works but feels architecturally weird — it forces the implementation of a slash-command to live outside the directory you'd naturally store the slash-command in.
Proposed fix
One of:
- Auto-exclude conventional dependency/build directories during command discovery:
node_modules/,dist/,build/,.history/,coverage/,.git/,target/,__pycache__/,.next/,vendor/. Low-config, high-leverage.
- Honor
.gitignorewithin the discovery tree (matching git's semantics). Already-trained intuition for any developer.
- Add a
commandIgnore/skillIgnoresetting insettings.jsontaking glob patterns:
``json``
{
"skillIgnore": ["**/node_modules/**", "**/dist/**", "**/.history/**"]
}
Of these, (1) plus (2) seems best — sensible defaults, with .gitignore for project-specific tweaks.
Severity
Medium. Doesn't break functionality, but silently consumes a large fraction of every long session's context budget. Easy to miss because the system-reminder block is collapsed/compressed in the UI.
Environment
- Claude Code CLI (recent version, late April 2026)
- macOS Darwin 25.3.0
- Affected since I added a TypeScript slash-command tool. Estimated impact: any user whose
~/.claude/commandsincludes a Node/Python project.
This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗