You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
"Code Mode" instructions are confusing Gemma-4-31B #53623
Thanks for the detailed report. This depends on how Gemma-4-31B itself reads the Code Mode instructions, so it needs a maintainer with access to that model to reproduce; our automated environment can only use a simulated model.
I did read the v2.0.24 prompt text. The Code Mode instructions start with "Use the execute tool to call the tools listed below. They cannot be called directly…", but nowhere do they say that the regular top-level tools (read, edit, etc.) should still be called directly, outside execute. That gap could explain the behavior you're seeing.
Two details would help whoever picks this up:
Which provider or runtime you use to serve Gemma-4-31B (e.g. OpenRouter, Ollama, llama.cpp, vLLM).
Whether it still happens with hashline-opencode-plugin disabled. If that plugin registers its own read/edit tools, they may show up in the Code Mode catalog under the same names as the top-level tools.
You can reply here with the details, or edit the issue and then leave a comment saying you've updated it.
Same root cause with DeepSeek 4.1 Flash 1017 (litellm/deepseek-v4p1-flash) — but a different symptom: denial instead of mis-routing. Controlled repro + validated workaround.
With DS 4.1 the agent never mis-routes top-level tools into execute — it goes further and denies they exist. Asked to read a file, it searches the Code Mode catalog, hits Unknown tool 'read' on the dangling sandbox references, and concludes "in this environment no read tool exists; everything must go through execute", then asks the user to paste the file contents. The exact same prompt with litellm/glm-5p3-flash calls read directly and works instantly.
Controlled matrix (opencode run, identical probe prompt: "use the read tool on /tmp/opencode/probe.txt, don't use bash or execute", opencode v2.0.32, Linux):
Config
Model
Result
default (shared service)
glm-5p3-flash
✅ calls read directly
default (shared service)
deepseek-v4p1-flash
❌ "no read tool exists"
default + clarification in the user message
deepseek-v4p1-flash
❌ still refuses
temp global config + system-level instructions ("native tools are direct, never via execute")
deepseek-v4p1-flash
✅ calls read directly
control: temp config without instructions, --standalone
deepseek-v4p1-flash
❌ fails
Takeaways:
(a) The native tool declarations do reach the model — a system-level instruction is enough to unlock correct behavior, so nothing is dropped between OpenCode and the provider (both models served via LiteLLM, @ai-sdk/openai-compatible).
(b) User-message corrections don't override the Code Mode prose for this model; system-level instructions do.
(c) Shared service vs --standalone is not a factor.
Suggested fix — one sentence in the generated Code Mode instructions: "MCP catalog tools cannot be called directly — use execute. Native top-level tools (read, edit, shell, …) are NOT part of this catalog and must be called directly as usual." That sentence alone fixed DS 4.1 Flash for us (rows above). Happy to share the exact instruction file we used if useful for evals.
Subagent data point for the same gap — opencode v2.1.3, opencode-go/deepseek-v4.1-flash. The cost here is not a refusal but a fixed discovery tax: 4 wasted calls per agent turn, paid twice per task.
Two pdca-scout subagents in one 11-minute task opened with the identical sequence, independently of each other:
execute → await tools.bash({...}) → Error: Unknown tool 'bash' (ten commands in one batch, all failing);
search({ query: "shell" }) → the catalog returns MCP servers only (mslearn, opencode, roslyn) — no built-ins anywhere in it;
reasoning: "No bash tool in the Code Mode catalog";
only then: call shell directly — works immediately.
The second subagent repeated steps 1–3 verbatim twenty minutes later, in a fresh session, with no shared context. Both eventually recovered; neither produced a wrong result — the price was turns, tokens and a confused reasoning trail that the caller then has to read past.
One trap I did not see mentioned above: the agent's own frontmatter declares bash: permissions, so the model's first guess is tools.bash — a name that is not even the real built-in (shell). The permission namespace and the tool name disagree, which makes step 1 read as a configuration error rather than a wrong layer, and sends the model looking for a configured shell instead of a native tool.
So the single sentence @janorga proposed covers this case too, and would pay for itself on the first subagent dispatch. +1 from a subagent context. Related: #55087 — making built-ins callable from execute would remove the guess entirely rather than just documenting the boundary.
Same behavior on opencode v2.1.3 with Gemini, default config: no opencode.json, no plugins.
This is not specific to Gemma or to one provider — the two defects are
model-independent, and any model that takes the Code Mode wording literally
will hit them:
Prompt wording: nothing says built-in tools stay top-level. The heading
"Use the execute tool to call the tools listed below" reads as if every
tool call must go through execute, so the model writes read(...) / tools.read(...) inside the code block. PR fix(core): tell Code Mode models built-in tools stay top-level #57627 addresses this.
Suggestion quality: the sandbox catalog only contains tools.opencode.*,
so the closest match for read is an unrelated MCP tool. Listing the
available namespaces (or omitting the suggestion when the first segment
matches no namespace) would be more useful than the current hint.
It shows up more often with models from external providers (Gemini, Mistral,
Kimi, ...) than with models OpenCode is tuned against, but the underlying
cause is the prompt/catalog, not the model: the wrong behavior is directly
encouraged by the instructions.
Deterministic, model-independent reproduction: calling tools.read({ path: "/etc/hostname" }) inside execute yields the message
above every time.
Activity
opencode-agent commentedon Oct 6, 2026
Thanks for the detailed report. This depends on how Gemma-4-31B itself reads the Code Mode instructions, so it needs a maintainer with access to that model to reproduce; our automated environment can only use a simulated model.
I did read the v2.0.24 prompt text. The Code Mode instructions start with "Use the
executetool to call the tools listed below. They cannot be called directly…", but nowhere do they say that the regular top-level tools (read,edit, etc.) should still be called directly, outsideexecute. That gap could explain the behavior you're seeing.Two details would help whoever picks this up:
hashline-opencode-plugindisabled. If that plugin registers its ownread/edittools, they may show up in the Code Mode catalog under the same names as the top-level tools.You can reply here with the details, or edit the issue and then leave a comment saying you've updated it.
github-actions commentedon Oct 6, 2026
This issue might be a duplicate of existing issues. Please check:
executeinstead.rekram1-node commentedon Oct 7, 2026
Will adjust instructions, ran evals with lot of smaller models but didnt try gemma or xiaomi
janorga commentedon Oct 19, 2026
Same root cause with DeepSeek 4.1 Flash 1017 (
litellm/deepseek-v4p1-flash) — but a different symptom: denial instead of mis-routing. Controlled repro + validated workaround.With DS 4.1 the agent never mis-routes top-level tools into
execute— it goes further and denies they exist. Asked to read a file, it searches the Code Mode catalog, hitsUnknown tool 'read'on the dangling sandbox references, and concludes "in this environment noreadtool exists; everything must go throughexecute", then asks the user to paste the file contents. The exact same prompt withlitellm/glm-5p3-flashcallsreaddirectly and works instantly.Controlled matrix (
opencode run, identical probe prompt: "use thereadtool on /tmp/opencode/probe.txt, don't use bash or execute", opencode v2.0.32, Linux):readdirectlyreadtool exists"instructions("native tools are direct, never viaexecute")readdirectly--standaloneTakeaways:
@ai-sdk/openai-compatible).instructionsdo.--standaloneis not a factor.tools.readreference inside the sandbox (looks registered, but fails withUnknown tool 'read') acts as false confirmation for the model's wrong conclusion. Related: execute: tools.shell unavailable inside Code Mode runtime despite being in catalog #39312 (closed as expected behavior).Suggested fix — one sentence in the generated Code Mode instructions: "MCP catalog tools cannot be called directly — use
execute. Native top-level tools (read,edit,shell, …) are NOT part of this catalog and must be called directly as usual." That sentence alone fixed DS 4.1 Flash for us (rows above). Happy to share the exact instruction file we used if useful for evals.AlexeyShirshov commentedon Oct 25, 2026
Subagent data point for the same gap — opencode v2.1.3,
opencode-go/deepseek-v4.1-flash. The cost here is not a refusal but a fixed discovery tax: 4 wasted calls per agent turn, paid twice per task.Two
pdca-scoutsubagents in one 11-minute task opened with the identical sequence, independently of each other:execute→await tools.bash({...})→Error: Unknown tool 'bash'(ten commands in one batch, all failing);search({ query: "shell" })→ the catalog returns MCP servers only (mslearn,opencode,roslyn) — no built-ins anywhere in it;shelldirectly — works immediately.The second subagent repeated steps 1–3 verbatim twenty minutes later, in a fresh session, with no shared context. Both eventually recovered; neither produced a wrong result — the price was turns, tokens and a confused reasoning trail that the caller then has to read past.
One trap I did not see mentioned above: the agent's own frontmatter declares
bash:permissions, so the model's first guess istools.bash— a name that is not even the real built-in (shell). The permission namespace and the tool name disagree, which makes step 1 read as a configuration error rather than a wrong layer, and sends the model looking for a configured shell instead of a native tool.So the single sentence @janorga proposed covers this case too, and would pay for itself on the first subagent dispatch. +1 from a subagent context. Related: #55087 — making built-ins callable from
executewould remove the guess entirely rather than just documenting the boundary.ttpanna commentedon Oct 25, 2026
Same behavior on opencode v2.1.3 with Gemini, default config: no
opencode.json, no plugins.This is not specific to Gemma or to one provider — the two defects are
model-independent, and any model that takes the Code Mode wording literally
will hit them:
"Use the
executetool to call the tools listed below" reads as if everytool call must go through
execute, so the model writesread(...)/tools.read(...)inside the code block. PR fix(core): tell Code Mode models built-in tools stay top-level #57627 addresses this.tools.opencode.*,so the closest match for
readis an unrelated MCP tool. Listing theavailable namespaces (or omitting the suggestion when the first segment
matches no namespace) would be more useful than the current hint.
It shows up more often with models from external providers (Gemini, Mistral,
Kimi, ...) than with models OpenCode is tuned against, but the underlying
cause is the prompt/catalog, not the model: the wrong behavior is directly
encouraged by the instructions.
Deterministic, model-independent reproduction: calling
tools.read({ path: "/etc/hostname" })insideexecuteyields the messageabove every time.