Repository navigation
Description
Summary
In opencode2 (V2), after switching mode/agent (Build ↔ Plan, or to any custom primary agent), the model has no way to know which mode it is in:
- The
agent-switchedmessage part written on every mode switch is silently dropped when session history is converted to LLM context. - The built-in
planagent only overrides permissions — it has nosystemoverride, so the system prompt is byte-identical before and after the switch. - No reminder-injection code exists anywhere in the V2 request path. The v1
SessionRemindersmechanism (packages/opencode/src/session/reminders.ts, the "Plan mode is active..." / "Your operational mode has changed from plan to build..." synthetic parts) was never ported to V2.
This is the parity gap explicitly acknowledged but left untracked in the closing comment of #40395:
There is a separate plan-mode parity gap: V2's built-in
planagent currently changes permissions but has no plan-specific system prompt, while the citedsession/reminders.tsandOPENCODE_EXPERIMENTAL_PLAN_MODEbelong to V1 and are not part of the V2 request path. That should be tracked independently from the disproven custom-agent claim.
This issue is that independent tracking.
Why the model cannot know the mode
1. agent-switched parts are discarded in the LLM projection
Switching agent publishes session.agent.selected, which appends a type: "agent-switched" message to the session timeline. But in packages/core/src/session/runner/to-llm-message.ts:
function toLLMMessage(message: SessionMessage.Info, ...): Message[] {
switch (message.type) {
case "agent-switched":
case "model-switched":
return []
...The only artifact of a mode switch is a TUI timeline label ("Switched agent to plan"); the model receives nothing.
2. The plan agent has no system prompt
In packages/core/src/plugin/agent.ts, the plan agent only sets name/description/permissions:
draft.update(Agent.ID.make("plan"), (item) => {
item.name = Agent.Name.make("Plan")
item.description = "Plan mode. Disallows all edit tools."
item.mode = "primary"
item.permissions.push(
{ action: "question", resource: "*", effect: "allow" },
{ action: "edit", resource: "*", effect: "deny" },
)
})Unlike explore/compaction/title/summary, it does not set item.system. Since packages/core/src/session/model-request.ts builds the system block as agent.info.system ? agent.info.system : PROMPT_DEFAULT, plan and build sessions send the same system prompt.
3. No mode reminders exist in the V2 request path
Searching the published @opencode-ai/[email protected] Linux binary for every v1 reminder string returns zero occurrences:
| string (present in v1 binary) | count in next-16741 binary |
|---|---|
Your operational mode has changed from plan to build |
0 |
Plan mode is active |
0 |
supersedes ALL other instructions |
0 |
no longer in read-only |
0 |
Plan Workflow |
0 |
The only <system-reminder> generators that exist in the V2 binary are UI-origin context hints: working-directory change, "user opened the file", and code-selection notes. None of them mention the mode/agent.
Notably, two model-specific system prompts even promise a reminder that is never delivered:
packages/core/src/plugin/system-prompt/kimi.txtandmeta.txt:When
planmode is active, you will see a <system-reminder> about this.
For every other model (Claude, GPT/codex, Gemini), the system prompt does not mention plan mode at all.
Contrast: v1 behavior
opencode v1 injects synthetic reminder parts into the last user message at every request based on agent state:
- currently plan agent → a "Plan mode is active... you MUST NOT make any edits..." reminder (plus, with
OPENCODE_EXPERIMENTAL_PLAN_MODE, the plan-file workflow) - previous turn was plan, now build → "Your operational mode has changed from plan to build. You are no longer in read-only mode..."
So in v1 the model always knows its current mode, even after compaction.
Impact
- After Build → Plan, the model keeps behaving as if in build mode; it only infers the restriction when an
edittool call is denied — and the denial carries no explanation of the mode. - Plan → Build switches are completely silent.
- Nothing tells the model "you are in a planning mode, do edits via plan text"; the only enforcement is a tool-level deny, which encourages workarounds (e.g. shell-based writes, cf. Plan mode can write and edit files via bash #39491 for the same symptom in v1.18.x).
- For the kimi/meta prompts the instruction is actively misleading ("you will see a system-reminder" — the model never will).
Reproduction
opencode2(v0.0.0-next-16741), start a session on thebuildagent.- Switch to
plan(agent switch), send: "Which mode are you running in? One sentence." - The model answers from the default identity with no knowledge of plan mode. Same after switching back to build — it cannot detect either transition.
- Confirm via code/strings as above.
Suggested fixes (for discussion)
- A (minimal): in
toLLMMessage, renderagent-switchedas a synthetic user message (e.g. "The active agent is nowplan.") instead of[]. - B (v1 parity): port the v1 reminders logic into the V2 request path — per-request, inject the appropriate reminder based on the current agent (plan-active reminder; edge-triggered build-switch reminder), including the experimental plan-mode plan-file workflow.
- C: give the
planagent its ownitem.system. Cheap, but insufficient alone: it cannot express "switched back to build", and mid-session switches still get no notification for models whose prompt was already assembled.
Likely the right answer is B (+ C for clarity), matching v1 semantics.
Related
- agents: system/prompt not applied to model requests — model ignores agent identity #40395 (closed not_planned — its closing comment requested this issue)
- SessionReminders: build-switch banner mislabels/repeats when a custom primary agent (e.g. read-only 'ask') is used between plan and build #38066 / fix(session): edge-trigger build-switch reminder instead of scanning full session history #38067 (v1 reminders correctness: edge-trigger build-switch banner)
- Custom primary agent mode name not shown in system-reminder notification #38643 (v1: reminder mislabels custom primary agents)
- [FEATURE]: Let custom primary agents participate in plan mode (plan file path + configurable plan_exit handoff target) #31868 (custom primary agents participating in plan mode)
- Plan mode can write and edit files via bash #39491 ("the model forgot that it was in plan mode" — v1 symptom of weak mode signaling)
Environment
- opencode2
v0.0.0-next-16741(@opencode-ai/clinext channel, Linux x64) - Verified against the
v2branch source (packages/core/src/...) as of this report
Activity
mrraghur commentedon Aug 11, 2026
Amigos, any ETA on this bug. Getting badly bitten by it
gnh1996 commentedon Aug 11, 2026
I have rolled back to V1. It seems the official team pays little attention to these basic‑level issues. I also submitted feedback via Twitter before, yet they did not care about it.
opencode-agent commentedon Aug 11, 2026
Fixed by #41665. The Plan plugin now injects model-visible reminders when a session starts in Plan, when entering Plan, and when leaving Plan, using the persisted previous-agent selection. This closes the V2 mode-signaling parity gap tracked here.
maxiedaniels commentedon Sep 7, 2026
Are you sure this is fixed?? I'm experiencing major issues with Gemini flash thinking it's still in plan mode, and even when I CAN get it to check tools, it not being able to access the edit tool.