Skip to content

Plan mode

Plan mode is a sticky planning workflow independent of the session's stored ask, edits, or full-auto permission mode. Enter it with /plan, /plan PROMPT, the cockpit, or C-<tab> in the composer. Shift-TAB in the composer continues to cycle only ask -> edits -> full-auto -> ask, including while Plan is active. The composer displays both dimensions as [Plan · MODE]. Directive scope pauses Plan dispatch while preserving Plan for the return to chat; its composer chrome shows MODE and Plan paused. A session with an unfinished Goal cannot enter Plan; a completed Goal is historical and does not block it.

/plan PROMPT enters Plan and sends PROMPT through the ordinary UserPromptSubmit and skill-preparation transaction. Ordinary follow-up turns, including implementation requests, remain planning input until the user exits Plan or accepts a proposal.

Directive Plan before implementation

A top-level directive can independently enable Plan before implementation from its overlay or inspector Settings menu. Nested directive presentations use their owner's setting. The setting is off by default and does not enter sticky session Plan mode. Implement, Implement this, Request changes, and Retry first send the exact eventual implementation request through a read-only planning turn. Discuss is unchanged. Batch processing remains sequential: an enabled directive reaches approval and implementation before the next item starts.

Directive planning uses the directive's model and effort override when set; otherwise it resolves the preset's planning workload. Its proposal uses the ordinary <proposed_plan> parser and shared approval interaction. The directive card offers only implementation Mode, Model, Skills, Instructions, Accept, Feedback, and Cancel: execution is always Direct in the directive's bound session and current context. The selected mode and model are request-local implementation settings; they do not replace the session policy or the directive's planning model. Selection survives proposal feedback, while a fresh directive action starts with fresh defaults seeded with the directive's own skill selection (deduplicated by skill source); the card's selection at accept time is the single authority for that attempt. Browser feedback from a full or owner link continues that directive's planning conversation directly, with the current proposal as reference; it neither submits ordinary chat nor enters the host's composer. View links cannot answer the approval. Feedback captured from a replaced, cancelled, or invalidated attempt cannot restart its planning. If planning policy resolution or synchronous request startup fails, the proposal, selection, and approval attempt remain available for another feedback submission. Startup recovery does not roll back an attempt that has already settled or been replaced.

Directive skills

A directive's Settings menu also toggles skills on the workspace record, selected from the user-invocable roster of the directive's live bound execution session, else the workspace's active chat session (with no open session, selection is refused). The selection persists with the record, shows as a SKILLS: label line, and attaches to direct implementation-type prompts (Implement, Implement this, Request changes, Retry) with the accepted-plan handoff semantics: argument-free instruction mentions stored by canonical SKILL.md source that ignore skill model/effort, agent, hooks, and permission policy. Discuss never sees the attachments. Skill sources are revalidated at every dispatch; a missing, disabled, malformed, or no longer user-invocable selection starts no request and leaves the directive retryable, and batch processing skips that directive and continues.

The durable presentation progresses through Planning, Plan Ready, Plan Accepted, Implementing, and the ordinary terminal lifecycle. Planning turns, the current proposal, selection, and the exact accepted implementation prompt belong to the workspace directive record. Resume restores a pending proposal; cancel keeps the planning history as a draft; Continue Plan re-enters the directive composer scope. Editing the owner request or a nested detail invalidates an unstarted proposal; a late planning result cannot restore its approval. Each in-flight attempt has a transient identity shared by its record, session owner, and approval callbacks, so an old callback cannot publish, accept, or release a replacement attempt. Failed, aborted, malformed, and ownerless planning terminals remain cancelled drafts and release the session workflow before queued input resumes; resume does not recreate ownership for them. Rewind removes planning turns at and after the checkpoint and restores an accepted pre-attempt plan when it removes that plan's implementation attempt.

Only one root workflow owns a session at a time. Ordinary Plan cannot start while directive planning is active, and a directive cannot begin planning while ordinary Plan is active. Ordinary chat input uses the existing pending-input queue while directive approval owns the session.

