anomalyco / anomalyco/opencode

External-skill discovery (skills/**/SKILL.md) is fully recursive with no depth limit, causing derailment when a tool vendors nested skill copies (e.g. gstack)

Open
#49,271 2 comments 0 reactions 1 assignee View on GitHub

@nexxeln is already working on this.

Since Sep 16, 2026.

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

Description

OpenCode's external-skill discovery (confirmed via strings on the compiled opencode-darwin-arm64 binary, v1.18.31) uses the glob pattern skills/**/SKILL.md under ~/.claude and ~/.agents — fully recursive, no depth limit, applied on every run regardless of --dir or --pure.

This becomes a problem when a legitimately installed tool vendors copies of its own skills for other coding assistants inside its own directory tree. gstack (a Claude Code skill package) does exactly this by design — it vendors a full copy of its ~68-skill suite for 9 other tools (.opencode/skills/, .factory/skills/, .kiro/skills/, .cursor/skills/, .gbrain/skills/, .hermes/skills/, .slate/skills/, .agents/skills/, .openclaw/skills/) inside ~/.claude/skills/gstack/, so that whichever of those tools a user runs also picks up gstack's skills.

OpenCode's recursive glob walks straight into that vendored tree and loads all ~600 nested SKILL.md files as if they were its own available skills — confirmed in debug output: message=init count=65 on this machine, every run, regardless of which model or prompt was used.

Consequence, reproduced across 3 local model families (Qwen2.5-Coder 3B/7B, Qwen2.5-Instruct 7B, Llama-3.1-8B) via Ollama, 5 trials: every model, every trial, derailed mid-task into vocabulary lifted from those phantom skills. Example: one trial's model responded mid-task with "It seems like you are asking for the 'setup' skill instead... the correct command is 'setup [skill name]'"setup is not part of the task's vocabulary anywhere; it is the literal name of several nested skills in the vendored tree (setup-deploy, setup-browser-cookies, setup-gbrain). --pure did not help (it only gates plugins, not this scan).

Fix confirmed: setting OPENCODE_DISABLE_EXTERNAL_SKILLS=1 drops init count from 65 to 1 (only the built-in customize-opencode skill remains), and two clean re-runs of the same sandbox task (a one-line Python bug + failing pytest test) showed zero skill-vocabulary derailment in either trial.

Suggested fix: don't recurse past a directory that already matched SKILL.md — treat it as one skill's own directory (which may legitimately contain its own nested files, including other tools' vendored SKILL.md copies), not a new search root to walk into.

Related existing reports on the same underlying gap (this report adds a concrete, reproducible model-behavioral consequence, plus the exact glob pattern from the binary, rather than just a performance/warning symptom):

  • #46327 (open) — duplicate skill name warnings from nested/symlinked SKILL.md
  • #29462 (closed) — skill enumeration has no upper bound
  • #20647 (closed) — skill descriptions bloat system prompt, breaking small-context models
  • #27027 (closed) — skill discovery follows symlinks into large directories, causing slow startup

Repro steps:

  1. Have any tool installed under ~/.claude/skills/<name>/ that itself vendors nested SKILL.md copies several directories deep (or simulate by creating ~/.claude/skills/test/.opencode/skills/foo/SKILL.md, .factory/skills/bar/SKILL.md, etc.)
  2. Run opencode run --dir <any-project> --model <any-model> --print-logs --log-level DEBUG "<any task>"
  3. Observe message=init count=<N> in the log, where N includes every nested SKILL.md, not just top-level ~/.claude/skills/<name>/SKILL.md entries
  4. Compare against OPENCODE_DISABLE_EXTERNAL_SKILLS=1 opencode run ... — count drops to 1, and the derailment stops

Environment: macOS 25.6.0 (Darwin), opencode-ai 1.18.31 (npm), Ollama-backed local models via @ai-sdk/openai-compatible provider.

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.