Tutorial1 day ago

We Counted 228 Claude Code Skills and Four in Five Descriptions Get Dropped

Claude Code budgets its skill listing at 1 percent of the context window. We counted 228 skills across four scopes totalling 50,606 characters, 25 times over budget on a 200K model.

The WJS Desk

Sep 1, 2026 · updated 4 hours ago · 7 min read

Photo by Erik Mclean on Pexels

We set out to measure what our six Claude Code skills cost in context. The answer was 1,455 characters, which seemed fine until we learned the budget: the skill listing scales at 1% of the model's context window, so 2,000 characters on a 200K model. Six skills, 73% of the ceiling.

Then we counted everything else on the machine. Project skills, user skills, plugin skills and the legacy commands directory all feed the same listing. 228 entries. 50,606 characters. That is 25 times over budget on a 200K model and five times over on a 1M one, which means roughly four out of five skill descriptions on this machine are being dropped right now.

Nothing errors. Nothing warns you in normal use. The skills are all still there and you can still type their names. They have just stopped being findable.

What you will end up with

A count of what your own skill listing actually costs, the arithmetic for where your ceiling is, and the specific settings that change it. Around 20 minutes, all read-only until the last section.

The two budgets, which are not the same thing

A skill is a directory with a SKILL.md, under .claude/skills/ for a project or ~/.claude/skills/ for you. Frontmatter carries the metadata; everything below it is the body. Only one of those is always in context:

WhatLoadsOur project skills
Name plus description plus when_to_useEvery session, always1,455 chars (~363 tokens)
SKILL.md body and reference filesOnly when invoked29,521 chars (~7,380 tokens)

The on-demand half is 20 times larger and costs nothing until used. That is the entire argument for moving a procedure out of CLAUDE.md into a skill: CLAUDE.md loads every session whether relevant or not, a skill body does not. It also means reference files are free. Our pipeline skill has a 2,343 byte SKILL.md and 10,152 bytes of references beside it, and neither touches the listing.

So the body is not the problem. The listing is, and almost nobody measures it.

Count yours

Only frontmatter counts, and it comes from four places at once:

for scope in \
  ".claude/skills/*/SKILL.md" \
  "$HOME/.claude/skills/*/SKILL.md" \
  "$HOME/.claude/plugins/**/SKILL.md" \
  "$HOME/.claude/commands/*.md"
do
  n=$(ls {scope} 2>/dev/null | wc -l)
  echo "$scope -> $n entries"
done

Then add the description characters. Ours, by scope:

ScopeEntriesListing chars
Project skills61,455
User skills11124,838
Plugin skills5119,568
Legacy commands/604,745
Total22850,606

Against the budget:

Context windowListing budgetOur listingMust be dropped
200K2,000 chars25.3x over48,606 chars
1M10,000 chars5.1x over40,606 chars

The legacy directory is the one people forget. Custom commands were merged into skills, so a file at .claude/commands/deploy.md and a skill at .claude/skills/deploy/SKILL.md both create /deploy and both consume listing budget. Sixty files nobody had thought about in months were still charging rent.

What overflow actually does

Claude Code drops descriptions to fit, starting with the skills you invoke least, so the ones you use daily keep their full text. The listing always contains every name; what disappears is the text Claude matches your request against.

That degradation is precisely backwards from what you want. A skill you invoke by name every day does not need a description, because you are doing the routing. A skill you wrote six months ago and half-remember is the one that needs Claude to recognise the situation, and that is the one that goes dark first.

From the driver's seat this is invisible. Your daily skills keep working, so nothing feels broken. The failure looks like Claude simply not thinking of a skill you have, which reads as a model limitation rather than a configuration ceiling you crossed months ago.

What we found when we looked at the descriptions

Three things, none of which we expected.

Not one skill used when_to_use. Zero of 117. The field exists specifically to carry trigger phrases and example requests, it is appended to the description in the listing, and it shares the same 1,536-character per-entry cap. Every skill on this machine was making description do both jobs.

Eighteen skills exceeded 300 characters against a median of 156. The largest was 816 characters, which is 41% of a 200K model's entire listing budget spent on one entry. That skill is named token-budget-advisor, which we are choosing to read as instructive rather than embarrassing.

