Repository navigation
Skill list injected twice per request wastes ~5K–7K tokens of context budget #22236
Description
Description
Every LLM request includes the full skill list twice — once in the system prompt body via SystemPrompt.skills(), and once in the skill tool's description field. With 30+ skills, this costs roughly 5,000–7,000 tokens per request that carry no new information.
How it happens
Injection point 1 — System prompt body (session/system.ts):
Skill.fmt(list, { verbose: true })
// → XML format with <name>, <description>, <location> for each skillInjection point 2 — skill tool description (tool/skill.ts):
Skill.fmt(list, { verbose: false })
// → Compact markdown: "## Available Skills\n- **name**: description"Both are sent in every request. The model sees the same 30+ skills listed in two different formats.
History
- PR tweak: adjust way skills are presented to agent to increase likelyhood of skill invocations. #17053 (2026-03-11) introduced the dual injection — adding
SystemPrompt.skills()while keeping the tool description listing — to increase the likelihood of skill invocations. - PR refactor(session): make SystemPrompt a proper Effect Service #21992 (2026-04-11) formalized the split with
{ verbose: true/false }, with the comment: "the agents seem to ingest the information about skills a bit better if we present a more verbose version here and a less verbose version in tool description".
Impact
For a user with 30+ skills (custom + built-in), the baseline system prompt already exceeds 60,000 tokens before any conversation starts. The duplicated skill list accounts for 8–12% of that overhead. This is especially painful for models with smaller context windows (128K) where it eats 5% of the total budget on day-zero.
Suggested alternatives
- Keep only one injection point. The system prompt version (verbose XML) is likely sufficient — the model doesn't need a second copy in the tool description to know skills exist. The tool description could simply say "Load a skill. Run without arguments to see available skills."
- Lazy-load the skill list. Instead of embedding the full list in every request, inject a short summary (e.g., skill count + top 5 most relevant) and let the model call the
skilltool to get the full list on demand. - Make it configurable. Add a config option like
"skills": { "prompt_injection": "single" | "dual" | "none" }so users can opt out of the duplication.
Measured token counts (approximate)
| Component | Tokens |
|---|---|
| Verbose XML (system prompt, 30 skills) | ~3,500 |
| Compact markdown (tool desc, 30 skills) | ~2,000 |
| Duplication overhead | ~5,500 |
| cc @rekram1-node — you authored the original dual-injection design in #17053. Curious if you've seen measurable improvements in skill invocation rates that justify the token cost, or if a single injection point would work just as well now that models are better at tool use. |
Plugins
No response
OpenCode version
1.4.3
Steps to reproduce
No response
Screenshot and/or share link
No response
Operating System
No response
Terminal
No response
Activity
github-actions commentedon Apr 13, 2026
This issue might be a duplicate of existing issues. Please check:
If your issue adds new information beyond what's already tracked in #13188, please clarify the distinction. Otherwise, consider adding your analysis (token measurements, dual-injection finding) as a comment on that existing issue.
malhashemi commentedon Apr 14, 2026
@rekram1-node How did we end up here? I just came back from a long time off :( we used to have this work wonderfully, each agent only sees the list of allowed to run skills. Now the tool description has the whole skill registry loaded into it for no reason!
/skillcommand (seems to be newly added) injects the content of SKILL.md with no information about active directory. May I get your permission to solve these issues. Heard it got slightly harder to contribute, compared to few months back. Getting better skill invocation comes from better skills descriptions :) not from listing them twice. I do not want my agent to see 100+ skills if I am only allowing the agent to run 5 of them.malhashemi commentedon Apr 14, 2026
@zubingtan Injection point 1 should have the skills to be filtered to only the ones you allow in the agent permission, from what I am seeing so far with point 2 is that it lists everything. Skills got very popular since they first launched, so some sort of lazy loading could be beneficial. However, it heavily depends on how you use OC, if you are a multi agent user you might want to rely on the permission system to limit the skills scope (once the filtering issue fixed).
zubingtan commentedon Apr 15, 2026
@malhashemi Thanks for the context! To add to what you said — in the newer version, the duplication isn't just about the <available_skills> XML block in the system prompt. There's also a separate, full skill list injected into the tool description, making it appear twice per request. A concrete data point: I compared v1.4.3 vs v1.3.7 in Build agent mode by sending a simple
hi. The token consumption jumped from ~20K to ~70K. I asked opencode itself to analyze the context breakdown, and it confirmed the presence of duplicated skill content, plus a large number of tools (bash and others) being injected. This made me think — going forward, opencode really needs a baseline token budget test for trivial tasks (e.g. sendinghiin a fresh session) as part of its regression suite. That way, token regressions like this get caught before shipping, not after.barisgit commentedon Apr 18, 2026
I ran a simple request through a proxy and for a simple hello I get this under skill description:
It is extremely clear that everything is duplicated. By also being in system prompt each skill is essentially defined 3 times
barisgit commentedon Apr 18, 2026
After digging around a bit I see exact same
describeSkill()block in these two files:packages/opencode/src/tool/registry.tspackages/opencode/src/tool/skill.ts