[Bug]: Plan mode performs real write / side-effecting actions (file edits, git commits, MCP tool calls) before the plan is approved
Nobody has claimed this yet.
- Dominant language
- TypeScript
- Stars
- 23k
- Forks
- 5.9k
- Avg merge
- 11h 14m
- Merged PRs (30d)
- 357
Description
Before submitting
- I searched existing issues and did not find a duplicate.
- I included enough detail to reproduce or investigate the problem.
Area
apps/server
Steps to reproduce
- Start a thread with a Claude model (Claude Fable 5), access level set to Full access, and turn on Plan mode — the Plan toggle stays lit in the composer.
- Let the model produce a plan so the thread reaches the "plan captured / awaiting review" state. Do not press Implement.
- Keep sending follow-up messages that refine the plan and give operational instructions — clarifying questions, specifying where an output artifact should be placed, asking to notify specific people — all while the Plan toggle is still on.
- Eventually press Implement to approve the plan.
Expected behavior
Plan mode should stay read-only until the plan is explicitly approved via Implement. Follow-up messages should only refine the plan. No file edits, no git branches/commits, and no side-effecting external tool calls (MCP integrations, e.g. creating a wiki/doc page or posting an issue-tracker comment) should happen during the planning phase. This should match Claude Code's own behavior, where plan mode never performs write operations.
When Implement is finally pressed, it should hand off the current plan — reflecting all the refinements made during the conversation — not a stale snapshot.
Actual behavior
1. Writes happen during planning. While the composer still showed Plan mode active (Implement never pressed), the model performed real, irreversible side effects:
- modified files in the working tree,
- created an external wiki/documentation page via an MCP integration,
- posted a comment on an external issue tracker via an MCP integration, mentioning/notifying several people.
A follow-up whose only intent was to specify where to place an output artifact (something like "put the document in folder X") appears to have been interpreted as approval to leave plan mode and execute — even though no approval was given and Plan mode was still active.
In a separate session the same behavior went further: from the plan-ready state, the model created and transitioned an issue-tracker ticket, posted comments on a pull request, edited files, created a git branch, and committed the changes — despite an explicit instruction to only plan the implementation.
2. "Implement" hands off an outdated plan snapshot. When Implement is finally pressed, the composer switches from Plan to Build and injects a PLEASE IMPLEMENT THIS PLAN: message containing a stale copy of the original full plan (all of the original "to-do" steps), rather than the latest refined plan / current state. Because the side-effecting work had already been carried out during the planning phase (symptom 1 above), the injected plan describes changes that were already done. The agent runs briefly and then reports that "the plan is already fully implemented", and the genuinely-pending follow-up actions the model had promised to do after approval are not what the Implement flow targets.
Impact
Major degradation or frequent failure — irreversible side effects (git commits, external ticket/doc/comment mutations, notifications to other people) performed without approval, from what is supposed to be a read-only planning phase. On top of that, the approval handoff replays an outdated plan, so Implement does redundant/no-op work instead of the actually-pending steps.
Version or commit
T3 Code (Alpha) 0.0.28 (fda6486233e0)
Environment
macOS · Claude provider (Claude Fable 5) · access level Full access · Plan → Build on Implement
Workaround
Switching the access level to Supervised stops writes during planning, since it forces an approval prompt on every command/file change — but it's very heavy-handed for a phase that should already be read-only.
Likely area / root-cause hypothesis
The plan-mode permission gate in the Claude adapter appears not to cover MCP tool calls or git/file writes. PR #3696 installs the SDK permission callback in plan mode and intercepts ExitPlanMode via canUseTool, which confirms plan-mode enforcement lives in the Claude adapter's permission-callback path (apps/server). The bug is that, before the plan is approved, that policy does not deny write / side-effecting tools — file edits, git commits, and MCP integration calls all execute. It also looks like a plainly-phrased planning instruction can be treated as implicit approval to leave plan mode, so the gate should not depend on how the follow-up is phrased.
The second symptom suggests the plan captured for the Implement handoff is a snapshot taken at initial plan proposal and is not updated as the plan is refined across subsequent turns, so approval replays an outdated plan.
Additional context
- Differs from #1884 (closed): that report was about Enter on a follow-up triggering implementation instead of "Iterate on plan." This is broader — Plan mode performs real writes and external MCP mutations before the plan is approved, regardless of the selected access level.
- Expectation is that Plan mode enforces read-only semantics independent of the access level (Full access / Auto-accept edits), the way Claude Code does natively, rather than requiring Supervised as a workaround.
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.
Research direction
Start in apps/server's Claude adapter permission-callback path, using PR #3696 as the entry point. Trace plan-mode handling for file, git, and MCP actions and how the current plan is stored across follow-up turns. Done means planning remains read-only until Implement and Implement uses the latest refined plan.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- typescript
- Domain
- backend, security
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 52/100