anomalyco / anomalyco/opencode

[FEATURE]: Remove or truncate <location> path in system prompt available_skills — wastes ~3.3K tokens/turn

Open
#39,294 0 comments 1 reaction 1 assignee View on GitHub

@jlongster is already working on this.

Since Jul 28, 2026.

Dominant language
TypeScript
Stars
209k
Forks
27.5k
PR merge metrics
PR metrics pending

Description

Description

The system prompt's <available_skills> block includes a <location> field with the full absolute file path for every skill. This field is:

  1. Unused by the LLM — skills are loaded via skill(name="foo"), not by path. The tool's internal registry already maps namelocation during discovery, so the LLM never needs to know the path.
  2. Extremely verbose — macOS paths like <location>/Users/yejq/Library/Application Support/com.xxx.zzz/mmmm/.opencode-config/skills/art-requirement/SKILL.md</location> average ~136 characters each.
  3. Made worse by pathToFileURL — spaces become %20, # becomes %23, and a file:// prefix adds 7 chars on top (as documented in #33786).

Token waste measurement (real-world data)

Measured from an actual system prompt dump with 84 skills:

Total <location> blocks:        84
Total characters in locations:  11,382
Average per location:           ~136 chars
Estimated tokens wasted:        ~3,252 tokens per turn

3.2K tokens burned on every API call on paths the LLM never reads, never uses, and doesn't need.

Single sample entry:

<location>/Users/yejq/Library/Application Support/com.xxx.zzz/mmmm/.opencode-config/skills/art-requirement/SKILL.md</location>

= 141 characters, for a skill whose name (art-requirement) is the only thing the LLM needs to invoke it.

Why <location> is unnecessary

The skill loading flow:

  1. System prompt tells the LLM: "these skills exist, here are their names + descriptions"
  2. LLM decides to use a skill → calls skill(name="ppt-master")
  3. The tool internally maps namelocation (already known from discovery)
  4. The tool reads SKILL.md and returns the content + a base directory hint

At no point does the LLM need the file path. The tool's internal registry already knows where every skill lives. The <location> field in the system prompt is pure context pollution.

For skills that reference relative resources (scripts/, references/), the base directory is already provided in the tool output when the skill is loaded — again, no need for the LLM to pre-know it.

Where the waste happens

In packages/opencode/src/tool/skill.ts (as documented in #13188):

...accessibleSkills.flatMap((skill) => [
  `  <skill>`,
  `    <name>${skill.name}</name>`,
  `    <description>${skill.description}</description>`,
  `    <location>${pathToFileURL(skill.location).href}</location>`,  // ← waste
  `  </skill>`,
])

And in the system prompt via Skill.fmt(list, { verbose: true }) (as documented in #22236):

Injection point Format Includes <location>?
System prompt body (verbose: true) XML Yes
Skill tool description (verbose: false) Compact markdown No

The verbose: false path already excludes <location>, proving it's not essential for the tool description. The system prompt just inherited it.

Proposed solutions

Option A (minimal, safe): Strip <location> from the system prompt only

  • Keep the verbose: true XML format but omit the <location> tag
  • The tool description already omits it (verbose: false)
  • The full location is still returned in the tool output when a skill is actually loaded (where it's genuinely useful for resolving relative resource paths)

Option B (configurable): Add an includeLocation flag to Skill.fmt()

Skill.fmt(list, { verbose: true, includeLocation: false })

Option C (root cause): Use the skill name as the identifier instead of the full path

<location>art-requirement</location>

This preserves the field for any consumer that depends on its presence, without the token bloat.

Related issues

  • #13188 — Lazy-load agent/skill lists (identifies location as part of the waste but focuses on broader lazy-loading)
  • #20647 — 600KB system prompt bloat from skill descriptions (includes <location> in the bloat total)
  • #22236 — Skill list injected twice per request (notes verbose: true includes <location>)
  • #33786 — Location URL-encoding bug via pathToFileURL (confirms the encoding problem)
  • anthropics/claude-code#59921 — Claude Code silently drops descriptions above a threshold (downstream symptom of the same budget pressure)

Impact

For users with many skills (common in plugin-heavy setups), this is pure waste — 3K+ tokens that could be used for actual conversation context, tool results, or just cost savings. The fix is effectively a one-line change with zero functional impact, since the skill tool resolves namelocation internally regardless of what's in the system prompt.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.