Every coding agent ships a mode that says: think first, don't write code yet. They all call it Plan Mode. They all want the same thing — a model that explores a codebase, reasons about architecture, and produces a plan before touching a single file. The interesting part is how differently they enforce that contract.

I spent an evening reading the source code of five implementations: Claude Code, Codex, Gemini CLI, Kilocode, and OpenCode. Not the docs — the actual code. Tool definitions, permission systems, prompt templates, state machines. What I found is a clean philosophical split hiding beneath superficially similar features.

The Core Idea

Plan Mode, in every implementation, means: the model should read, search, and reason. It should not edit files, run destructive commands, or make commits. When it has a plan, it should present it. The user decides when to execute.

That's the invariant. Everything else — how the model enters and exits the mode, how tools are restricted, where the plan lives, what happens when the model tries to cheat — diverges immediately.

Three Philosophies

The five implementations fall into three camps, and the camps reveal something about how each team thinks about the relationship between a language model and the system it runs inside.

Trust the model

Claude Code takes the most permissive approach. When Plan Mode is active, the system injects a <system-reminder> message into the conversation that says, essentially: you MUST NOT edit files, you MUST NOT run non-readonly tools, this supersedes all other instructions. Strong language. But at the code level? Every tool remains available. No permission check fires. No call is blocked. If the model decides to ignore the instruction and call FileWrite on your production config, nothing stops it.

This isn't negligence — it's a design choice. Claude Code's enforcement is entirely prompt-based because Anthropic trusts the instruction-following capability of its models. The architecture is simpler for it. There's no permission layer to maintain, no allowlist to keep in sync with new tools. The contract lives in natural language, and the model is expected to honour it.

Trust the system

Gemini CLI sits at the opposite end. It ships a plan.toml policy file with a catch-all deny rule at priority 60 and explicit allow rules at priority 70 for a hardcoded list of read-only tools: glob, grep_search, read_file, list_directory, google_web_search, ask_user, and a few others. Everything else — including shell — is denied before execute() is ever called. The model receives an error message as tool output and has to work within the constraint.

Write tools get special treatment: write_file and replace are allowed, but only when the file path matches a regex for .md files inside the designated plans directory. Try to write anywhere else and the policy engine blocks it. This is the only implementation where shell is hard-blocked in Plan Mode. Everyone else allows bash and hopes the prompt keeps the model honest.

