[BUG] Skill loader silently drops project-level SKILL.md files when total exceeds ~120 (137 files → 116 available)

Resolved 💬 3 comments Opened May 14, 2026 by hmoriya Closed May 18, 2026

Summary

In a project with a large number of project-level skills under .claude/skills/**/SKILL.md (137 in our case), Claude Code's skill loader silently drops a non-trivial subset (~21 files, ~15%) from the session's available skills list. Affected skills cannot be invoked via the Skill tool (returns Unknown skill: <name>) even though:

  • SKILL.md exists at a valid path (.claude/skills/{category}/{name}/SKILL.md)
  • frontmatter is structurally identical to other working skills (name, description, user-invocable: true, allowed-tools, role all present)
  • the same project loads 116/137 skills successfully — there is no parse error reported anywhere

The dropping appears non-deterministic across path/alphabet ordering, and we have not been able to identify a frontmatter property that distinguishes loaded vs. dropped skills.

Reproduction

Tested in archway/archway_harness (a framework repository with extensive project-level skills).

# 1. Total SKILL.md files on disk
find .claude/skills -name SKILL.md -type f | wc -l
# → 137

# 2. With user-invocable: true
grep -l "^user-invocable: true" .claude/skills/*/*/SKILL.md | wc -l
# → 136

# 3. Run a structural validator (in-repo) — all PASS
python3 .parasol/validators/skill-registry-check.py --stage 3
# → SKILL-REGISTRY-001 PASS: 137 skills, no violations.

Then in a fresh Claude Code session (CLI v2.1.142, macOS 26.4.1 / Darwin 25.4.0), the available skills section of the system prompt contains ~116 entries. 21 SKILL.md files are silently missing.

Comparison of loaded vs. dropped skills

Both have identical frontmatter shape:

# .claude/skills/parasol/parasol7.context/SKILL.md   ← LOADED
---
name: parasol7.context
description: Parasol V7 Phase 1: コンテキスト理解 — 組織・市場・ステークホルダー分析
user-invocable: true
allowed-tools: Read, Write, Edit, Glob, Grep, Bash
role: planner
---
# .claude/skills/parasol/parasol7.inception/SKILL.md   ← DROPPED
---
name: parasol7.inception
description: Phase 1.5 インセプションデッキ — Phase 1 分析結果を顧客すり合わせ形式に変換し、Phase 2 への合意ゲートとする
user-invocable: true
allowed-tools: Read, Write, Edit, Glob, Grep, Bash
role: planner
---

Both files:

  • live in the same parent directory (.claude/skills/parasol/)
  • have a valid workflow.md sibling
  • were added in the same git commit

But only parasol7.context appears in available skills; parasol7.inception returns Unknown skill: parasol7.inception when invoked via the Skill tool.

Sample of dropped skills (15 of ~21)

.claude/skills/parasol/parasol7.backflow/SKILL.md
.claude/skills/parasol/parasol7.bo-detail/SKILL.md
.claude/skills/parasol/parasol7.complete-phase/SKILL.md
.claude/skills/parasol/parasol7.consult-chef/SKILL.md
.claude/skills/parasol/parasol7.full-design/SKILL.md
.claude/skills/parasol/parasol7.golden-thread/SKILL.md
.claude/skills/parasol/parasol7.imagination-detect/SKILL.md
.claude/skills/parasol/parasol7.inception/SKILL.md
.claude/skills/parasol/parasol7.inheritance/SKILL.md
.claude/skills/parasol/parasol7.necessity-check/SKILL.md
.claude/skills/parasol/parasol7.quality-gate/SKILL.md
.claude/skills/parasol/parasol7.quick-start/SKILL.md
.claude/skills/parasol/parasol7.testspec/SKILL.md
.claude/skills/parasol/parasol7.trace/SKILL.md
.claude/skills/parasol/parasol7.usecase/SKILL.md

Expected Behavior

One of the following:

  1. All 137 SKILL.md files with user-invocable: true are loaded and discoverable via the Skill tool, OR
  2. A clear error / warning is emitted to the session (or to a debug log) when a SKILL.md is rejected — currently the drop is silent, which makes it impossible to debug from the user side
  3. Document the registry capacity / discovery semantics (any total limit, ordering, parse rules) so framework authors can stay within bounds intentionally

Actual Behavior

  • 21 SKILL.md silently absent from the session's available skills list
  • No warning, no debug message, no failure indicator
  • Skill: <dropped-skill-name> returns Unknown skill: <name> at invocation time
  • Users / agents fall back to manually Read-ing the workflow.md, which bypasses framework registration and re-introduces drift the framework was designed to prevent

Investigation Notes

The downstream project (archway_harness) has an in-repo validator (.parasol/validators/skill-registry-check.py, Closes #1688) that verifies:

  • R-1: SKILL.md existence at every skill directory
  • R-2: required frontmatter fields (name / description / user-invocable / allowed-tools / role)
  • R-3: name ↔ path basename consistency
  • R-4: name uniqueness
  • R-5: workflow.md reference validity

All 137 SKILL.md PASS this validator at stage 3 (strict). So the issue is not on the SKILL.md authoring side.

The repro tracking issue downstream: https://github.com/archway/archway_harness/issues/1787 (with previous fixes #1544, #1688 that addressed adjacent symptoms but not the drop-on-overflow root cause).

Hypotheses (unconfirmed)

  1. Total skill count limit — Claude Code may cap project-level skills at ~120 to prevent excessive system-prompt growth. If so, this should be documented and ideally configurable.
  2. Per-directory or per-category limit — possibly an enumerator that stops early in deep directory trees
  3. Token budget on system prompt — skills loaded until a token threshold is hit, then truncated silently
  4. Frontmatter parser edge case with multi-byte description text (all our affected skills use Japanese description)

We could not narrow it down further without access to the loader source / a debug flag.

Workaround

We are currently:

  • Falling back to manually Read-ing workflow.md from within other skills (defeats the purpose of user-invocable)
  • Considering archiving deprecated skills to reduce total count below the apparent threshold

Neither is sustainable for a framework that grows over time.

Request

Any of these would help downstream framework projects:

  1. A documented hard limit (e.g. "max 128 project-level skills per session") so we can architect within it
  2. A claude debug skills subcommand that prints the discovered/loaded/dropped lists with reasons
  3. A non-silent failure mode when SKILL.md is rejected (write to stderr or a .claude/logs/ file)
  4. An override config like .claude/settings.json"skills.maxProjectSkills": 200 for projects that knowingly need more

Environment

  • Claude Code CLI: v2.1.142
  • OS: macOS 26.4.1 (Darwin 25.4.0, arm64 / Apple Silicon)
  • Project size: 137 SKILL.md files across 11 categories under .claude/skills/
  • Tested in: fresh claude session in repo archway/archway_harness @ commit f78574fb (main)
  • Behaviour reproduced in: a mirror repository (saibugas_webportal_chef) with the same .claude/skills/ structure — same skills dropped

Thank you for looking into this — happy to provide additional diagnostics if there is a debug flag we can enable.

View original on GitHub ↗

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