The Skills My Agent Could Not See

From the guide: Claude Code Comprehensive Guide

I had 84 skills installed and assumed all 84 were working. Five of them were not. swiftui, testing-philosophy, typeset, web-performance, and update-shortcuts-guide were reaching the model as bare names with no description attached, while their files on disk carried perfectly good descriptions. A skill with no description cannot be routed to, because the description is the routing signal. Those five could never auto-activate, and nothing anywhere told me. No error, no warning, no log line. I found them by accident, and the only reason I could prove the cause is that the fix reversed it in front of me.

TL;DR

  • Skill descriptions load into every turn’s context, and they share a fixed character budget. Exceed it and descriptions get dropped silently.12
  • I had 84 skills installed, 82 of which carried descriptions, totaling 21,848 characters. Five arrived with the name present and the description missing. On disk those five had 206 to 336 characters each.
  • No file attribute explained which five got dropped. Description length, file size, YAML format, name/directory mismatch, and modification time all overlapped between the dropped and the kept.
  • I rewrote 74 descriptions down to 9,885 characters total. All five reappeared mid-session, in the same conversation, with descriptions intact. Hypothesis, intervention, confirmation.
  • The exact budget is undocumented and currently disputed. Anthropic has open issues reporting that the fraction gets computed against a fixed 200K baseline while ignoring the 1M context extension.34
  • The rewrite rule that made it fit: a description’s only job is answering when should this be invoked. Procedure, philosophy, and file paths belong in the body, which loads only on invocation.

A Failure With No Error Message

Most harness bugs announce themselves. A hook exits non-zero, an MCP server refuses to start, a tool call returns a stack trace. The description budget does none of that. It quietly serves the model a shorter list than the one on your disk, and every downstream symptom looks like a model problem instead of a plumbing problem.

I noticed by reading my own context window rather than my filesystem. Scanning the skill listing, five entries had a name and nothing after it. Every other entry had a name and a sentence. I pulled the files:

swiftui                    HAS  322 chars on disk -> DROPPED in context
testing-philosophy         HAS  291 chars on disk -> DROPPED in context
typeset                    HAS  248 chars on disk -> DROPPED in context
web-performance            HAS  206 chars on disk -> DROPPED in context
update-shortcuts-guide     HAS  336 chars on disk -> DROPPED in context

The consequence is worse than a skill being slow or wrong. An agent decides whether to invoke a skill by reading its description. Strip the description and you have not degraded routing, you have removed it. The skill is installed, valid, and unreachable. swiftui is my iOS 26 patterns skill, which means every Swift session I ran had been flying without it.

Anthropic has open issues describing the same failure, including one titled “Skill description budget silently truncates routing information, causing skill routing failures.”2 So the behavior is a known bug rather than a local misconfiguration. That was useful to learn, and it did not help me find which of my skills were affected.

Ruling Out the Easy Answers

The tempting move was to guess the mechanism and fix it. I tried to falsify the guesses first, because “five skills are broken” and “five skills are broken for this reason” are very different claims.

If some file-level property marked a skill for dropping, the dropped group should differ from the kept group somewhere measurable. I compared them:

Property Dropped (5) Kept (77)
Mean description length 280 chars 266 chars
Mean file size 9,106 bytes 7,608 bytes
Block-scalar YAML description 2 of 5 30 of 77
name differs from directory 1 of 5 4 of 77
Modification date Jan through Jul Jan through Jul

Nothing separated them. The dropped descriptions were not the longest, the files were not distinctively large, the YAML style was mixed in both groups, and the modification dates spanned the same range. Alphabetical position failed too: skills sorting after swiftui kept their descriptions.

At that point the honest position was that I had a reproducible symptom and no mechanism. So I wrote it down that way and went looking for a test rather than a theory.

The Test

If the total budget is what matters, then cutting the total should restore the dropped descriptions, regardless of which files I cut. That prediction is falsifiable and cheap.

I rewrote 74 descriptions, taking the total from 21,848 characters to 9,885. The five previously-invisible skills came back with descriptions attached, in the same session, without a restart.

That is the whole experiment. One prediction, one intervention, one confirmation. The dropping is a function of aggregate size, not of any property of the individual file, which is exactly why no per-file attribute could distinguish the two groups.

A bug that leaves no trace still leaves a counterfactual. If you cannot find the cause by inspecting the failure, change one variable and see whether the failure follows.

I want to be precise about what I did not establish. I do not know the exact budget, and I am not going to publish a number I cannot source. The official documentation omits the limit.5 Community measurement puts the practical ceiling near 15,500 to 16,000 characters and notes roughly 109 characters of per-entry overhead from XML tags, the skill name, and the location field, none of which a raw description-character count captures.6 With 84 skills, that overhead alone runs about 9,156 characters. Meanwhile Anthropic contributors report the budget fraction gets computed against a fixed 200K baseline and ignores the 1M context extension, so two sessions on the same machine can get different budgets.34

My first pass at writing up this finding claimed my setup was “119% over budget.” I had multiplied an unverified assumption (1% of a 1M window) by a real measurement and produced a confident number with nothing under it. The observed facts survive: 21,848 characters dropped five descriptions, 9,885 dropped none. The percentage did not survive, and it never should have been written.

A Description’s Only Job Is Routing

Cutting 12,000 characters sounds destructive. It was not, because most of what lived in those descriptions was never doing routing work.

Here is what my jiro skill advertised, at 686 characters:

Shokunin craftsmanship philosophy for code quality and professional pride. Activates when implementing features, refactoring code, writing tests, reviewing work, or working on any non-trivial changes across FastAPI/Python, Swift/SwiftUI, HTMX frontends, and infrastructure code. Embeds three core philosophies: Shokunin (excellence in unseen details), Omotenashi (service through craft), Rick Rubin (creative channeling and distillation). Central decision gate: the Evidence Gate (produce proof of quality, not feelings about it). Use when: building features, refactoring, testing, reviewing code, fixing bugs, or any work where quality evidence is required before reporting completion.

Roughly 500 of those characters explain what the skill contains. None of it helps decide whether to open it. The replacement runs 126 characters:

Craftsmanship and evidence standards for code quality. Use when implementing, refactoring, testing, reviewing, or fixing bugs.

Same trigger words, same routing behavior, one fifth the cost. The philosophy did not disappear; it lives in the body, which loads only when the skill actually runs. Paying for it on every turn bought nothing.

The pattern repeated across the whole set. Nine update-*-guide skills carried 3,024 characters of near-identical boilerplate about scanning sources, syncing copies, and running translations. Collapsed to roughly 115 characters each, they still route correctly, because what distinguishes them is which guide they update, not the pipeline they share.

Three rules did the work:

  1. Keep the trigger, cut the explanation. Names, slash commands, and the words a user would actually type stay. Descriptions of internal procedure go.
  2. File paths belong in the body. A path cannot help the model decide when to invoke something.
  3. Shared boilerplate is pure overhead. If nine skills say the same sentence, that sentence distinguishes none of them.

The Second Tax: Descriptions That Act Without Being Called

Trimming exposed a subtler cost. Eleven of my descriptions, 3,808 characters in total, carried imperative language: ALWAYS, NEVER, MUST, PROACTIVELY, BEFORE. distribute said NEVER. no-shortcuts said ALWAYS. git-custody said BEFORE.

Those words sit in context on every single turn whether or not the skill ever runs. They read as instructions because they are written as instructions, and the model has no reliable way to treat a description as inert catalog copy while treating an identically-phrased system instruction as binding.

Recent work names the effect. “The Regression Tax,” measured across roughly 6,000 runs on two office-automation benchmarks and three harness stacks, identifies skill description osmosis: a skill changing agent behavior purely by being present in context, even when never invoked.1 Its headline finding is that the best skills win by regressing less rather than by gaining more, and that skills over-invest in procedural guidance while under-investing in grounding and verification.

The production evidence arrived before the theory. Anthropic walked back auto-activation for the bundled /verify and /code-review skills in v2.1.215, making them explicit-invocation only.7 Two releases later /deep-research stopped self-invoking as well.8 Those are heavyweight skills whose unprompted runs cost more than they earned, which is osmosis observed in the wild by the vendor and corrected by removing the activation rather than rewriting the description.

So an oversized description costs twice. It consumes budget that other skills need for routing, and it exerts behavioral pressure that nobody asked for. Both costs fall on turns where the skill contributes nothing.

The Uncomfortable Part: The Body May Not Govern Either

“Move it to the body” is the advice I just gave, and it carries an assumption worth stating out loud: that a procedure the agent loads on invocation actually governs what the agent does. New benchmark work suggests that assumption is weaker than it sounds.

HANDBOOK.md tested exactly that. Sixty-five tasks, policy documents running 20 to 124 pages, agents working across email, chat, calendars, and commerce in simulated companies, with 824 programmatic grading criteria. The best of thirty model configurations passed 36.2% of trials, and most frontier configurations came in under 25%.9

The named failure modes are the ones that matter here. Agents let a plausible in-environment request override the standing policy. They perform a required check and then act against its result. They lose rule details over long horizons. None of those are retrieval failures; the document was available the whole time.

So the honest version of my rule is narrower than “descriptions route, bodies explain.” Moving procedure out of the description is still correct, because it reclaims budget other skills need for routing and stops uninvoked text from steering behavior. Both of those are real wins and neither depends on the body governing well. What it does not buy you is confidence that the relocated procedure will be followed. A 124-page handbook and a 3,000-word SKILL.md body sit on the same curve.

The practical read: treat body length as a cost, not a free parking space. If a rule genuinely must hold, a description is the wrong place for it and a long body is only a slightly better one. Enforcement belongs somewhere deterministic (a hook, a permission rule, a test), not in prose that a model is asked to remember while doing something else.

Auditing Your Own

Start inside a session. Run /context, which reports whether any skills got excluded.5 If it flags exclusions, you have the problem and you are done diagnosing.

The reason I did not start there is instructive: my five skills were not excluded, they arrived with names intact and descriptions stripped, which is a quieter failure than a missing entry and may not surface the same way. So verify against your filesystem regardless. The check needs no tooling beyond a shell:

python3 - <<'PY'
import os, re, glob
rows = []
for f in glob.glob(os.path.expanduser('~/.claude/skills/*/SKILL.md')):
    name = os.path.basename(os.path.dirname(f))
    fm = re.match(r'^---\s*\n(.*?)\n---\s*\n', open(f, encoding='utf-8', errors='replace').read(), re.S)
    if not fm:
        continue
    d = re.search(r'^description:\s*(.*?)(?=\n[a-zA-Z_-]+:|\Z)', fm.group(1), re.S | re.M)
    if not d:
        continue
    desc = ' '.join(d.group(1).split()).strip('"\'').lstrip('|').strip()
    rows.append((len(desc), name))
rows.sort(reverse=True)
print(f'{len(rows)} skills, {sum(r[0] for r in rows)} description chars')
for length, name in rows[:15]:
    print(f'  {length:4d}  {name}')
PY

Then compare the output against what your model actually received. The gap between the two is the whole finding. If a skill appears in your context with a name and no sentence after it, that skill is installed and unreachable.

Three habits follow from the audit:

Budget every new skill, not just the long ones. Per-entry overhead rides along with each skill regardless of description length, so the tenth 90-character skill costs more than 90 characters.

Re-run the count after adding skills. I cannot give you a safe margin, because the ceiling is undocumented and reportedly varies with how the fraction gets computed.34 An empirical check beats a computed headroom number that rests on an assumption, which is the exact error I made.

