Skip to content

perf(skills): skill listing is 42% over its character budget; ~50 skills lose their descriptions and become undiscoverable #3505

Description

@kyle-sexton

Warning

The figures and the arithmetic below are superseded. Corrected values are in this issue's comments and restated here. Do not work from the original body.

Corrected measurement

My original count globbed find -name SKILL.md recursively. Claude Code discovers skills at skills/<name>/SKILL.md — direct children only — so seven nested files were wrongly included (two playbooks vendor baselines, one playwright, two context7, two docs-hygiene eval fixtures).

Originally stated Correct
Listing-eligible skills 170 163
Combined description + when_to_use 127,944 chars 120,723 chars
Overflow vs the 90,000-char budget (fraction: 0.03) +37,944 (42%) +30,723 (34%)
Mean / median 752 / 710 740 / 730
Max single entry 5,484 1,528
Entries over the 1,536 listing cap 1 0
Entries over the 1,024 spec max 21 20

Withdrawn: the claim that any skill exceeds the 1,536-char listing cap. None do. The 5,484-char outlier was the boris vendor baseline, which is never loaded — see #3506, closed as invalid.

Arithmetic error, corrected: the original body said "170 x 200 = 34,000 chars. That fits inside the default 30,000-char budget." It does not. At the stock fraction: 0.01 the budget is 30,000 chars, so fitting 163 skills there needs a mean of ~184 chars — which is, coincidentally, almost exactly Anthropic's own worked-example length (~176). At 0.03 (90,000) the mean may be up to ~552; at 0.05 (150,000), ~920.

What is actually true and still worth doing

  • Mean description is 740 chars against Anthropic's worked examples at ~176.
  • The fleet is 34% over budget at fraction: 0.03, and Claude Code responds by dropping whole descriptions from the least-invoked skills — roughly 50 skills list as bare names and cannot be keyword-matched.
  • At fraction: 0.05 the fleet fits with 29,277 chars of headroom, so a consumer on 0.05 has no active truncation today. This is therefore a headroom-and-growth problem, not an active-truncation one, for those consumers.

Do not re-derive the per-field half

skill-quality's check already enforces check 2b (DESC_FIELD_CAP=1024, the Agent Skills spec field maximum) as a WARN, added in 0.19.0 via #3119, and the ~19 breaching skills are already known. The "20 entries over 1024" slice is already visible to the repo's own tooling.

What no per-skill check can catch is the aggregate — every one of the 163 is individually under the 1,536 gate and 143 are under 1,024 too. The overflow exists only in the sum, which is exactly why check-listing-budget.sh is advisory and exits 0. That aggregate is what this issue tracks.

Consumer-side lever: measured, and rejected

skillListingMaxDescChars: 400 was trialled and reverted. At fraction: 0.05 no cap is needed, and a 400 cap is actively harmful: of the 163 eligible skills, 160 carry a Use when: trigger block, and in 45 of them it starts past character 400 — so the cap strips routing keywords from 28% of the fleet. Trimming at source, with the key use case first, is the only lever that does not trade one discoverability failure for another.

Verification criterion

Prefer the repo's own tool over a hand count: skill-quality:check listing-budget reports under budget.


Original body — SUPERSEDED by the block above. Kept for the record; do not work from its numbers or checklists.

Summary

The marketplace's skill descriptions are collectively too long. On a machine with the fleet enabled, the skill listing overflows Claude Code's character budget, and Claude Code responds by stripping descriptions from the least-invoked skills — which makes those skills undiscoverable, which keeps them least-invoked. It is self-reinforcing.

This is measured, not inferred.

Evidence

Claude Code's own debug log on an affected machine:

[WARN] Skill listing over budget: 194 skills, 127555 chars > 90000 budget
       — descriptions will be truncated. Run /skills to disable some, or raise skillListingBudgetFraction

Current measurement across the enabled fleet (listing-eligible = excludes disable-model-invocation: true):

Metric Value
Listing-eligible skills 170
Combined description + when_to_use 127,944 chars
Budget (at skillListingBudgetFraction: 0.03) 90,000 chars
Overflow +37,944 chars (42% over)
Mean per skill 752 chars
Median 710 chars
Max 5,484 chars
Skills over 500 chars 135 of 170