Planning model policy

Every root Plan request resolves the current preset's planning workload at request realization. The resolved backend, model, and effort are local to that request; the session's ordinary model policy and chat buffer remain unchanged. Changing the preset therefore affects the next Plan request. Missing workload fields inherit the session policy, while an invalid workload fails before dispatch.

For example:

(:model-workloads ((planning :tier strong)
                  (plan-implementation :tier balanced)))

A single leading user-invoked inline skill may override the planning model or effort for that request. Instruction skills and model-side Skill calls do not. Retained agents keep their own workload policies. Plan Summary preparation uses the shared summarization workload.

The plan-implementation workload initializes the model and effort shown in approval for both ordinary Plan and directive Plan before implementation. It resolves from the owning chat buffer's preset, independently of the temporary planning model or a directive's planning override. Its default entry is empty, so unconfigured fields inherit the session policy. Invalid model policy prevents creating the initial approval selection; it never silently falls back. This workload does not select models for ordinary coding turns or delegated workers, which retain their own policy.

Tool boundary

Reading commands are allowed in Plan, not just native Read/Glob/Grep. Bash uses the shared read-only classification for file reading, searching, listing, comparison, path inspection and supported Git inspection. Pipes and &&, ||, ; compositions are allowed when every component is read-only. For example, git status --short && git diff --stat needs neither a broad Bash allow rule nor .git write authority. Read-only execution is hardened against shell startup and Git helpers; unsafe helper-dependent worktree inspection refuses rather than silently executing helpers. Explicit denials and ordinary resource permissions still apply. Unknown commands, output-file options, mutating compounds and unsupported shell constructs remain blocked. This rule is shared by standalone/sticky Plan, directive planning, and retained agents in a planning session. See Bash specifics.

Plan requests expose ApplyPatch for session-only work:// descendants, including retained agents, so durable plans and notes can be updated through the ordinary ApplyPatch path. Before materialization, the pipeline denies any proposal with an ordinary, shared, memory, or bare endpoint tree-wide; this includes mixed local/ordinary and ordinary-only proposals, and neither local nor ordinary targets are touched. Permission modes and explicit allow rules cannot widen this workflow boundary. Other edit tools and Eval remain unavailable: arbitrary Emacs Lisp cannot be classified reliably as read-only, including in a child process. Resource-address completion remains side-effect free. See address-to-resource.md.

Plan can delegate. Agent and the other agent tools stay available, so the planner can run independent investigations in parallel or ask an agent to critique a draft plan passed in its message. The Plan reminder says so; when to delegate is the model's call. Each agent turn started under Plan carries an immutable Plan read-only stamp. Its requests, nested agents and forked skills keep Plan's tool and Bash limits until that turn ends, even after the proposal is accepted or the user leaves Plan. A /review or /verify started during Plan is bound the same way. A later follow-up from an ordinary turn starts an ordinary turn. Skill preparation keeps the caller's stamp too, so a skill's ! commands follow Plan's Bash classification.

A Plan caller cannot steer an agent turn that runs outside Plan limits. SendMessage to a running agent is accepted only when the target's current turn is itself Plan read-only; SendMessage to /root is also accepted. Otherwise the call fails and suggests sending once the agent is idle, which starts a Plan read-only turn. Unread Plan-sender mail stamps any non-root activation that will read it, including a later direct assignment or deferred activation after the last sample or a capacity wait. Terminal RESULT records are information and do not carry the sender's Plan stamp. While sticky Plan is active this also refuses agents started before Plan was entered. Interrupting, listing and waiting are unaffected. Mail and results remain advisory text: a recipient that reads them later acts under its own authority at that time.

Directive Plan before implementation runs on the implementation preset's tool surface, bounded by the same Plan stamp, so it can delegate and use read-only Bash. Its boundary is stricter in one respect: its planning requests do not expose or allow ApplyPatch, including session-only proposals. Eval is unavailable as in every Plan request. Directive Discuss is unchanged; it keeps its own read-only capability ceiling, which denies delegation.