One skill parsed to an empty description. A single entry with nothing for Claude to match on, sitting in the listing as a name and nothing else. It had presumably been that way since it was written.

Three ways to buy budget back

Trim, and front-load the use case. Each entry's combined description and when_to_use is capped at 1,536 characters regardless of budget, and Claude matches on that text, so the first clause should say when to reach for the skill rather than what it is. Cutting the eighteen worst offenders on this machine to the 156-character median would recover about 3,000 characters, more than a 200K model's whole budget.

Demote the ones you always invoke by name. Set low-priority entries to name-only in skillOverrides and they list without a description. If you only ever type /deploy, its description is buying nothing and can be freed for skills you want discovered automatically.

Raise the budget deliberately. skillListingBudgetFraction takes a fraction, so 0.02 is 2%. SLASH_COMMAND_TOOL_CHAR_BUDGET sets a fixed character count instead, and skillListingMaxDescChars changes the per-entry cap. At 25x over, no fraction saves you; the fix is fewer and shorter entries.

What broke

We measured the wrong thing first. We counted our project skills, got a comfortable number, and nearly published it. The listing is machine-wide, and a project with six tidy skills inherits whatever else is installed. If you measure only your repo you will conclude you are fine while four fifths of your descriptions are being dropped.

We assumed the listing showed what the file says. It shows the text after the budget is applied. The Skills row in /context reports the post-budget size, so it matches what the model actually receives. Reading your own SKILL.md and assuming Claude sees that description is exactly the wrong check.

Overflow is logged, just not where you look. It writes a warning to the debug log, visible with --debug, and /doctor estimates the listing's context cost and names its biggest contributors. Neither appears in normal use.

Pro tip: Run /doctor before trimming anything. It names the biggest contributors directly, which beats a shell loop and tells you where the budget went rather than where you assume it went.

The compaction detail nobody mentions

Invoked skills survive auto-compaction on a separate budget. Claude Code re-attaches the most recent invocation of each skill after the summary, keeping the first 5,000 tokens of each, with a combined ceiling of 25,000 tokens, filled starting from the most recently invoked.

Two consequences. Invoke many skills in a long session and the earliest ones can be dropped entirely after a compact. And only the first 5,000 tokens come back, so a skill whose non-negotiable constraint sits at the bottom of a long body may lose exactly the part that mattered. Put the rules near the top.

Common mistakes

  • Measuring only the project. The budget is shared across project, user, plugin and legacy command scopes. Ours was 97% not-this-project.
  • Forgetting .claude/commands/. Sixty files still in the listing long after anyone remembered they existed.
  • Padding descriptions with keywords. It reads as thorough and spends a shared budget. Every extra clause is taken from a skill you have not thought about.
  • Skipping when_to_use. Splitting what it does from when to use it costs nothing inside the same cap and makes both halves easier to write. Nobody on this machine had done it.
  • Assuming more skills is strictly better. Every skill taxes the discoverability of every other one. 228 skills is not 228 capabilities, it is 228 names and a few dozen surviving descriptions.
  • Burying the constraint. Compaction keeps the first 5,000 tokens of a skill. A rule at the bottom may not come back.

What we would not do yet

We are not raising skillListingBudgetFraction. At 25x over, doubling the fraction changes nothing except the per-session cost, and the honest fix is deleting skills we do not use. A fixed ceiling is doing useful work anyway: it stops us writing a skill for something that should have been three lines in CLAUDE.md.

We are also not mass-editing 117 descriptions. The eighteen over 300 characters are worth an afternoon; the rest are near the median and would be churn.

The rollback

Everything here reverses. Frontmatter edits are text, skillOverrides and skillListingBudgetFraction are settings keys you can delete, and nothing changes how a skill behaves when invoked directly. The worst case of an over-aggressive trim is a skill Claude stops suggesting, which you notice the first time you type its name.

The number we would leave you with is not ours, it is whatever yours turns out to be. We assumed six skills and found 228, and the gap between those two numbers is the entire point of measuring.

Share

Claude Code budgets its skill listing at 1 percent of context. We counted 228 skills on one machine: 50,606 characters, 25x over. Most descriptions never load. #ClaudeCode #DevTools #AI

Never miss a ship

The best stuff that shipped this week, delivered every Thursday. Free, no spam. We read all the boring stuff so you get the fun parts.

Keep reading