Skip to content

V2: agent/mode switches are invisible to the model — plan agent has no system prompt, no reminders in the request path (v1 parity gap) #40474

Closed

Description

@gnh1996

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:

  1. The agent-switched message part written on every mode switch is silently dropped when session history is converted to LLM context.
  2. The built-in plan agent only overrides permissions — it has no system override, so the system prompt is byte-identical before and after the switch.
  3. No reminder-injection code exists anywhere in the V2 request path. The v1 SessionReminders mechanism (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 plan agent currently changes permissions but has no plan-specific system prompt, while the cited session/reminders.ts and OPENCODE_EXPERIMENTAL_PLAN_MODE belong 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.txt and meta.txt:

    When plan mode 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 edit tool 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

  1. opencode2 (v0.0.0-next-16741), start a session on the build agent.
  2. Switch to plan (agent switch), send: "Which mode are you running in? One sentence."
  3. The model answers from the default identity with no knowledge of plan mode. Same after switching back to build — it cannot detect either transition.
  4. Confirm via code/strings as above.

Suggested fixes (for discussion)

  • A (minimal): in toLLMMessage, render agent-switched as a synthetic user message (e.g. "The active agent is now plan.") 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 plan agent its own item.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

Environment

  • opencode2 v0.0.0-next-16741 (@opencode-ai/cli next channel, Linux x64)
  • Verified against the v2 branch source (packages/core/src/...) as of this report

Activity

  1. mrraghur commented on Aug 11, 2026

    @mrraghur

    Amigos, any ETA on this bug. Getting badly bitten by it

  2. gnh1996 commented on Aug 11, 2026

    @gnh1996
    Author

    Amigos, any ETA on this bug. Getting badly bitten by it

    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.

  3. opencode-agent commented on Aug 11, 2026

    @opencode-agent
    Contributor

    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.

  4. maxiedaniels commented on Sep 7, 2026

    @maxiedaniels

    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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions