anomalyco / anomalyco/opencode
SessionReminders: build-switch banner mislabels/repeats when a custom primary agent (e.g. read-only 'ask') is used between plan and build
@jlongster is already working on this.
Since Jul 21, 2026.
- Dominant language
- TypeScript
- Stars
- 209k
- Forks
- 27.5k
- PR merge metrics
- PR metrics pending
Description
Summary
SessionReminders.apply's legacy (non-experimentalPlanMode) branch decides whether to inject the "operational mode has changed from plan to build" reminder using:
https://github.com/anomalyco/opencode/blob/dev/packages/opencode/src/session/reminders.ts#L37
const wasPlan = input.messages.some((msg) => msg.info.role === "assistant" && msg.info.agent === "plan")
if (wasPlan && input.agent.name === "build") {
// ...push BUILD_SWITCH synthetic reminder
}
.some() here checks "has this session ever contained a plan-agent message", not "was the immediately preceding turn plan". input.messages comes from MessageV2.filterCompactedEffect(sessionID) (see prompt.ts around the main agent loop), which is the full uncompacted session history, not a per-turn window.
Why this matters for custom agents
opencode explicitly supports custom primary agents (https://opencode.ai/docs/agents), which can be switched to via Tab like build/plan. With only the two built-in agents, "session ever had a plan message" and "previous turn was plan" are almost always equivalent in practice, so this has presumably gone unnoticed.
Once a third primary agent is in rotation — e.g. a custom read-only advisor agent (config agent: { ask: { mode: "primary", permission: { edit: "deny" } } }) — the assumption breaks:
- User is in
plan, does some read-only exploration. - User switches to a custom agent (e.g.
ask) for a few turns of Q&A, unrelated to planning. - User switches to
build.
At step 3, wasPlan is still true (the plan message from step 1 is still in the uncompacted history), so BUILD_SWITCH fires — even though the actual previous turn's agent was ask, not plan. The model receives:
<system-reminder>
Your operational mode has changed from plan to build.
...
</system-reminder>
which is factually wrong for that turn (it changed from the custom agent to build, not from plan). Worse: because the check scans the entire uncompacted history rather than being edge-triggered, this reminder can re-fire on every subsequent build turn for the rest of the session (until compaction eventually drops the old plan-agent message out of the window), regardless of how many other agents were used in between. A reminder that's supposed to be a rare, high-signal "your mode just changed" notice instead becomes noisy and occasionally false, which risks the model learning to discount it.
Reproduction
- Define a custom primary agent, e.g.:
--- name: ask mode: primary permission: edit: deny --- You are a read-only advisor. - In a session: switch to
plan, send one message. Switch toask, send one or more messages. Switch tobuild, send a message. - Inspect the synthetic parts on that last user message (or just observe the model's response) — the
BUILD_SWITCHreminder appears and claims the transition was "from plan to build", despite the immediately preceding turn beingask.
Confirmed against a live 1.18.3 session with exactly this custom-agent setup (transcript inspected via opencode db / sqlite).
Suggested fix
Mirror the pattern already used a few lines below in the same file for the experimentalPlanMode branch (assistantMessage = input.messages.findLast((msg) => msg.info.role === "assistant"), then check assistantMessage?.info.agent === "plan"), which is edge-triggered and doesn't have this issue. I've opened a PR with this fix: (linked below).
Environment
- opencode 1.18.3 (macOS, Homebrew install)
- Reproduced conceptually against
devbranch source (same logic present,reminders.tsunchanged between the two as of this writing)
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Assessment
This issue has not been assessed yet.