/claude-api skill loads the entire multi-language bundle (~230k tokens) instead of the detected project language
Summary
Invoking the claude-api skill with no arguments in a Python project caused the entire bundled skill document — every supported language (C#, Go, Java, PHP, Python, Ruby, TypeScript), plus the full Managed Agents API reference, model migration guide, prompt caching internals, etc. — to be loaded into context as a single ~928 KB / ~230,000-token user message.
This directly contradicts the skill's own stated instructions:
"Choose the right surface based on your needs, detect the project language, then read the relevant language-specific documentation."
Instead of doing language detection first and then reading only the matching section (e.g., just "Claude API — Python"), the base skill invocation appears to dump the whole multi-language reference doc up front, before any detection step runs.
Repro steps
- In a Python project (in my case: two files,
src/logsum.pyandtests/check_logsum.py, no existing LLM integration) - Run
/claude-apiwith no arguments - Observe the first tool-adjacent message injected into context is the full skill bundle, not a language-scoped subset
- Only after that full load does the assistant proceed to
ls,find, and read the two local source files — i.e., actual language detection happens downstream of the expensive load, not before it
Impact
- Unnecessary token spend on every bare
/claude-apiinvocation, scaling with the full size of the bundled doc regardless of which language is actually relevant - In my case, a monthly usage spend limit jumped from ~$49.18 to $57.05 (~$7.87) in the minutes immediately following a single invocation that was cancelled after only 4 quick tool calls (
ls,find, 2xRead) — before any actual code was read for a "surface" decision or written - Worth noting the interrupted session never even got a concrete task (no argument was passed, and the target files had no existing LLM code to modify), so the full-bundle load bought nothing
Expected behavior
Per the skill's own "Language Detection" section, the doc load should be scoped to the detected project language's section (e.g., just the ~2,100-line "Claude API — Python" block) rather than the full ~15,900-line, all-language bundle.
Environment
- Claude Code CLI
- Skill:
claude-api(bundled skill path referenced/tmp/claude-1000/bundled-skills/2.1.233/.../claude-api) - Project: single-file Python script + test, no existing Anthropic/OpenAI SDK usage
4 Comments
Root cause, decompiled from the
2.1.233binary — and it explains why detection failed in your Python project.Language detection reads the top level of the cwd only, non-recursively.
Your files were
src/logsum.pyandtests/check_logsum.py. Neither is at the root, and you had norequirements.txt/pyproject.toml/setup.py/Pipfilethere either — soreaddirsaw onlysrcandtests, matched nothing, and returnednull.So the title is slightly off, and I think in a way that matters for the fix: the bundle wasn't loaded "instead of the detected project language." Detection failed, and the failure branch is what dumps everything:
Each file is then wrapped in
<doc path="...">…</doc>and inlined verbatim. No truncation, no lazy read — the skill declaresallowedTools: ["Read","Grep","Glob","WebFetch"]and ships a "Quick Task Reference" routing table that names the exact file per task, but the docs are pasted in wholesale regardless, so the routing table has nothing left to route.Note the fallback string: it inlines all nine languages' docs and then says "Ask the user which language they are using." It pays maximum context cost precisely in the case where it knows least.
This makes the bug much broader than it looks. Root-only detection fails on any layout that doesn't keep source files or a manifest in the repo root —
src/-layout Python (yours), Cargo/Rust, CMake/C++, Gradle multi-module, monorepos withpackages/*, docs-only repos. I hit it on a C++/CMake repo: root hasCMakeLists.txt,core/,hosts/,docs/and nothing on the marker list, so it takes the samenullpath.Measurements from the on-disk bundle (
bundled-skills/2.1.232/.../claude-api, 65 files):| Bucket | Bytes |
|---|---|
|
shared/| 565,768 || python / typescript / java / go / ruby / csharp / php / curl | 65,659 / 54,833 / 39,450 / 36,916 / 16,239 / 26,355 / 29,118 / 17,962 |
| All 65 files (the
nullbranch) | 852,300 |Single largest file:
shared/model-migration.mdat 174,809 bytes — 20% of the corpus, inlined whether or not you are migrating a model.Two things worth separating in the fix:
readdirshould at minimum be a shallow walk, or fall back to the marker set before giving up. But detection will always miss sometimes.nullbranch is the actual cost bug, and it is fixable independently. "I don't know the language" should inline less, not everything — ask first, or inline nothing language-specific and let the modelReadon demand. It already has the tool and the routing table.And worth flagging even if both land: the success path isn't cheap either. A correctly detected language still inlines all of
shared/— 565,768 bytes, ~210k+ tokens — on top of the language set. Someone asking a one-line pricing question getsshared/models.md(12,146 bytes) plus 553KB they didn't ask for.Prior reports of this same branch, for linking: #83818 is the closest (explicitly identifies the failed-detection path, and additionally observes the
nullgets interpolated into the rendered doc paths as a literalunknown/claude-api/README.mdthat doesn't exist). Also #80190, #81312, #86817, #74473.If you want to size the blast radius from telemetry: the skill emits
tengu_claude_api_skill_loadedwith adetected_langfield — the share of"none"is the answer.@jasonayre — this fully explains what I saw, thank you for digging into the binary. Confirms it: my repo had
src/logsum.pyandtests/check_logsum.py, nothing at root, no manifest file — exactly the shape that hitsreaddirreturning nothing and falling into thenullbranch.Good catch that the framing in my title was backwards — it wasn't "bundle instead of detected language," it was "detection silently failed, and failure is the expensive path." That's a worse bug than I originally described: the fallback should degrade gracefully (ask first, or inline nothing and let the model
Readon demand — it already has the tool and the routing table per your point), not max out cost exactly when it has the least information to justify it.The
shared/finding is useful context too — even in my case, correct detection wouldn't have made this cheap, just less bad. 565KB of shared docs going out regardless of the actual question is its own problem.Given five other issues already hitting this same branch (#83818, #80190, #81312, #86817, #74473), seems like this is well past "one user's edge case" — the
detected_lang: "none"telemetry share you mentioned would be the fastest way for the team to see how often this fires. Hoping this gets prioritized given the recurrence.NP. Ya I was pretty annoyed when my context shot up over 330k+ tokens (had a semi bloated claude.md in my repo I forgot to pull fix from other computer which put me at 500k+ total), when I opened a new (fable) session, asked a single question about api/token cost and it loaded the skill, and I was like, wtf...
I'm not holding my breath given the bot has auto closed the last issue's I've opened after x amount of time; but I did create a thread on the claude discord in hopes that someone will see it and escalate.
<img width="1085" height="990" alt="Image" src="https://github.com/user-attachments/assets/79f92366-ce28-4f6b-a4c4-83ab614d140b" />
This is fixed in 2.1.234: the built-in
claude-apiskill now loads its reference docs on demand instead of inlining them (changelog entry: "Reduced the context cost of loading the built-inclaude-apiskill from ~200k+ tokens to ~25k by loading reference docs on demand").Verified on 2.1.234 (Linux): invoking
/claude-apiin a directory with no language markers (the failed-detection case described above) injects ~73 KB (~18k tokens) with no doc files inlined, and ~92 KB (~23k tokens) in a Python project — versus the ~850–930 KB you measured on 2.1.233. The doc files still ship on disk and are read individually when needed.Changelog: https://github.com/anthropics/claude-code/blob/main/CHANGELOG.md
Closing as fixed — reply here if you still see the whole bundle injected on 2.1.234 or later and we'll reopen.
🤖 Generated with Claude Code
---
_Generated by Claude Code_