ReAct decides the next step after seeing the last result, which is powerful and means you cannot see where it is going until it gets there. Plan-and-execute inverts that: produce the whole plan first, then execute it.
// 1. plan, schema'd so steps are inspectable, not prose
const { object: plan } = await generateObject({
model,
schema: z.object({
steps: z.array(z.object({
description: z.string(),
files: z.array(z.string()),
risk: z.enum(['low', 'medium', 'high']),
})),
}),
prompt: `Plan how to: ${task}. Do not make any changes yet.`,
})
// 2. the gap where a human reads it. most of the value is here
const risky = plan.steps.some((s) => s.risk === 'high')
if (risky) await approve(plan)
// 3. execute, one step at a time
for (const step of plan.steps) {
await execute(step)
await checkpoint(step) // resumable if step 4 of 9 fails
}That gap between step 1 and step 3 is the pattern. A bad plan is cheap to reject and expensive to discover halfway through.
What it buys
- Review before cost. You see the shape of the work while changing it still costs nothing.
- A visible scope. "Nine steps touching four files" is something you can disagree with. A ReAct agent gives you that information only in retrospect.
- Natural [checkpoints](/context-engineering-dictionary/checkpoint). Steps are boundaries, so a failure at step six resumes at six.
What it costs
The plan is written with the least information the agent will ever have: before any file is read, any test run, any error seen. When reality diverges, a rigid plan marches on regardless.
The usual fix is to re-plan rather than abandon planning:
for (const step of plan.steps) {
const result = await execute(step)
if (result.surprising) {
plan = await replan(task, { done: completed, discovered: result.details })
}
}Which is really a hybrid, and hybrids are what most good agents are: plan for scope and reviewability, ReAct within a step where the path is genuinely unknown.
Related terms
ReAct
ReAct interleaves reasoning and acting: the model thinks, takes one action, reads the result, and thinks again. It is the loop underneath most agents, and its defining property is that the next step is chosen after seeing the last result.
Read definition →PatternProvenPrompt chaining
Prompt chaining breaks a task into a fixed sequence of steps, feeding each step’s output into the next. It is the simplest workflow pattern, and it beats one giant prompt whenever a task has natural stages.
Read definition →PatternValidatedOrchestrator-workers
Orchestrator-workers has a central model decide how to break a task down at run time, dispatch the pieces to workers, and combine what comes back. It is parallelization for tasks whose shape you cannot know in advance.
Read definition →PatternValidatedCheckpoint
A checkpoint is a deliberate save point holding enough state to resume a task from there. It turns a long run from something that either finishes or is lost into something that can be picked up.
Read definition →