Skip to content

Skill list injected twice per request wastes ~5K–7K tokens of context budget #22236

Closed

Description

@zubingtan

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 skill

Injection 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

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

  1. 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."
  2. 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 skill tool to get the full list on demand.
  3. 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

  1. added
    coreAnything pertaining to core functionality of the application (opencode server stuff)
    perfIndicates a performance issue or need for optimization
    on Apr 13, 2026
  2. github-actions commented on Apr 13, 2026

    @github-actions
    Contributor

    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.

  3. malhashemi commented on Apr 14, 2026

    @malhashemi
    Contributor

    @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! /skill command (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.

  4. malhashemi commented on Apr 14, 2026

    @malhashemi
    Contributor

    @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).

  5. zubingtan commented on Apr 15, 2026

    @zubingtan
    Author

    @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. sending hi in a fresh session) as part of its regression suite. That way, token regressions like this get caught before shipping, not after.

  6. barisgit commented on Apr 18, 2026

    @barisgit

    I ran a simple request through a proxy and for a simple hello I get this under skill description:

    Load a specialized skill that provides domain-specific instructions and workflows.
    
    When you recognize that a task matches one of the available skills listed below, use this tool to load the full skill instructions.
    
    The skill will inject detailed instructions, workflows, and access to bundled resources (scripts, references, templates) into the conversation context.
    
    Tool output includes a `<skill_content name=\"...\">` block with the loaded content.
    
    The following skills provide specialized sets of instructions for particular tasks
    Invoke this tool to load a skill when a task matches one of the available skills listed below:
    
    ## Available Skills
    - **agent-browser**: Browser automation CLI for AI agents. Use when the user needs to interact with websites, including navigating pages, filling forms, clicking buttons, taking screenshots, extracting data, testing web apps, or automating any browser task. Triggers include requests to \"open a website\", \"fill out a form\", \"click a button\", \"take a screenshot\", \"scrape data from a page\", \"test this web app\", \"login to a site\", \"automate browser actions\", or any task requiring programmatic web interaction.
    - **cartography**: Repository understanding and hierarchical codemap generation
    - **openspec-apply-change**: Implement tasks from an OpenSpec change. Use when the user wants to start implementing, continue implementation, or work through tasks.
    - **openspec-archive-change**: Archive a completed change in the experimental workflow. Use when the user wants to finalize and archive a change after implementation is complete.
    - **openspec-bulk-archive-change**: Archive multiple completed changes at once. Use when archiving several parallel changes.
    - **openspec-continue-change**: Continue working on an OpenSpec change by creating the next artifact. Use when the user wants to progress their change, create the next artifact, or continue their workflow.
    - **openspec-explore**: Enter explore mode - a thinking partner for exploring ideas, investigating problems, and clarifying requirements. Use when the user wants to think through something before or during a change.
    - **openspec-ff-change**: Fast-forward through OpenSpec artifact creation. Use when the user wants to quickly create all artifacts needed for implementation without stepping through each one individually.
    - **openspec-new-change**: Start a new OpenSpec change using the experimental artifact workflow. Use when the user wants to create a new feature, fix, or modification with a structured step-by-step approach.
    - **openspec-onboard**: Guided onboarding for OpenSpec - walk through a complete workflow cycle with narration and real codebase work.
    - **openspec-sync-specs**: Sync delta specs from a change to main specs. Use when the user wants to update main specs with changes from a delta spec, without archiving the change.
    - **openspec-verify-change**: Verify implementation matches change artifacts. Use when the user wants to validate that implementation is complete, correct, and coherent before archiving.
    - **simplify**: Simplify and refine recently modified code for clarity and consistency. Use after writing code to improve readability without changing functionality.
    - **vast-ai-llm**: Deploy and manage self-hosted LLMs on Vast.ai GPU instances. Use when the user wants to rent GPUs, run vLLM/SGLang inference servers, manage Vast instances, configure SSH tunnels, or troubleshoot GPU server issues.
    Load a specialized skill that provides domain-specific instructions and workflows.
    
    When you recognize that a task matches one of the available skills listed below, use this tool to load the full skill instructions.
    
    The skill will inject detailed instructions, workflows, and access to bundled resources (scripts, references, templates) into the conversation context.
    
    Tool output includes a `<skill_content name=\"...\">` block with the loaded content.
    
    The following skills provide specialized sets of instructions for particular tasks
    Invoke this tool to load a skill when a task matches one of the available skills listed below:
    
    ## Available Skills
    - **agent-browser**: Browser automation CLI for AI agents. Use when the user needs to interact with websites, including navigating pages, filling forms, clicking buttons, taking screenshots, extracting data, testing web apps, or automating any browser task. Triggers include requests to \"open a website\", \"fill out a form\", \"click a button\", \"take a screenshot\", \"scrape data from a page\", \"test this web app\", \"login to a site\", \"automate browser actions\", or any task requiring programmatic web interaction.
    - **cartography**: Repository understanding and hierarchical codemap generation
    - **openspec-apply-change**: Implement tasks from an OpenSpec change. Use when the user wants to start implementing, continue implementation, or work through tasks.
    - **openspec-archive-change**: Archive a completed change in the experimental workflow. Use when the user wants to finalize and archive a change after implementation is complete.
    - **openspec-bulk-archive-change**: Archive multiple completed changes at once. Use when archiving several parallel changes.
    - **openspec-continue-change**: Continue working on an OpenSpec change by creating the next artifact. Use when the user wants to progress their change, create the next artifact, or continue their workflow.
    - **openspec-explore**: Enter explore mode - a thinking partner for exploring ideas, investigating problems, and clarifying requirements. Use when the user wants to think through something before or during a change.
    - **openspec-ff-change**: Fast-forward through OpenSpec artifact creation. Use when the user wants to quickly create all artifacts needed for implementation without stepping through each one individually.
    - **openspec-new-change**: Start a new OpenSpec change using the experimental artifact workflow. Use when the user wants to create a new feature, fix, or modification with a structured step-by-step approach.
    - **openspec-onboard**: Guided onboarding for OpenSpec - walk through a complete workflow cycle with narration and real codebase work.
    - **openspec-sync-specs**: Sync delta specs from a change to main specs. Use when the user wants to update main specs with changes from a delta spec, without archiving the change.
    - **openspec-verify-change**: Verify implementation matches change artifacts. Use when the user wants to validate that implementation is complete, correct, and coherent before archiving.
    - **simplify**: Simplify and refine recently modified code for clarity and consistency. Use after writing code to improve readability without changing functionality.
    - **vast-ai-llm**: Deploy and manage self-hosted LLMs on Vast.ai GPU instances. Use when the user wants to rent GPUs, run vLLM/SGLang inference servers, manage Vast instances, configure SSH tunnels, or troubleshoot GPU server issues.
    

    It is extremely clear that everything is duplicated. By also being in system prompt each skill is essentially defined 3 times

  7. barisgit commented on Apr 18, 2026

    @barisgit

    After digging around a bit I see exact same describeSkill() block in these two files:

    • packages/opencode/src/tool/registry.ts
    • packages/opencode/src/tool/skill.ts
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

bugSomething isn't workingcoreAnything pertaining to core functionality of the application (opencode server stuff)perfIndicates a performance issue or need for optimization

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions