anomalyco / anomalyco/opencode
codemode: tool discovery helper documented three ways; only bare search(input) works on 1.18.21 — README's 'never fails' claim is false
@jlongster is already working on this.
Since Aug 27, 2026.
- Dominant language
- TypeScript
- Stars
- 209k
- Forks
- 27.5k
- PR merge metrics
- PR metrics pending
Description
Summary
Three opencode surfaces describe the Code Mode tool-discovery helper with three
different invocation forms, and on opencode 1.18.21 only one of them works:
| Surface | Form shown | Works on 1.18.21? |
|---|---|---|
Generated execute() scaffold ("## Search" section) |
search(input: {...}) — bare global |
✅ yes (verified) |
packages/codemode/README.md + generated "## Workflow"/"## Rules" text |
tools.$codemode.search({...}) |
❌ no — Unknown tool '$codemode.search'. |
What a model infers from the catalog's own path convention (tools.<ns>.<tool>) |
tools.search({...}) |
❌ no — Unknown tool 'search'. |
Impact: models following either of the two documented namespaced forms hit a hard
UnknownTool failure with no actionable suggestion, and can misdiagnose the
scaffolding as broken rather than mis-invoked.
The README also states the search tool is "always registered … so a speculative
tools.$codemode.search call never fails as an unknown tool" — that claim is
false on this build (reproduction below).
Environment
- opencode version: 1.18.21 (Homebrew, release)
- OS: Darwin 27.0.0 arm64 (macOS)
- Terminal: iTerm.app (xterm-256color, truecolor)
- Shell: /bin/zsh
- Install/channel: release
- Active plugins: @dietrichgebert/ponytail, @ljw1004/opencode-trace
Reproduction
Deterministic within a single session; each form was tested in its own execute()
sandbox against the same partial catalog (~91 tools across 6 namespaces):
- Start a session with Code Mode active and a partial inline catalog.
- In one
execute()sandbox, runtools.$codemode.search({ query: "jira", limit: 2 })
— the README's documented form.
→Unknown tool '$codemode.search'. - In another sandbox, run
Object.keys(tools)→ lists the 6 MCP namespaces with
no$codemodenamespace present, confirming it is not registered there at all. - In another sandbox, run bare
search({ query: "jira add comment", limit: 2 })
→ succeeds immediately, returning exact catalog paths such as
tools["mcp-atlassian-jira"].jira_add_comment.
Similarly tools.search({ query }) → Unknown tool 'search'.
Expected Behavior
- One canonical invocation form should hold everywhere: scaffold, README, and the
Workflow/Rules guidance baked into everyexecute()description. - The
UnknownToolsuggestions for these paths should point at whichever form is
real (e.g."use bare search({ query })"), instead of failing circularly —
notably, upstreamtool-runtime.tsalready attaches helpful suggestions to
UnknownTool errors; this build surfaced none for either failed form. - If the intended contract is
tools.$codemode.search, then per the README it
should never raise UnknownTool; if the intended contract is a bare global, the
README/workflow text should not advertise$codemode.search, and the "never
fails" sentence needs correcting or version-scoping.
Actual Behavior
- The generated scaffold on 1.18.21 documents discovery as a bare global
search(input: {...}), separate from the## Available toolssection whose
entries are alltools.*. - The codemode README (and current dev/v2 source in
tool-runtime.ts) document the
same helper astools.$codemode.search(...), always registered under a reserved
namespace, andObject.keys(tools)on other builds reportedly includes
$codemode. - On 1.18.21 neither namespaced form resolves, and
Object.keys(tools)shows no
$codemode; only the bare global exists. Any model following the README or the
convention it learned from the catalog fails and gets an unhelpful error.
Related but distinct prior reports:
- #40611 — nested-runtime collision where a separate MCP server's internal
tools.search()resolved against the outer Code Mode catalog (fixed via
codemode: false). This report concerns a single runtime with no second server. - #41389 — catalog-listed MCP tools failing when invoked outside
execute. This
report concerns the discovery helper itself, insideexecute.
Additional Context
Suggested fix directions (any one suffices):
- Register the discovery tool in both places inside the sandbox (alias bare
search↔tools.$codemode.search), so all three documented forms work. - Version-scope/correct the README's "never fails as an unknown tool" claim, or
restore registration under$codemode. - Make the two failing paths' UnknownTool suggestions name the working form.
Local mitigation on this machine: a version-stamped instruction block in
~/.config/opencode/AGENTS.md documenting that discovery is a bare global on
1.18.21 and everything else lives under tools.*.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Assessment
This issue has not been assessed yet.