Note the budget above is already 3× the default. At the stock 0.01 the budget is 30,000 chars and the fleet is 4.3× over.

when_to_use is not the problem — it totals 215 chars fleet-wide. This is entirely description length.

Why this is the wrong length

Per Skill authoring best practices, the description should state "what the Skill does and when to use it." Anthropic's own worked examples run ~150-200 characters:

description: Extract text and tables from PDF files, fill forms, merge documents. Use when working with PDF files or when the user mentions PDFs, forms, or document extraction.

That is 176 chars. Our fleet mean is 752 — roughly 4× Anthropic's demonstrated style.

The same page states the operative principle directly: "The context window is a public good. Your Skill shares the context window with everything else Claude needs to know, including ... Other Skills' metadata."

Mechanism (why truncation is worse than it sounds)

Per Extend Claude with skills — "Skill descriptions are cut short":

The listing always contains every skill name, but if you have many skills, Claude Code shortens descriptions to fit the listing's character budget, which can strip the keywords Claude needs to match your request. The budget scales at 1% of the model's context window. When the listing overflows, Claude Code drops descriptions starting with the skills you invoke least, so the skills you use most keep their full text.

Observed live in a session with this fleet: roughly 50 skills currently appear as bare names with no description, including testing:* (all 5), work-items:* (all 9), planning:* (7 of 11), review:code-review, review:fanout, review:security-review, toolchain:*, verification:*, and prototype:*. Claude cannot auto-match any of them — they are effectively manual-invocation-only despite not being configured that way.

Worst offenders by plugin (combined listing chars)

   9568   15 skills  mean= 637  discipline
   9266   13 skills  mean= 712  session-flow
   8255    9 skills  mean= 917  work-items
   7954    9 skills  mean= 883  claude-ops
   7785    5 skills  mean=1557  playbooks
   7699   11 skills  mean= 699  docs-hygiene
   7698   11 skills  mean= 699  planning
   6803    9 skills  mean= 755  claude-config
   4425    5 skills  mean= 885  code-tidying
   4206    5 skills  mean= 841  knowledge
   3967    5 skills  mean= 793  discovery
   3599    4 skills  mean= 899  instruction-placement
   3364    3 skills  mean=1121  overengineering

Proposed work

Trim description toward Anthropic's demonstrated shape: what it does + when to use it, key use case first, target ~200 chars, hard ceiling 400.

The current descriptions are long mostly because they carry an exhaustive trigger-phrase list and a "Skip when / Not for" disambiguation block. Those are real information, but they belong in the SKILL.md body, not in always-resident metadata. Keep the highest-signal trigger keywords in the description; move the exhaustive lists and boundary sections into the body.

Suggested ordering (highest chars first): discipline, session-flow, work-items, claude-ops, playbooks, docs-hygiene, planning, claude-config.

Arithmetic: 170 skills × 200 chars = 34,000 chars. That fits inside the default 30,000-char budget at ~200 chars... to be strictly under stock default, target ~176 chars/skill. At a 400-char ceiling the fleet lands at 68,000 chars — comfortably inside the current 90,000 budget with room for growth.

Acceptance criteria

  • No listing-eligible skill has a combined description + when_to_use over 400 chars.
  • Fleet total combined listing text is under 68,000 chars.
  • Every skill's trigger keywords are preserved somewhere — description or body — with no loss of the terms that drive matching (this repo's skill-quality:check has a trigger-keyword-preservation-vs-HEAD check; it should pass).
  • claude --debug on a machine with the fleet enabled no longer logs Skill listing over budget.

Guardrail

Do not achieve the target by deleting trigger keywords — that trades one discoverability failure for another. The win comes from moving prose (rationale, boundary/"skip when" text, exhaustive phrase enumerations) into the body, not from making descriptions vague. Anthropic's guidance explicitly warns against vague descriptions like Helps with documents.

Sources

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    agent-readyFully specified and briefed; eligible for autonomous pickup from the frontier.priority: highSignificant impact, or blocks an imminent release; staff this cycle.work-class: scopedA briefed fix or small feature; blast radius bounded by the brief, tests exist.

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions