Describe the enhancement you want to request
Problem
Slash commands that produce display-only output (panels, status confirmations) emit
their entire user-visible content via the command.execute.before hook's parts
output. After that hook returns, the host's command dispatch in
packages/opencode/src/session/prompt.ts always invokes the LLM for the next
assistant turn — wasting a round-trip for every such command, even when the model
has nothing meaningful to do.
A real-world plugin that ships three display-only commands (/show-models,
/pick, /auto-pick) currently emits an "Acknowledged" turn from the model after
each invocation, costing tokens and latency for zero user value.
What I tried in the plugin
Initially I added a template instruction "No further response is required" to each
command. The instruction tells the model to stay silent, but the LLM stream is
still dispatched — the suppression is text-only, not behavioral. Visual QA against
a freshly built opencode confirmed the dispatch happens.
Plugin-side workarounds don't exist:
command.execute.before hook output is just { parts } — no flag exposed
chat.message hook output is { message, parts } — same
client.session.abort() from a hook races the runner becoming busy
- The plugin Effect runtime dies on throw, so we can't crash the session as a side-channel
Proposed solution
Add an optional noReply?: boolean field to the command schema
(packages/opencode/src/command/index.ts). When set, the dispatch path forwards
noReply: true to prompt(), which already has a short-circuit
(if (input.noReply === true) return message). With this flag, display-only
commands can opt out of the follow-up LLM turn while keeping their existing panel
behavior.
Opt-in and additive: existing commands without noReply keep current behavior.
Verification I did locally
- 6-line patch on a local fork (PR coming)
- Typecheck clean (14/14 tasks)
bun test test/session/prompt.test.ts — 53/53 pass
- Visual QA via tmux: baseline window (20s idle) → 0 LLM dispatches; post-
/show-models
window (20s) → 0 LLM dispatches. The flag works end-to-end.
PR forthcoming. Happy to iterate on naming, location, or schema shape.
Describe the enhancement you want to request
Problem
Slash commands that produce display-only output (panels, status confirmations) emit
their entire user-visible content via the
command.execute.beforehook'spartsoutput. After that hook returns, the host's command dispatch in
packages/opencode/src/session/prompt.tsalways invokes the LLM for the nextassistant turn — wasting a round-trip for every such command, even when the model
has nothing meaningful to do.
A real-world plugin that ships three display-only commands (
/show-models,/pick,/auto-pick) currently emits an "Acknowledged" turn from the model aftereach invocation, costing tokens and latency for zero user value.
What I tried in the plugin
Initially I added a template instruction "No further response is required" to each
command. The instruction tells the model to stay silent, but the LLM stream is
still dispatched — the suppression is text-only, not behavioral. Visual QA against
a freshly built opencode confirmed the dispatch happens.
Plugin-side workarounds don't exist:
command.execute.beforehook output is just{ parts }— no flag exposedchat.messagehook output is{ message, parts }— sameclient.session.abort()from a hook races the runner becoming busyProposed solution
Add an optional
noReply?: booleanfield to the command schema(
packages/opencode/src/command/index.ts). When set, the dispatch path forwardsnoReply: truetoprompt(), which already has a short-circuit(
if (input.noReply === true) return message). With this flag, display-onlycommands can opt out of the follow-up LLM turn while keeping their existing panel
behavior.
Opt-in and additive: existing commands without
noReplykeep current behavior.Verification I did locally
bun test test/session/prompt.test.ts— 53/53 pass/show-modelswindow (20s) → 0 LLM dispatches. The flag works end-to-end.
PR forthcoming. Happy to iterate on naming, location, or schema shape.