Snapshot before you trim. Most of my skill directories were untracked by git, and seven were symlinks into a directory that was not a repository at all, so git add refused them with “beyond a symbolic link.” I wrote every original description to a JSON file first. Version control you have not verified is not a backup.

Key Takeaways

  • A skill without a description is not degraded, it is unreachable. The description carries the entire routing decision.
  • The failure is silent by construction. No error, no warning, no log. Run /context for exclusion warnings, then compare your context listing against your filesystem, because a stripped description is quieter than a missing entry.
  • Aggregate size drives the dropping, not per-file properties. No attribute of the individual file predicted which skills lost their descriptions.
  • When inspection fails, intervene. I could not find the mechanism by examining the failure. Changing the total and watching the failure reverse proved it in one step.
  • Descriptions route; bodies explain. Anything in a description that does not help decide when to invoke is paid for on every turn and earns nothing.
  • Imperatives in descriptions act on you uninvoked. ALWAYS and NEVER steer behavior from the catalog, which is the measured osmosis effect.1
  • Do not publish a percentage you cannot source. My own first write-up multiplied a real measurement by a guessed budget and produced a confident, wrong number.

  1. “The Regression Tax,” arXiv:2607.22520, July 24, 2026. Approximately 6,000 runs across two office-automation benchmarks and three harness stacks. Names three regression modes: skill description osmosis (behavior change from context presence without invocation), grounding displacement, and verification displacement. Headline finding: the best performing skills outperform others primarily by regressing less rather than by gaining more. 

  2. Skill description budget silently truncates routing information, causing skill routing failures, anthropics/claude-code issue #64606. See also Skill descriptions truncated due to context budget constraints, issue #56710. 

  3. skillListingBudgetFraction is calculated against a fixed ~200K baseline, not the model’s actual context window, anthropics/claude-code issue #57941. 

  4. Skill description budget uses base context, ignores [1m] extension, anthropics/claude-code issue #57168. 

  5. Extend Claude with skills, Claude Code documentation. The published documentation does not state a total character budget for skill descriptions. See also Skills docs omit the 250-character cap for /skills descriptions, issue #40121. 

  6. Claude Code skill budget research. Community measurement placing the practical ceiling near 15,500 to 16,000 characters of total skill metadata, with roughly 109 characters of per-entry overhead (XML tags ~85, skill name ~20, location field ~4), and observing that whole entries get hidden rather than individually truncated in the cases measured. 

  7. Claude Code CHANGELOG, v2.1.215, July 2026: the bundled /verify and /code-review skills are no longer self-invoked and require explicit invocation. 

  8. Claude Code CHANGELOG, v2.1.218, July 22, 2026: /code-review runs as a background subagent and /deep-research no longer self-invokes. 

  9. Liudas Panavas, Sebastian Minus, Bradley Monton, Derek Ray, Suhaas Garre, Sushant Mehta, and Edwin Chen, “HANDBOOK.md: A Benchmark for Long-Context Agentic Instruction Following”, arXiv:2607.25398, submitted July 28, 2026. Sixty-five tasks across five domains (finance, medical billing, insurance, logistics, HR) in ten fictional companies, with expert-written standard operating procedures of 20 to 124 pages and 824 programmatic grading criteria. Best of thirty evaluated model configurations passed 36.2% of trials; most frontier configurations remained below 25%. Named failure patterns: letting a plausible in-environment request override standing policy, performing a required check and then acting against its result, and losing rule details over long horizons. 

Related Posts

Context Is the New Memory

Context engineering is the highest-impact skill in agent development. Three compression layers turn a 200K token window …

18 min read

AI Agent Skills Need Behavioral Audits, Not Pass Rates

AI agent skills can change behavior while pass rates stay flat. Behavioral audits compare traces, declared capabilities,…

14 min read

Context Engineering Is Architecture: 650 Files Later

Context engineering for AI agents across a 650-file, seven-layer hierarchy. Three production failures, real token budget…

21 min read