Proposal interaction

Only a completed root-assistant prose span can create a proposal. The last complete <proposed_plan>...</proposed_plan> block in that span becomes the one actionable proposal. A later proposal replaces it; an accepted user follow-up demotes it to a non-actionable draft while preserving the selected axes.

The first delivered reminder in a Plan episode includes the full preferred proposal shape. Later turns carry a one-line reference to the earlier contract and this manual, including after compaction. A cancelled dispatch does not mark the template delivered. Leaving and re-entering sticky Plan, or starting a new directive planning conversation, rearms the full template; feedback continues the existing episode. Reopening a session or starting a fresh child reestablishes its guidance independently. This is model guidance, not a parser-enforced schema: the proposal parser accepts any nonblank Markdown inside the tags.

The opening tag must end its line and the closing tag must occupy its own line. Both may be indented. Prose immediately before the opening tag is accepted: streaming can concatenate assistant messages without an intervening newline. Extraction and view hiding use the same delimiter rules, including while a proposal streams. If a Plan response contains at least one standalone proposal tag but no complete, nonblank proposal can be extracted, mevedel shows a warning explaining why approval is unavailable and asks you to have the assistant resend the full plan with correctly separated tags. It does not repair the transcript, publish a proposal, or leave Plan mode. Ordinary inline discussion of tag names, tool output, and injected agent output do not trigger this warning. Responses without proposal delimiters remain ordinary discussion; the diagnostic does not try to infer plan intent from prose.

Proposal guidance

Recover the complete Plan contract here when its earlier reminder is unavailable:

  • Inspect and discuss, not implement. Bash is limited to read-only-classified commands; Eval is unavailable. Standalone/sticky Plan permits ApplyPatch only for session-owned work:// descendants. Directive Planning permits no file writes. Children inherit these limits; delegate independent investigation or critique of a draft supplied in the task when useful.
  • Treat implementation requests as requests to produce or revise the plan. Explore available evidence first; ask only about genuine user preferences the evidence cannot resolve. Do not ask whether to proceed with implementation.
  • Finish with exactly one line-oriented block below. Every new block replaces the previous proposal completely. The opening tag ends its line; the closing tag occupies its own line.
<proposed_plan>
# Concrete Plan Title

## Summary
- Root cause or goal, behavior change, non-goals.

## Key Changes
- Group by subsystem or behavior; name files, APIs, interfaces, or data shapes only to remove ambiguity.

## Regression Coverage
- User-visible flows, edge cases, and failures to test.

## Validation
- Exact focused test/build commands.

## Assumptions
- Defaults, compatibility assumptions, unchanged behavior.
</proposed_plan>

The approval interaction has these axes:

Location Current Fresh Summary
Here yes yes yes
Worktree yes yes yes
  • Location: Here or Worktree.
  • Context: Current, Fresh, or Summary. Summary costs one additional model request.
  • Execution: Direct or Goal.
  • Budget: a positive Goal token limit, or Unlimited.
  • Mode: Ask, Edits, or Full-auto.
  • Model: the proposal-local implementation backend/model and reasoning effort.
  • Skills: canonical user-invocable skills attached to implementation.
  • Instructions: free-form multiline implementation-only guidance.

Keys are l for Location, c for Context, e for Execution, m or TAB for Mode, M for the proposal-local Implementation model selector, s to toggle skills, i to edit implementation instructions, and—when Goal is selected—b for Budget. The ordinary /model cockpit remains session-level. The instructions editor saves with C-c C-c and cancels with C-c C-k. RET accepts, f opens an editable feedback draft, q hides the approval, and C-g cancels. Location and Context are independent; the default is Here/Current, and switching to Worktree keeps Current. A Worktree starts at HEAD: uncommitted changes in the source checkout are not copied, apart from the files the session itself edited, which the fork restores. Accepting a Worktree proposal first checks that the session can fork (no pending input, request, live execution, active agent turn or active Goal), then asks for its branch name. Native acceptance uses the minibuffer; browser owner acceptance uses the card's branch input. Both validate the branch through the same Git checker before acceptance. While Worktree is selected, the card names whatever would refuse that check, in the same words as the refusal, so a queued follow-up is resolved in the Pending Inputs cockpit first instead of being discovered on RET. The notice that uncommitted changes stay behind comes from a git status check of about 40 ms; it runs when the card first shows and after each selection change, and other redraws, such as queue events and the control-transfer poll, reuse it. The blocker check is in memory and stays current on every redraw. Full and owner links can accept Here using the host-selected settings. Only owner links can accept Worktree; full links can still send feedback, and the host rejects forged full-link acceptance. Settings changes remain in Emacs.

Pending input remains available while the approval overlay is open. C-c TAB queues a follow-up without demoting or settling the proposal. Same-turn steering left from the Plan request must be delivered or resolved before acceptance. Queued follow-ups do not block a Here acceptance and run after the accepted implementation kickoff; a Worktree acceptance refuses them, because the planning session closes once its fork takes over. The same ordering applies while handoff preparation or retry owns the session.

The approval card keeps the Markdown proposal expanded above a compact Implementation section. Cycle keys appear beside their settings; accept, feedback, hide, and cancel remain in the action footer. Each setting is one screen row of the narrowest window showing the view, cut with an ellipsis and its full text on hover, and the Worktree notice takes the blank row above the actions the same way. Changing a setting therefore never changes the local card's height: the Context and Execution descriptions differ in length and wrapped below about 84 columns, and the notice used to add two or three rows. The cut applies to the local card only. The browser shows read-only Markdown with every setting, model, skill list, notice and full implementation instructions, without inactive native keyboard hints. A guest's approval information therefore does not depend on the host's split geometry. If the complete review exceeds the browser frame budget, the card explicitly directs the user to review and accept in Emacs instead of offering acceptance with truncated information; browser feedback remains available. The native card is laid out again when that width changes. A hidden approval stays pending and hidden across live-session redraws. RET or a mouse click on its 1 plan interaction-counter segment shows the card again; resuming a persisted session also shows it because hidden state is not persisted.

Direct remains the default and sends one ordinary implementation turn. Goal is an explicit opt-in that continues automatically until complete, genuinely blocked, paused, or budget-limited. When Goal is selected, the approval shows the proposal's target token budget. With Direct, the Budget row stays as a dimmed Goal execution only placeholder without a key, so cycling Execution never changes the card's height: with the composer anchored on its screen row, each toggle otherwise moved the card and the transcript above it by one row (ADR 0126). b accepts a positive integer; empty input means Unlimited. The setting starts from the effective session default, stays local to the pending proposal, survives Execution toggles and revised proposals, and on acceptance sets only the new Goal's budget, not the mevedel-goal-token-budget default. The first proposal resolves the plan-implementation workload and snapshots its model and effort into the same persisted selection. Later preset changes do not replace that selection. M changes only that implementation snapshot; choosing a model that cannot support the selected effort resets effort to its default. Cancellation, Plan exit, and acceptance all leave the ordinary session model, effort, and permission mode unchanged. Every implementation target and retry uses the accepted snapshot within its implementation scope.

Implementation-scoped policy

The accepted Model, effort, and Mode form one strict implementation policy. Direct captures it on the one implementation request; retries reuse the same accepted selection rather than resolving new defaults. Goal stores it on the durable Goal and uses it for every active ordinary root Goal turn, including user follow-ups, automatic continuation, and turns after /goal resume. Ordinary chat while the Goal is paused, blocked, budget-limited, or complete uses the session baseline. An already-admitted implementation turn retains its captured policy through settlement even if the Goal stops meanwhile.

