# The Skill Budget Trap That Silently Drops Claude Code Skills

By Laith Al-Saadoon · Published 2026-03-05 · Updated 2026-09-11

Canonical: https://laithalsaadoon.com/notes/skill-budget-trap

Topics: Claude Code, Skills, Debugging

A hidden character budget silently drops Claude Code skills from context. I traced the failures, raised the budget, and added two hooks that enforce skill use.

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.

<a id="the-investigation"></a>

## 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.

<a id="root-cause"></a>

## 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](https://gist.github.com/alexey-pelykh/faa3c304f731d6a962efc5fa2a43abe1):

| Avg Description Length | Skills 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.

<a id="defense-in-depth"></a>

## 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](https://laithalsaadoon.com/notes/erpaval) makes the handoffs between research, planning, execution, and validation explicit.

## Related reading

- https://laithalsaadoon.com/notes/erpaval

- https://laithalsaadoon.com/notes/remarkable-spec

