plan / act modes: two roles under one architecture
Responsibilities
Cline splits "talking with the user" and "actually modifying files" into two modes (plan and act), explicitly typed as Mode = "plan" | "act" (Mode type:14). A Task instance belongs to exactly one mode; switching modes rebuilds the Task, so within a single task the mode is fixed. This mode parameter flows from buildApiHandler all the way into the ApiHandler, and from attemptApiRequest into the context of getSystemPrompt, threading through the whole stack.
It serves two core purposes. First, it affects ApiHandler selection — buildApiHandler picks the provider from either planModeApiProvider or actModeApiProvider based on the mode (mode provider:520), so plan and act can be wired to different models and different thinkingBudget values. Second, it affects the content of the ACT_VS_PLAN component in the system prompt and the availability hints for certain tools (act_vs_plan template:5).
Design motivation
- Two ApiConfiguration sets for plan / act:
planModeApiProviderandactModeApiProviderare two independent fields, both defaulting toDEFAULT_API_PROVIDER(planModeApiProvider:243). Users can route plan through a cheaper model for fast discussion and act through a stronger model for actual code changes. - Mode threads through handler construction: after
createHandlerForProviderreceives the mode, it picks from paired fields likeplanModeApiModelId / actModeApiModelId,planModeReasoningEffort / actModeReasoningEffort, andplanModeThinkingBudgetTokens / actModeThinkingBudgetTokens(mode-aware options:94). Every "thinking budget", "reasoning effort", and "model id" is isolated by mode. - plan_mode_respond is plan-exclusive: the
plan_mode_respondtool description explicitly statesThis tool is only available in PLAN MODE. Act mode does not block this tool at runtime, but theACT_VS_PLANsection in the system prompt tells the model thatplan_mode_respondis not available in ACT MODE (ACT MODE exclusion:9). - The main ACT MODE toolset: of the 18 tools declared in the generic variant, only
PLAN_MODE = "plan_mode_respond"is plan-exclusive. The others —execute_command / read_file / write_to_file / replace_in_file / search_files / list_files / attempt_completionand so on — are available in both modes (generic tools:58). Act mode relies on this set to modify files, run commands, and wrap up withattempt_completion. - yoloMode affects the plan prompt:
getActVsPlanModeTemplateTextcheckscontext.yoloModeToggled !== trueand only adds the hint "you can use ask_followup_question to ask clarifying questions" to the plan description when yolo mode is off (yolo guard:18). In yolo mode the model does not proactively ask. - needs_more_exploration parameter:
plan_mode_respondcarries an optional boolean parameterneeds_more_exploration(needs_more_exploration:38), letting the model say "I still need to read a few more files" after writing its response, so it is not locked into its initial plan.
Key files
Mode type:14—type Mode = "plan" | "act", only these two values.buildApiHandler:517— Entry point; picks the provider fromplanModeApiProvider / actModeApiProviderand forwards mode tocreateHandlerForProvider.anthropic case mode-aware:94— Thecase "anthropic"branch readsapiModelId / reasoningEffort / thinkingBudgetTokensfrom the paired fields by mode.mode provider pick:520—const apiProvider = mode === "plan" ? planModeApiProvider : actModeApiProvider.planModeApiProvider default:243— Both fields default toDEFAULT_API_PROVIDER; plan/act use the same provider when the user has not configured them explicitly.act_vs_plan template:5— The template for the ACT_VS_PLAN section in the system prompt; defines each mode's tool availability and behavioral expectations.ACT MODE description:9— ACT MODE can use every tool except plan_mode_respond, and finishes with attempt_completion.PLAN MODE description:11— PLAN MODE can only respond with plan_mode_respond; the goal is to gather information before producing a plan.yolo mode guard:18— In yolo mode the "you can ask clarifying questions" hint is dropped.plan_mode_respond generic:25— Spec for the plan-mode-only tool, with three parameters:response / needs_more_exploration / task_progress.PLAN MODE only constraint:7— The description statesThis tool is only available in PLAN MODE; the model self-constrains based on the prompt.act_mode_respond description:29— Act-mode-only tool used to report progress without interrupting the execution flow; cannot be called consecutively.generic tools list:58— The 18 tool ids declared by the generic variant, covering both plan and act tools.Task mode field:585— Task construction callsbuildApiHandlerwith themodeparameter from TaskParams.
Data flow
Mode propagation is one-directional and linear: a Task receives a mode at construction, that mode decides which branch buildApiHandler takes, and then attemptApiRequest passes the same mode into the system prompt layer via SystemPromptContext.providerInfo.mode:
// apps/vscode/src/core/api/index.ts
export function buildApiHandler(configuration: ApiConfiguration, mode: Mode): ApiHandler {
const { planModeApiProvider, actModeApiProvider, ...options } = configuration
const apiProvider = mode === "plan" ? planModeApiProvider : actModeApiProvider
// ... thinkingBudget limits ...
return createHandlerForProvider(apiProvider, options, mode)
}Every case in createHandlerForProvider selects fields by mode. The Anthropic branch is typical:
// apps/vscode/src/core/api/index.ts
case "anthropic":
return new AnthropicHandler({
onRetryAttempt: options.onRetryAttempt,
apiKey: options.apiKey,
anthropicBaseUrl: options.anthropicBaseUrl,
apiModelId: mode === "plan" ? options.planModeApiModelId : options.actModeApiModelId,
reasoningEffort: mode === "plan" ? options.planModeReasoningEffort : options.actModeReasoningEffort,
thinkingBudgetTokens:
mode === "plan" ? options.planModeThinkingBudgetTokens : options.actModeThinkingBudgetTokens,
})The mode === "plan" check is repeated across more than 30 cases, which looks verbose, but the upside is that each branch explicitly tells the reader "there are plan/act pairs here" without relying on field-naming conventions. The ACT_VS_PLAN section in the system prompt is rendered from context:
// apps/vscode/src/core/prompts/system-prompt/components/act_vs_plan_mode.ts
const getActVsPlanModeTemplateText = (context: SystemPromptContext) => `ACT MODE V.S. PLAN MODE
In each user message, the environment_details will specify the current mode. There are two modes:
- ACT MODE: In this mode, you have access to all tools EXCEPT the plan_mode_respond tool.
- In ACT MODE, you use tools to accomplish the user's task. Once you've completed the user's task, you use the attempt_completion tool to present the result of the task to the user.
- PLAN MODE: In this special mode, you have access to the plan_mode_respond tool.
- In PLAN MODE, the goal is to gather information and get context to create a detailed plan for accomplishing the task, which the user will review and approve before they switch you to ACT MODE to implement the solution.
// ...`Note that it does not render different templates per mode; instead it writes both modes' rules into the same prompt and lets the model pick a path based on the environment_details.mode field (environment_details mode:7). The actual "select tools by mode" happens in ClineToolSet.getEnabledTools, which filters the tool list based on context.providerInfo.mode (ApiProviderInfo.mode:75).
Boundaries and failure modes
- No hard block on plan using an act-exclusive tool:
getEnabledToolsfilters by thevariant.toolslist and does not separately check mode at runtime to excludeplan_mode_respond(getEnabledTools:87). The generic variant declares bothPLAN_MODEandATTEMPT, so the model mainly self-constrains via the system prompt. - Switching mode rebuilds Task: a Task stores its mode at construction; switching mode mid-run triggers a new Task construction rather than mutating a field.
buildApiHandleris called only once during Task construction (buildApiHandler call:585). - planModeApiProvider default:
DEFAULT_API_PROVIDERis the shared default for both plan and act (planModeApiProvider default:243). A new user's first Cline run uses the same provider for both modes, so behavior is identical. - thinkingBudget is separately limited for plan / act:
buildApiHandlerreadsmode === "plan" ? planModeThinkingBudgetTokens : actModeThinkingBudgetTokensand applies a separate maxTokens cap (mode budget:525). Plan's budget never leaks into act or vice versa. - yoloMode conflicts with plan: when
yoloModeToggled === true, the plan section drops the "you can ask ask_followup_question" hint (yolo guard:18). But yolo mode is fundamentally about skipping user confirmation and auto-executing, which is in tension with plan's "discuss before executing" philosophy. In practice, yolo users rarely use plan. - act_mode_respond consecutive-call block: the
act_mode_respondtool description explicitly states "cannot be called consecutively or it will fail" (CRITICAL CONSTRAINT:43), enforced by a runtime check. - needs_more_exploration self-correction: after writing a plan, plan_mode_respond can still say "I need more exploration" by setting
needs_more_exploration=true, which routes the next turn through exploration tools instead of wrapping up (needs_more_exploration:38). This gives the model a self-correction exit.
Summary
The plan / act split is the line Cline draws between "discussing an approach" and "actually changing code". In implementation it is a single Mode = "plan" | "act" type plus a set of paired configuration fields. The design tradeoff is: rather than dynamically switching mode at runtime, every mode switch rebuilds the Task, so handler / prompt / toolset are all rebuilt together and state isolation is clean. The model self-constrains which tool to use via the ACT_VS_PLAN section in the system prompt; runtime interception is minimal.
- How the toolset is filtered by context:
/prompts/toolset - How the system prompt is assembled:
/prompts/prompt-builder - How mode affects handler selection:
/providers/api-handler