Neither Here nor Worktree promotes these settings to session defaults. A Worktree fork copies the planning session's ordinary defaults and preset; the accepted selection is not installed as that baseline. Summary, control, directive, and unrelated child requests do not inherit an ambient Goal implementation policy. Directive implementation retains its own request-local selection on the common permission path.

Children started from an implementation turn inherit its permission-mode override for that child turn, including nested delegation, but retain their own model workload resolution. The override changes mode-based decisions only: current hard denies, shared permission rules, grants, and workflow ceilings remain effective. Views, permission logs, and reminders report effective request settings without changing stored defaults. There is no session-policy snapshot/restore cycle; user changes to the baseline remain intact.

The exact backend/model and effort must resolve at dispatch. An unavailable provider/model or unsupported effort fails visibly rather than falling back to the session model; an active Goal pauses on that runtime failure. A provider's structured rejection of an accepted model also leaves the baseline untouched, instead of applying ordinary session-model fallback recovery.

Acceptance and recovery

Acceptance archives the plan immutably, clears the interaction, exits Plan, and shows Preparing implementation.... It publishes and archives before it moves any proposal metadata, so an acceptance that fails before the immutable archive exists leaves the proposal exactly as it was and resume still offers it. That mirrors the rule for a failure after the archive, which stays accepted. Here/Current keeps the planning transcript. Fresh starts a new context with setup material and the accepted plan. Both Summary locations project the same effective source history and generate the shared eight-section handoff background. The accepted proposal is replaced in that evidence by an omission marker; the exact immutable plan and implementation-only instructions are supplied separately as relevance focus and remain authoritative. A Worktree implementation runs these same contexts in its fork; see Worktree implementation.

Summary applies that background through aggressive root compaction, with no verbatim tail, and therefore retains PreCompact/PostCompact, bounded request retries, segment rotation, persistence, and the new compact context epoch. The successful result is cached in the durable retry record, so a later implementation-start failure does not regenerate it.

Durable Plan descriptors contain only a normalized session-relative artifact path and its content hash. The qualified logical path is derived after the owning session is known; remote consumers read verified publication bytes for that logical artifact. Absolute source or publication paths are not part of Plan metadata or retry records.

When the prepared submission is ready, the view releases its Preparing implementation... row before kickoff.

After any valid location/context preparation, Direct submits its ordinary one-turn instruction. Goal instead constructs a Goal in the implementing session, using its own immutable accepted-plan path and the Plan-selected Goal budget. Its deterministic objective treats plan outcomes, constraints, and acceptance criteria as the completion contract while allowing mechanics to follow current repository evidence. The first canonical turn receives the prepared context, resolved artifact path, full accepted plan, and compact kickoff; the transcript stores that full input while the view shows Implement accepted plan as Goal.

The generated implementation turn goes through the ordinary deterministic skill planner. Skills selected with s are stored by canonical SKILL.md source and attached as argument-free instruction mentions. Live $skill mentions written in the i instructions editor use the same semantics and deduplicate with selected skills. Instruction attachments ignore skill model/effort, agent, hooks, and request permission policy. Their current source is reloaded at dispatch and retry; an explicitly bound skill that is missing, disabled, malformed, or no longer user-invocable leaves the accepted handoff retryable and starts no request. The transcript stores the full generated prompt while the rendered view keeps the compact implementation label, both live and after reconstruction. Prepared skill bodies travel in that model prompt and appear immediately in a separate collapsed attached-skills disclosure. Its expansion is independent of the Prompt drawer, hook context, and ordinary system-reminder batches; attachments do not increase the reminder batch count.

Previously user-invoked user-only skills retain their resolved invocation records across handoff. A redundant model-side Skill read returns the recorded prepared guidance in that conversation without re-running commands, injections, hooks or policy. It is not a new user invocation or permission grant; the guidance remains subject to the original task's scope and applicability.

Worktree implementation

