
How Claude Code, Codex and Cursor load skills, what really costs context, and how to audit, prune and scope installed skills.
Originally published on KitQuarry. Written by Eliran Kotzero for KitQuarry.
In short: an installed skill costs context in two ways. Its name and description sit in a listing the model sees on every turn. Its full SKILL.md enters the conversation once it's used and stays there. The listing has a budget (1% of the context window in Claude Code, 2% in Codex by default), and when it overflows, descriptions get cut and skills stop triggering. Audit what's installed, turn off what you don't use, make side-effect skills manual-only, move repo-specific skills into the repo, and keep every description short with the trigger words first.
All three tools follow the Agent Skills standard and use progressive disclosure: the model starts with a short entry per skill and reads the rest only when it picks one.
| Tool | At session start | When a skill is used | Listing budget |
|---|---|---|---|
| Claude Code | Name and description of every skill Claude can invoke | Rendered SKILL.md enters the conversation and stays across turns | Scales at 1% of the context window; each entry capped at 1,536 characters |
| Codex | Name, description and file path | Reads the full SKILL.md | At most 2% of the context window, or 8,000 characters if unknown |
| Cursor | Discovers skills and presents them to Agent, which decides when they're relevant | Loads the skill; resources load on demand | Not documented |
So the skill you never use isn't free. Claude Code's docs put it plainly: every skill in the listing adds to your context on every turn, whether or not Claude ever uses it.
| Part of a skill | When it costs context |
|---|---|
name + description (+ when_to_use in Claude Code) | Every turn, for every skill the model can invoke on its own |
Body of SKILL.md | From the moment it's invoked. In Claude Code it stays in the conversation on later turns, so every line is a recurring cost |
Supporting files (references/, examples.md) | Only when the agent reads them |
Scripts (scripts/) | Executed, not loaded. Only their output reaches the context |
Manual-only skills (disable-model-invocation: true) | Claude Code leaves the description out of the listing entirely, so nothing until you type /name |
| Skills preloaded into a Claude Code subagent | The full content is injected when that subagent starts |
The listing is where too many skills hurt. In Claude Code every skill name always stays in it, but when the descriptions don't fit the budget, Claude Code drops descriptions, starting with the skills you invoke least. A skill listed by name only loses the keywords Claude matches against, so it stops triggering on its own. Codex works the same way in its own terms: it shortens descriptions first, and with a large skill set it may leave some skills out of the initial list and show a warning.
After auto-compaction, Claude Code re-attaches each invoked skill but keeps only its first 5,000 tokens, within a combined 25,000-token budget filled from the most recently used skill. Invoke many skills in one long session and the older ones can drop out entirely.
None of the three tools publishes a maximum count, and the number that matters isn't the count. It's whether the descriptions you rely on still fit. Signs you're past it:
/doctor for an estimate of the listing's context cost and its biggest contributors. The Skills row in /context shows the listing's size after the budget is applied. When the listing exceeds its budget, a warning goes to the debug log (claude --debug).You can raise the budget (skillListingBudgetFraction, for example 0.02 for 2%, or SLASH_COMMAND_TOOL_CHAR_BUDGET in Claude Code; skills.max_context_tokens, up to 10,000 tokens, in Codex). That trades context for discoverability. Pruning usually gets you more.
Skills come from more places than most people check. Claude Code loads them from enterprise, personal (~/.claude/skills), project (.claude/skills, from the launch folder up to the repo root), nested subfolders, --add-dir directories, plugins (as /plugin-name:skill-name), and skills synced from your claude.ai account (~/.claude/skills/synced/). Codex reads .agents/skills from the launch folder up to the repo root, ~/.agents/skills, /etc/codex/skills and its bundled system skills. Cursor reads .agents/skills, .cursor/skills and their ~/ versions, and for compatibility also .claude/skills, .codex/skills, ~/.claude/skills and ~/.codex/skills.
/skills lists every skill and groups synced ones under claude.ai sync. /skill-doctor (v2.1.252 or later) shows what each skill costs and how often it's used, flags skills that have never been invoked, and says where to turn them off. Start with the ones that cost the most./skills to see what's available.For a quick look across all three tools' folders, this script lists every SKILL.md visible from the current folder (personal folders, then project folders up to the repo root), sorted by description length, and marks manual-only skills:
#!/usr/bin/env python3
"""List agent skills visible from this folder, with description size and body length."""
import pathlib, re, subprocess
home, cwd = pathlib.Path.home(), pathlib.Path.cwd()
try:
root = pathlib.Path(subprocess.run(["git", "rev-parse", "--show-toplevel"],
capture_output=True, text=True, check=True).stdout.strip())
except Exception:
root = cwd
dirs = [home / d for d in (".claude/skills", ".agents/skills", ".cursor/skills", ".codex/skills")]
p = cwd
while True: # project folders from here up to the repo root
dirs += [p / d for d in (".claude/skills", ".agents/skills", ".cursor/skills", ".codex/skills")]
if p == root or p == p.parent:
break
p = p.parent
rows, seen = [], set()
for d in dirs:
found = (list(d.glob("*/SKILL.md")) + list(d.rglob("SKILL.md"))) if d.is_dir() else []
for f in sorted(found):
if f.resolve() in seen:
continue
seen.add(f.resolve())
text = f.read_text(errors="replace")
m = re.match(r"---\n(.*?)\n---\n?(.*)", text, re.S)
meta, body = (m.group(1), m.group(2)) if m else ("", text)
desc = re.search(r"^description:\s*(.*)$", meta, re.M)
manual = re.search(r"^disable-model-invocation:\s*(true|yes|on|1)\s*$", meta, re.M | re.I)
rows.append((str(d).replace(str(home), "~").replace(str(root), "."), f.parent.name,
len(desc.group(1).strip().strip("\"'")) if desc else 0, body.count("\n") + 1, "manual" if manual else ""))
print(f"{'location':<40} {'skill':<26} {'desc':>5} {'lines':>6}")
for loc, name, dl, lines, flag in sorted(rows, key=lambda r: -r[2]):
print(f"{loc:<40} {name:<26} {dl:>5} {lines:>6} {flag}")
auto = sum(r[2] for r in rows if not r[4])
print(f"\n{len(rows)} skills, {auto} description characters in auto-invocable skills")
Run it with python3 list_skills.py from your project. It reads single-line description: values only, follows symlinked skill folders and counts each target once. It can't see plugin, bundled or enterprise skills, or nested skills below the current folder, so use /skill-doctor for the full Claude Code picture. We tested it on a sample repo; it doesn't call any of the tools.
| Where the skill comes from | To remove it | To keep it but hide it |
|---|---|---|
| Claude Code personal or project | Delete ~/.claude/skills/<name>/ or .claude/skills/<name>/ | skillOverrides, or disable-model-invocation: true |
| Claude Code plugin | /plugin uninstall or disable it in /plugin | Not covered by skillOverrides; manage it in /plugin |
| Synced from claude.ai | Turn it off for your claude.ai account (deleting the folder makes the next sync download it again) | Same |
| Claude Code bundled | disableBundledSkills: true | "off" in skillOverrides |
| Codex local | Delete the folder | [[skills.config]] with enabled = false, then restart |
| Cursor | Delete the folder | disable-model-invocation: true |
Claude Code's skillOverrides has four states. In the /skills menu, highlight a skill and press Space to cycle them, then Esc to save to .claude/settings.local.json:
| Value | Listed to Claude | In the / menu |
|---|---|---|
"on" | Name and description | Yes |
"name-only" | Name only | Yes |
"user-invocable-only" | Hidden | Yes |
"off" | Hidden | Hidden |
// .claude/settings.local.json
{
"skillOverrides": {
"old-helper": "off",
"release-notes": "user-invocable-only",
"legacy-context": "name-only"
}
}
# ~/.codex/config.toml
[[skills.config]]
path = "/home/you/.agents/skills/old-helper/SKILL.md"
enabled = false
Deploy, commit, release and "send a message" skills shouldn't fire on their own anyway. Marking them manual-only also takes them out of the budget in Claude Code, where the description is no longer in context at all.
---
name: deploy
description: Deploys the current branch to staging or production. Only when the user asks to deploy.
disable-model-invocation: true
---
Cursor reads the same field: the skill is included only when you type /skill-name. In Codex, set allow_implicit_invocation: false under policy in the skill's agents/openai.yaml; explicit $skill invocation still works. The Codex docs don't say whether that also removes it from the initial list.
SKILL.md. Keep the body under 500 lines and put API details or long examples in files it links to. They load only when the agent reads them.CLAUDE.md or an always-on rule loads every session, while a skill's body loads only when it's used.The description does two jobs: it's what the model matches your request against, and it's the part every skill pays for on every turn. Claude Code caps each entry's combined description and when_to_use at 1,536 characters, and Codex shortens descriptions when the list is crowded. Both docs say the same thing: put the key use case and trigger words first.
description: This skill is a comprehensive helper that can assist with many aspects of testing, including writing new tests, reviewing existing tests, improving coverage, and general quality work across the codebase.
description: Writes and runs unit tests for changed code. Use when the user asks to add tests, raise coverage, or reproduce a bug with a failing test. Not for end-to-end tests.
The second is shorter and names the requests people actually type. For the full pattern and a test loop, see how to write a SKILL.md that actually triggers.
A personal skill loads in every project on your machine. If you use it in one repo, move it there.
~/.claude/skills, ~/.agents/skills, ~/.cursor/skills): only skills you want in every repo..claude/skills, .agents/skills): skills for this repo, committed so the team gets them..claude/skills below the launch folder at startup; they load the first time Claude reads or edits a file in that subdirectory. Cursor scopes a nested .cursor/skills or .agents/skills to files in its directory. Codex scans from the launch folder up to the repo root, so a skill in services/payments/.agents/skills is picked up when you start Codex in that service.paths frontmatter (Claude Code and Cursor): glob patterns that limit when a skill is used. Claude Code loads it automatically only when working with matching files; Cursor surfaces it only then.---
name: migration-rules
description: Rules for writing database migrations. Use when creating or editing a migration.
paths:
- "db/migrations/**"
---
/skill-doctor in Claude Code (or the script above) and list skills you haven't used in a month.disable-model-invocation: true to every skill with side effects./context or /doctor again, then test the skills you kept in a fresh session.The same thinking applies to instruction files: see why a long CLAUDE.md gets ignored, and for keeping one set of rules across tools, AGENTS.md vs CLAUDE.md. MCP servers have their own per-tool files, covered in one MCP server, three configs.
None of the three tools publishes a maximum. The limit that matters is the skill listing budget. In Claude Code it scales at 1% of the context window, and when the listing overflows, Claude Code drops descriptions, starting with the skills you invoke least. Once a skill's description is gone, Claude can't match your request to it. Run /doctor for the listing's cost and /skill-doctor to find skills you never use.
Their listing entry does. Claude Code's docs say every skill in the listing adds to your context on every turn, whether or not Claude uses it. The SKILL.md body loads only when the skill is invoked. A skill with disable-model-invocation: true is left out of the listing, so it costs nothing until you call it.
In Claude Code, set it to "off" or "name-only" in skillOverrides, or use the /skills menu, which saves to .claude/settings.local.json. Plugin skills ignore skillOverrides, so disable the plugin with /plugin. In Codex, add a [[skills.config]] entry with the SKILL.md path and enabled = false to ~/.codex/config.toml, then restart Codex.
By default the initial list uses at most 2% of the model's context window, or 8,000 characters when the window size is unknown. With many skills, Codex shortens descriptions first and may leave some skills out with a warning. skills.max_context_tokens sets a different budget, up to 10,000 tokens.
Keep only skills you use in every repo in ~/.claude/skills or ~/.agents/skills. Put repo-specific skills in that repo's .claude/skills or .agents/skills, and module-specific ones in a nested folder. Claude Code loads nested skills only once it works on files there, and Cursor scopes nested skills to their directory.
Official docs, checked 2026-10-30.
If you want a starting point, KitQuarry's free sampler is on GitHub: ai-coding-rules-sampler. It has a short CLAUDE.md/AGENTS.md, security rules and three skills (plan-feature, review-changes, record-decisions) for Claude Code, Cursor, Codex and Windsurf. MIT, free. (I made it.)
aiI like AI coding agents. I do not like when they rewrite a file that was already fine, hard-code a...
mcpConnecting 3 to 5 Model Context Protocol (MCP) servers (GitHub, Postgres, Linear, Slack, Notion) into...
aiI use Cursor almost every day. The hard part is not generating code. It is giving the agent enough context, constraints, and a plan so the feature still makes sense after it reaches production.
aiLearn how the Model Context Protocol standardizes AI integrations, with a look at connecting Claude and Cursor to custom environments.
cursorCursor's November 6 changelog entry is short — "Voice Chat with Agents" — but it changes the shape of...
aiWhere you put an instruction decides when the agent sees it and what it costs every turn. Here is a...
Workflows from the Neura Market marketplace related to this Cursor resource