With 160 skills installed, Claude Code kept 20 descriptions, and the model found 0 of 3 skills that lost theirs A developer tested Claude Code 2.1.289 with 160 installed skills and found that when the skill listing exceeded its 30,000-character budget on a 1M-token Opus 5.5 session, only 20 of 160 skills kept their descriptions while all names were retained. In headless runs, the model invoked 0 of 3 target skills that were listed by name only, versus 7 of 7 that still had descriptions, confirming that dropped descriptions make skills effectively unselectable by the model. With Opus 5.5's 1M-token window, Claude Code 2.1.289 held the skill listing to 30,000 characters. Of 160 project skills with 1,000-character descriptions, 20 kept their descriptions 22 of 40, 21 of 80 and every name stayed, but the model invoked 0 of 3 target skills that were listed by name only, against 7 of 7 that still had descriptions. Every skill you install adds a line to the model's context on every turn: the skill's name and its description. When the model decides on its own whether a request calls for a skill, the description is all it has to go on. The skills page of the Claude Code docs says this listing has a character budget that "scales at 1% of the model's context window", and that once the listing overflows, Claude Code drops descriptions "starting with the skills you invoke least". We wanted three things the page doesn't give: the budget as an actual number for a default Opus session, the order in which descriptions really go, and what happens to a request that should have triggered a skill whose description was dropped. So we built a lab with 10, 40, 80 and 160 dummy skills, ran Claude Code headless 38 times, and read the listing each session recorded in its transcript. Everything below ran on 2026-10-05 UTC with Claude Code 2.1.289 claude --version and claude-opus-5-5 , selected with --model opus . The documentation quotes come from https://code.claude.com/docs/en/skills.md , settings-reference.md , env-vars.md and model-config.md , all fetched that day between 16:20 and 16:21 UTC. The skills page covers the listing in its troubleshooting section, under "Skill descriptions are cut short". These are the sentences we tested, quoted as fetched: --debug ." skillListingBudgetFraction setting for example, 0.02 = 2% or the SLASH COMMAND TOOL CHAR BUDGET environment variable to a fixed character count. To free budget for other skills, set low-priority entries to "name-only" in skillOverrides so they list without a description. You can also trim the description and when to use text at the source: put the key use case first, since each entry's combined text is capped at 1,536 characters regardless of budget. The cap is configurable with skillListingMaxDescChars ." The settings reference adds what a dropped description costs. Under skillListingBudgetFraction : "When the listing is over the cap, Claude Code keeps every skill's name but drops the descriptions of the least-used skills, so Claude can still invoke those skills but is less likely to choose one on its own." Its default is given as " 0.01 , which reserves 1% of the context window", and skillListingMaxDescChars defaults to 1536 . The environment variable reference describes SLASH COMMAND TOOL CHAR BUDGET this way: "Override the character budget for skill metadata shown to the Skill tool. The budget scales dynamically at 1% of the context window, with a fallback of 8,000 characters. Legacy name kept for backwards compatibility". The changelog has some history behind those numbers. Cut at its own heading, the 2.1.32 section says "Skill character budget now scales with context window 2% of context , so users with larger context windows can see more skill descriptions without truncation", and the 2.1.105 section says "raised the listing cap from 250 to 1,536 characters". The docs and the default setting now say 1%; we found no changelog line announcing a move from 2% to 1%. OpenAI's Codex documents a similar budget. Its skills page at https://developers.openai.com/codex/skills fetched 2026-10-05 16:21 UTC says: "In Codex, the initial list also includes each skill's file path. To avoid crowding out the rest of the prompt, this list uses at most 2% of the model's context window, or 8,000 characters when the context window is unknown. If many skills are installed, Codex shortens skill descriptions first. For large skill sets, Codex may omit some skills from the initial list and show a warning." we measured only Claude Code, so everything we say about Codex in this article comes from that page. What neither product's page tells you is how many characters "1% of the context window" comes to, given that the window is counted in tokens. That was the first thing the lab had to answer. The lab is a set of fresh directories, each holding nothing but .claude/skills/ . A small Python script writes N skills named lab-sk-001 to lab-sk-N . Each SKILL.md has a name , a 1,000-character description and a one-line body: --- name: lab-sk-001 description: "CW001A Recalibrates the amber ledger for the build. Use when the user asks to recalibrate the amber ledger, mentions a drifted amber ledger, or wants the amber ledger checked before a release. It reads the files the user points at, checks them against the team's written conventions, filler repeated up to 1,000 characters CW001Z" --- When this skill runs, reply with the single token BODY001 and nothing else. Every description starts and ends with a codeword of its own CW001A and CW001Z , so we could tell from the model's answer whether a description arrived whole, arrived cut short, or didn't arrive at all. Every skill also gets its own trigger phrase "amber ledger", "basalt ledger" and so on , built from twenty adjectives and eight nouns. One skill, lab-sk-002 , gets a 2,000-character description to test the 1,536-character cap. We built the set at 10, 40, 80 and 160 skills. Each listing run sent the same prompt: Do not use any tools. Look at everything in your context for this turn, including the list of available skills. List every token that begins with the two letters CW followed by three digits and one letter, in the order they appear, separated by single spaces. If there are none, reply NONE. Reply with that single line only. And each run was one invocation: claude -p "$PROMPT" --setting-sources project,local --strict-mcp-config \ --tools Skill --max-turns 1 --model opus --output-format stream-json --verbose \ --session-id "$SID" --debug-file "runs/$NAME/debug.txt" < /dev/null --setting-sources project,local keeps our user settings, and the plugins they enable, out of the runs. --strict-mcp-config with no config file means no MCP servers. We also unset the environment variables that the Claude Code session we were working from exports CLAUDECODE , CLAUDE CODE SESSION ID , CLAUDE EFFORT , CLAUDE CODE AUTO COMPACT WINDOW and about ten more , so the child runs did not inherit them. --tools Skill matters. Our first pilot used --tools "" to keep the model from reading files, and the model answered NONE. That transcript had no skill listing at all, and the first request was only 2,748 tokens. The listing is attached only when the Skill tool is available, so every later run allows that one tool and nothing else. The evidence for each run comes from three places. The first is the transcript at ~/.claude/projects/