Kilocode and OpenCode (which share a codebase — Kilocode forked from OpenCode) take a middle path. They implement Plan Mode as a separate agent with its own permission ruleset. The plan agent has edit: { "*": "deny" } with explicit exceptions for plan files in .kilo/plans/*.md or .opencode/plans/*.md. If the model calls an edit tool on any other path, the permission system rejects it at execution time. But bash is still allowed — the prompt instructs read-only usage, but there's no technical barrier.

Trust the user

Codex is the most minimal. Plan Mode changes the system prompt and… that's about it. Shell tools, file tools, everything remains available with enforcement purely via the prompt. The one hard block is a runtime error on update_plan — a checklist/progress tool meant for execution mode, not planning. The model can't call it during planning because the handler checks the mode and returns an error string.

But the real minimalism is in the output: Codex doesn't write a plan file to disk. The model wraps its plan in <proposed_plan> XML tags in its response. A custom stream parser — ProposedPlanParser in the Rust core — extracts these segments in real-time and renders them as a distinct UI element. The plan lives in conversation history, not on the filesystem. When the user switches back to Default mode, the plan is right there in the context for the model to reference.

The transition is entirely manual. There's no exit_plan_mode tool. The user types /collab or clicks a mode toggle. Codex's position is: the plan is output, the user reads it, the user decides. Minimum mechanism.

The enforcement spectrum, from hard to soft:

Gemini CLI (policy engine, catch-all deny, shell blocked) → Kilocode/OpenCode (permission system, edits blocked, shell allowed) → Codex (one tool hard-blocked, rest prompt-based) → Claude Code (entirely prompt-based, nothing technically prevented)

How You Get In and Out

Entry and exit mechanisms reveal how much autonomy each system gives the model.

Claude Code is unique: the model can enter Plan Mode on its own. The EnterPlanMode tool is available during normal operation, and the system prompt instructs the model to call it when it encounters tasks involving "architectural complexity" or "10+ files." The model self-escalates. No other implementation does this. Exit requires user approval — ExitPlanMode presents the plan and the user must confirm.

Gemini CLI also allows model self-entry via an enter_plan_mode tool, but with a confirmation dialog: the user sees "This will restrict the agent to read-only tools" and must approve. Four total entry paths exist: CLI flag (--approval-mode=plan), /plan slash command, Shift+Tab cycling, or natural language triggering the tool. Exit goes through exit_plan_mode, which presents a three-way choice: approve with auto-edit, approve with manual review, or reject with feedback.

Kilocode and OpenCode are user-initiated only. The plan_enter tool exists in the codebase but is commented out. The user selects the plan agent in the UI; the model calls plan_exit (a no-parameter fire-and-forget tool) when done.

Codex is the simplest: /plan to enter, manual mode switch to exit. No tools involved in the transition at all.

What Gets Injected

All five inject Plan Mode instructions into the conversation rather than modifying the static system prompt. But the mechanism and content differ meaningfully.

Claude Code and Kilocode/OpenCode both wrap instructions in <system-reminder> XML tags and inject them as synthetic messages. Claude Code uses a synthetic user message with an isMeta: true flag. Kilocode appends a synthetic text part to the last user message — riding inside the conversation turn rather than beside it. Both describe a 5-phase workflow: explore (with parallel subagents), design, review, write plan file, call exit tool.

Claude Code has four instruction variants: a full 5-phase prompt on first entry, a sparse reminder on subsequent turns (saving tokens), an ultraplan variant for remote planning sessions, and a sub-agent variant. This is the most sophisticated prompt management of the five.

Codex injects a developer message wrapped in <collaboration_mode> tags. Its phase model is different from everyone else's — three conversational phases (ground in environment, discuss intent with user, discuss implementation with user) rather than autonomous exploration. Codex expects the model to talk to the user during planning. The others expect the model to go explore and come back.

Gemini CLI goes furthest: it replaces an entire section of the system prompt. When Plan Mode is active, the primaryWorkflows section is swapped out for planningWorkflow. This is the closest any implementation gets to actually changing the system prompt rather than injecting conversation-level instructions. The planning prompt includes a 4-phase workflow (explore, consult, draft, review) and — notably — the available tool list is generated dynamically from the live tool registry and included in the prompt itself.

Where the Plan Lives

Three of the five write a Markdown file to disk. One writes it inline. The locations reveal different opinions about whether a plan is a project artifact or a conversation artifact.

ImplementationPlan artifactLocationVersioned in git?
KilocodeMarkdown file.kilo/plans/<timestamp>-<slug>.mdYes (VCS projects)
OpenCodeMarkdown file.opencode/plans/<timestamp>-<slug>.mdYes (VCS projects)
Claude CodeMarkdown fileDisk path from internal functionDepends on location
Gemini CLIMarkdown file~/.gemini/tmp/<project>/<session>/plans/No (outside project)
CodexInline block<proposed_plan> tags in model outputNo (conversation history)

Kilocode and OpenCode's choice to put plans inside the project directory and version them is interesting — it means plan files show up in git log, can be referenced in PRs, and persist beyond the session. Gemini deliberately stores plans outside the project tree, keeping them ephemeral. Codex's inline approach means the plan is inseparable from the conversation that produced it.

The Interesting Outliers

Gemini's model routing

When using an auto model alias, Gemini CLI routes Plan Mode requests to Gemini Pro and post-approval execution to Gemini Flash. No other implementation changes the underlying model based on whether you're planning or executing. This is arguably the smartest practical optimisation in the bunch: you want your best reasoner for architecture and your fastest model for implementation. The feature is configurable — you can disable it in settings.json — but the default is on.

Gemini's three-way approval

When Gemini's model calls exit_plan_mode, the user doesn't get a yes/no dialog. They get three choices: approve and auto-accept all subsequent edits, approve but manually review each edit, or reject with written feedback that goes back to the model for revision. This is the only implementation that lets you calibrate your trust level at the moment you've seen the plan — which is exactly when you have the best information to decide.

Gemini's collaborative editing

During plan review, pressing Ctrl+X opens the plan file in the user's configured editor. You can rewrite steps, leave inline comments, save, and the model re-reads the file and responds to your changes. This treats planning as genuinely collaborative rather than propose-accept/reject.

Claude Code's ultraplan

Claude Code has a variant called ultraplan where a separate remote session does the planning work, writes the plan file, and hands it back to the local session. The local session's only job is to call ExitPlanMode and present the result. There's also a swarm/teammate path where ExitPlanMode sends the plan to a "team-lead" agent for approval rather than a human. These are the earliest signs of multi-agent planning workflows in production coding tools.

Codex's stream parsing

Codex parses <proposed_plan> blocks out of the model's streaming output in real-time using a dedicated ProposedPlanParser in the Rust core. Plan deltas are emitted as EventMsg::PlanDelta events, rendered as a distinct UI element separate from the regular assistant message. Agent messages are deferred during plan-mode streaming — they only start when non-whitespace, non-plan text arrives, so a plan-only response never creates an empty message bubble. This is the most sophisticated streaming handling of the five.

Codex's update_plan (not what you think)

Codex has a tool called update_plan that sounds like it belongs in Plan Mode but is explicitly blocked there. It's a progress tracker for execution mode — the model calls it with a list of steps and their status (pending, in_progress, completed) to render a live checklist in the UI. The handler returns a hard error if called during planning. The prompt warns: "Do not confuse it with Plan mode." The name collision is unfortunate but the separation is clean.

What's Universal

After reading five implementations, the convergences are as telling as the divergences:

What This Means

The philosophical split — trust the model vs. trust the system vs. trust the user — isn't going to resolve. It's a genuine design tension with no correct answer, because the right choice depends on what you're optimising for.

If you trust models to follow instructions reliably, Claude Code's approach is elegant: minimal mechanism, no permission layer to maintain, no allowlist that falls out of sync when you add a new tool. The failure mode is catastrophic but, the argument goes, increasingly unlikely as models improve.

If you don't trust models that much — or you're building for users who shouldn't have to — Gemini's policy engine is the most defensible design. The catch-all deny with explicit allows is the same pattern used in firewalls, file permissions, and capability systems. It fails safe. The cost is complexity and the perpetual risk of blocking a tool the model legitimately needs.

Codex's minimalism has its own appeal. The plan is just text in a conversation. The user is in control. There's almost no mechanism to break, maintain, or explain. It's the most honest about what Plan Mode actually is: a prompt that says "think before you act," wrapped in just enough UI to make the thinking visible.

The fact that all five arrived at the same core idea independently — and then diverged so sharply on enforcement — suggests the idea is robust even if the implementations aren't settled. Plan Mode solves a real problem. How to enforce it is still an open question.

Researched by dispatching parallel sub-agents — one per codebase — to read source code, tool definitions, permission systems, and prompt templates. Synthesised from their reports. All analysis is based on source code as of March 2026.