Repository navigation
Description
Description
Summary
In OpenCode Desktop on Windows, the agent control is never rendered in the
composer, and its keybind (Mod/Ctrl + .) does nothing. The API reports
both plan and build as visible primary agents, and switching agents through
POST /api/session/:id/agent works — so this is a UI gating problem, not a
config or backend problem.
Reproduced on 2.1.1 and 2.1.2, in both existing and brand-new sessions.
Environment
| opencode | v2.1.2 (desktop), also reproduced on v2.1.1 |
| OS | Windows 10.0.26200.9711 (x64) |
| Shell | cmd.exe |
| Install | desktop installer, @opencodedesktop per-user install |
| Config | ~/.config/opencode/opencode.json, default_agent: "plan" |
| MCP | one stdio server (open-meteo), connected |
| Plugins | one local plugin (.opencode/plugins/replicate.ts) |
Reproduction
- Launch OpenCode Desktop 2.1.2 on Windows.
- Open an existing session, or create a new one.
- Look at the composer: the model selector and model variant are present, the
agent control is not. - Press
Ctrl+.— nothing happens. - Confirm the backend state:
opencode api get /api/agent
→ returnsplanandbuild, bothprimary, bothhidden: false. - Confirm switching works outside the UI:
opencode api post /api/session/<id>/agent --data '{"agent":"build"}'
→ succeeds, and subsequent requests in that session run asbuild.
Expected
An agent chip in the composer (as in the terminal client), listing the visible
primary agents; Mod/Ctrl + . opens the picker.
Actual
No control is rendered and the keybind never registers, so the only way to
change agents is the HTTP API.
Additional Context
Reading the shipped app.asar (2.1.2), the control is guarded here:
get agent() {
let t = e.controls().agents
return t.visible && t.options.length > 0
? { options: () => e.controls().agents.options.map(...), ... }
: undefined
}The composer attaches the keybind to that component:
R(q, {
get when() { return a.agent },
keyed: true,
children: (e) => R(lo, { title: n.t('ui.promptInput.chooseAgent'), keybind: ['Mod', '.'], control: e })
})and the control object is built with:
visible: t.agent.visible(),
options: t.agent.list().map(e => e.name),
current: t.agent.current()?.name ?? ''Because the agent list is non-empty (/api/agent returns two visible
primaries), the leading suspect is t.agent.visible() evaluating to false,
which returns undefined and suppresses both the chip and the keybind.
Things ruled out:
- Config. The control was missing before any
permissions/agentsedits,
and/api/agentreturns correct data with the current config. - Version. The gate is byte-identical in 2.1.1 and 2.1.2.
- Session state. Reproduced in a freshly created session.
- Missing toggle. The only agent-related i18n keys are
ui.promptInput.chooseAgent,ui.tool.agent[.default|.delegating]and
ui.sessionTimeline.notice.agentChanged— there is no settings entry that
could hide the control.
Impact: with default_agent: "plan" (a read-only agent by design), a new
session cannot be switched to build from the UI at all. Users who configure
sessions.default_agent to a restricted agent have no escape hatch.
Possible angle: check whatever populates t.agent.visible() — if it depends on
a feature flag or on the agent list being fetched for the current workspace, it
appears to be failing silently on Windows.
Plugins
No response
OpenCode version
No response
Steps to reproduce
No response
Screenshot
No response
Operating System
No response
Terminal
No response
Activity
opencode-agent commentedon Oct 21, 2026
Thanks for the detailed write-up and for digging into the bundle.
This looks like intended behaviour rather than a bug. In v2 the agent picker in the composer is hidden by default when only the built-in agents (
plan/build) are available. There's a setting to show it:Settings → General → "Show agent", described as "Switch between agents in the composer. When hidden, defaults to Build agent."
With it turned on,
t.agent.visible()becomes true, so the agent chip appears andCtrl+.opens the picker. (It's stored asgeneral.showCustomAgents, which is why it didn't turn up when you searched theui.*strings.) Also, while the picker is hidden, the app falls back to the Build agent rather than keeping you onplan.I'll leave this open as a request: show the picker by default, or at least when
default_agentis set to something other thanbuild. Maintainers will consider it.Related issues:
buildand ignoredefault_agentdefault_agentwith BuildIf the picker still doesn't appear after you turn on "Show agent", please reply here and say so.