A Worktree implementation is a Worktree Fork of the planning session at the reply that proposed the plan, so the fork carries the whole planning conversation into a linked worktree on the accepted branch, at .worktrees/<branch leaf>. The fork receives its own byte-identical accepted artifact and a retry record for the equivalent Here handoff, with repository-local skill paths retargeted to its checkout, and then runs the selected context and execution exactly as Here does: Current submits at once, Fresh rotates the fork's segment, Summary compacts the fork, and Goal lives in the fork. The fork's view takes over every window that showed the planning view, and the planning session, now saved with only its accepted-plan archive, is closed once the accepting command returns. Both sessions stay linked through the fork's recorded parent and fork point; the planning conversation remains reachable through the variant button at the plan reply.

If the planning session is shared, handoff shares the implementation fork and ends the old room with an explicit continuation notice. Each connected browser receives an Open link for the new room at its existing view, full, or owner tier; the old bearer never changes which session it names. An unshared planning session does not start sharing. If sharing the fork fails, the old room ends with an explicit handoff-failed notice and the native handoff still completes.

Each step is durable before the next. The source retry records the fork point, then the branch and directory reservation before any Git mutation, then the fork's save path once the fork transaction has published it. A retry reopens that fork, or finds the unique saved fork of this parent rooted at the reserved directory, instead of forking again; a published plan recognized by its hash is not installed again. The source's retry is cleared only after the fork holds its own, so at every point exactly one session owns the implementation. A directory that exists with no fork is refused with the fork transaction's cleanup command.

Acceptance is final even if preparation fails. The source session persists a bounded retry record, and mevedel-retry-plan-implementation resumes from the completed preparation step instead of recreating artifacts, summaries, or worktrees. A post-acceptance preparation failure settles the original approval; it never restores an action that could archive the same proposal again. Here and Worktree retries capture the same accepted implementation policy at dispatch without changing either session baseline. Goal execution reserves and persists its Goal ID in that record; a Worktree fork inherits the reservation. A retry reuses a Goal only when the reserved ID, accepted-plan reference, and stored implementation policy match; a different unfinished Goal or conflicting policy remains untouched and is reported as a conflict.

Goal construction is the Plan recovery boundary. The Goal, including its implementation policy and selected budget, is persisted before the retry is cleared and kickoff starts. Kickoff retains the exact Goal owner and reserved identity across publication. If that Goal is paused, cleared, replaced, edited, or given a different policy before dispatch, or another request starts, the stale kickoff is rejected without sending or pausing the current Goal. An actual startup failure pauses only the still-owned matching Goal with its runtime reason; recovery uses ordinary /goal resume, not Plan retry. Direct keeps the exact prepared retry record through request startup and clears it only when the canonical request settles successfully, whether gptel's FSM or an external engine such as Claude Code owns it. While kickoff authority is staged before admission, a competing ordinary composer submission is refused rather than inheriting that authority. Provider errors and aborts retain the record with the terminal reason for mevedel-retry-plan-implementation. Recorded reasons are bounded text: error data can carry whole requests or sessions, so printing is depth-limited and truncated rather than copying transcripts into the record and echo area. If recovery finds the matching Goal already durable but paused by session restore, it reactivates it without scheduling before retrying the owned kickoff, preventing both duplicate Goals and duplicate continuations.

For Goal execution, non-command input submitted after acceptance queues behind the reserved kickoff, in the fork for a Worktree implementation. Each queued follow-up then runs as its own Goal turn before automatic continuation. Paused kickoff-owned input remains held until resume.

Plan activity, proposal identity, selection, artifact descriptors, and retry state persist in session metadata. Resume reconstructs an approval only when Plan is active, metadata says proposed, and the current artifact still matches its recorded hash. Persisted proposals without a valid implementation model snapshot are demoted to drafts. Drafts never reactivate automatically.

A failed approval renderer dismisses the interaction without touching that metadata, so the proposal stays restorable: only a user cancellation discards the selection. A directive-owned approval still settles its caller, because a waiting batch must not hang on a rendering bug.