Skip to content
Side Quest

The Skill Budget Trap That Silently Drops Claude Code Skills

by Laith Al-Saadoon2 min read

Updated

  • Claude Code
  • Skills
  • Debugging

Stubbed my toe on a silent-but-deadly issue in Claude Code: if you have many skills installed, some of them are silently dropped from Claude’s awareness. There’s no error, warning, or log; the skills just vanish. Claude still works, but it doesn’t know some of your skills exist.

If you’re a power user of Skills, update ~/.claude/settings.json now:

{
  "env": {
    "SLASH_COMMAND_TOOL_CHAR_BUDGET": "50000"
  }
}

50K is roughly 5% of a 1M-token Opus context window, negligible overhead for full skill visibility. Then run /context in a new session to verify nothing is excluded.

The investigation #

I noticed /erpaval (our autonomous coding methodology skill) failing to activate roughly a third of the time across sessions. Sometimes Claude would say “I’ll use ERPAVal” and then never load the actual skill instructions. Other times it ignored the / invocation entirely.

I searched 40+ project transcript directories across ~/.claude/projects/ and found 14 confirmed failures out of 41 explicit /erpaval invocations. The smoking gun was a session where Claude’s own internal reasoning admitted, “I’ve been doing the exploration myself rather than delegating to agents.” It recognized the methodology by name from training data but never loaded the SKILL.md with the real instructions. It was improvising a degraded version of a skill it couldn’t see.

Root cause #

Claude Code loads skill descriptions via a three-level progressive disclosure system. At startup, only YAML frontmatter (name + description) gets packed into an available_skills block in the system prompt. The full SKILL.md loads on demand when Claude decides a skill is relevant. Supporting files (scripts, templates) load only when referenced.

The catch is that there’s a character budget for that metadata block. The formula is max(context_window × 0.02, 16000) characters. Each skill consumes its description length plus ~109 characters of XML overhead. Exceed the budget and skills get truncated alphabetically. A skill named zz-my-skill disappears before aa-my-skill.

The system inserts a hidden comment, <!-- Showing 42 of 63 skills -->, into the prompt, but nothing surfaces to the user.

I measured our 30 plugin skills: 17,402 total description characters. Default budget: 16,000. We were over by 1,400 characters, enough to silently drop the skills at the tail of the alphabet.

For reference, from community empirical testing by alexey-pelykh:

Avg Description LengthSkills That Fit (16K budget)
263 chars~42 skills
200 chars~52 skills
150 chars~60 skills
130 chars~67 skills
100 chars~75 skills

The lever is either to raise the budget (env var) or to shorten your descriptions. Both work. One Medium author rewrote all their descriptions to under 130 characters and went from 42 visible skills to 67 without changing the budget.

Defense in depth #

Even with the budget fixed, skills can fail to activate in practice because of context competition from MCP tools, large CLAUDE.md files, or the model simply choosing not to use the Skill tool. I built two hooks as an enforcement layer:

A UserPromptSubmit hook detects /skill-name patterns in the prompt and injects a mandatory reminder to call the Skill tool, a proactive nudge before Claude starts working. A Stop + SubagentStop hook forces a grounding self-audit before Claude can finish, checking whether it actually followed the skill’s instructions or went off-script.

One last gotcha: CLAUDE_CODE_MAX_SKILLS is a made-up variable name that gets repeated across community posts. It doesn’t exist. The only relevant env var is SLASH_COMMAND_TOOL_CHAR_BUDGET.

Selective loading is one part of a larger workflow. ERPAVal makes the handoffs between research, planning, execution, and validation explicit.

All Frontier Field Notes