Lesson 2 - Task Decomposition
Welcome to Task Decomposition
You just saw why an agent needs reasoning structure on hard tasks. Now you’ll build the first pattern that adds it. The instinct is one you already use yourself: faced with something big — “plan a budget 3-day autumn trip in Japan” — you don’t try to answer in one breath. You break it down. First pick a region and season, then work out a daily budget, then draft the itinerary. Each step is small enough to do well, and each one sets up the next. That’s task decomposition, and it powers the plan-then-execute pattern: ask the model to lay out an ordered list of steps before doing any work, then carry them out one at a time. This lesson builds it for real on Atlas, our travel-planning agent — and the whole thing layers onto the same Claude client you already have.
By the end of this lesson, you will be able to:
- Explain decomposition as a “plan first, then act” step that runs before the agent does any work
- Get the model to produce an ordered list of steps and parse it into something your code can loop over
- Execute each step in order while threading prior results forward so later steps build on earlier ones
- Recognize when plan-then-execute is the right pattern and when its commit-up-front nature is a liability
Let’s start with the core idea.
Decomposition Is “Plan First, Then Act”
The whole pattern rests on a single separation: planning is a different job from doing. When you ask a model to answer a hard, multi-part request in one shot, it has to figure out the structure and fill in the content at the same time — and under that double load it tends to skip a part, answer out of order, or blur two steps together. Decomposition pulls those jobs apart. First, a dedicated planning pass produces nothing but an ordered list of steps. Then a separate execution pass works through that list, one step at a time, each step a small focused task.
So the shape is: plan, then execute. The agent first decomposes the goal into an ordered sequence of sub-steps, then carries them out in order — and, crucially, feeds the result of each step forward so the next step can build on it. Get those three moves right and a vague request becomes a sequence the agent can actually carry out.
Notice where this sits relative to the other patterns in this module. Decomposition does its thinking before acting — it commits to a plan up front. ReAct (next lesson) thinks during the loop, and reflection (Lesson 4) thinks after the result is in hand. They’re complementary, and we’ll come back to how decomposition trades off against ReAct once you’ve seen it run.
Stage 1: The Plan
Everything starts by asking the model to plan. We make one model call whose only job is to turn the goal into an ordered list of steps — no work yet, just structure. We ask for the steps “one per line, no numbering,” which keeps the output easy to parse, and we cap the count (“2-5 short ordered steps”) so the plan stays focused rather than sprawling.
plan_resp = client.messages.create(
model=model, max_tokens=512, system=system,
messages=[{"role": "user",
"content": f"Break this goal into 2-5 short ordered steps, "
f"one per line, no numbering:\n{goal}"}])
plan_text = "".join(b.text for b in plan_resp.content if b.type == "text")
steps = [line.strip("-• ").strip() for line in plan_text.splitlines() if line.strip()]We pull the text out of the response blocks the same way you have all module. Then comes the parse: the plan arrives as a block of text with one step per line, and we turn it into a Python list the execution loop can iterate over. The list comprehension splits on newlines, drops any blank lines, and strips off leading bullet characters or dashes ("-• ") in case the model added them despite the “no numbering” instruction. The result is steps — a clean, ordered list of short instructions. That’s the entire planning pass: a vague goal in, an ordered checklist out.
Stage 2: Execute, Threading Results Forward
A plan you ignore is just a wish, so now we carry the steps out — in order, one at a time. For each step we make its own model call, and here’s the move that makes decomposition more than a checklist: we feed the results of earlier steps into the prompt for the current one.
done = []
for i, step in enumerate(steps, 1):
context = "\n".join(f"- {s}: {r}" for s, r in done) or "(nothing yet)"
step_resp = client.messages.create(
model=model, max_tokens=256, system=system,
messages=[{"role": "user",
"content": f"Goal: {goal}\nDone so far:\n{context}\n"
f"Now carry out this step and report the result:\n{step}"}])
result = "".join(b.text for b in step_resp.content if b.type == "text")
done.append((step, result))
print(f"Step {i}: {step}\n -> {result}")Walk through the threading carefully, because it’s the heart of the lesson. done is a running list of (step, result) pairs — everything finished so far. Before each new step, we build a context string from done: a few bullet lines summarizing what’s already settled (or the literal "(nothing yet)" on the very first step, when done is empty). That context goes into the prompt as “Done so far,” so the model executing step 3 can see the region chosen in step 1 and the budget set in step 2. After the call, we append the new (step, result) to done, and the next iteration threads it forward in turn.
This is what separates a plan from a checklist. If each step ran in isolation — same loop, but without the done/context part — step 3 would draft an itinerary with no idea which region step 1 picked or what budget step 2 set. You’d get three answers that don’t fit together. Threading results forward is what makes the steps build on each other instead of merely sitting next to each other.
One simplification worth naming: here each step is a single model call, deliberately. In a fuller agent, any step could itself kick off the agent loop from Module 2 — calling tools to look things up, do math, or check a source. We keep each step a single call here so the decomposition idea stands on its own, uncluttered. The pattern is the same either way: plan into steps, then execute each one, threading results forward.
The Full Orchestration
Here are both stages assembled into one function — the plan pass, then the execute loop:
def run_plan_then_execute(client, goal, *, system, model="claude-haiku-4-5"):
# Phase 1: ask the model for an ordered plan (one step per line).
plan_resp = client.messages.create(
model=model, max_tokens=512, system=system,
messages=[{"role": "user",
"content": f"Break this goal into 2-5 short ordered steps, "
f"one per line, no numbering:\n{goal}"}])
plan_text = "".join(b.text for b in plan_resp.content if b.type == "text")
steps = [line.strip("-• ").strip() for line in plan_text.splitlines() if line.strip()]
# Phase 2: execute each step, threading prior results forward.
done = []
for i, step in enumerate(steps, 1):
context = "\n".join(f"- {s}: {r}" for s, r in done) or "(nothing yet)"
step_resp = client.messages.create(
model=model, max_tokens=256, system=system,
messages=[{"role": "user",
"content": f"Goal: {goal}\nDone so far:\n{context}\n"
f"Now carry out this step and report the result:\n{step}"}])
result = "".join(b.text for b in step_resp.content if b.type == "text")
done.append((step, result))
print(f"Step {i}: {step}\n -> {result}")
return {"plan": steps, "results": done}Run it on the goal “Plan a budget 3-day autumn trip in Japan,” and you can watch decomposition do its job:
Step 1: Pick a region and season
-> Kyoto in autumn — mild weather, fall foliage.
Step 2: Estimate a daily budget
-> About $90/day: hostel $35, food $30, transit/sights $25.
Step 3: Draft a 3-day itinerary
-> Day 1 temples, Day 2 Arashiyama, Day 3 food markets.Look at how the steps connect. Step 1 settles on Kyoto in autumn. Step 2 doesn’t budget in a vacuum — it estimates a daily figure that fits a trip like the one being planned. And step 3 drafts an itinerary that’s clearly for Kyoto — temples, Arashiyama, food markets are Kyoto specifics, not generic placeholders. That coherence is the done/context threading paying off: each step saw what came before and built on it. The plan pass gave the run its shape; the threaded execution gave it consistency.
Decomposition is mostly a prompting move
Notice there’s no new framework here — just two prompts and a loop. The first prompt asks for a plan; the second asks the model to carry out one step “given what’s done so far.” Most of decomposition’s power comes from that simple ask: plan before you act, and let each step see the last. You can dial it up (richer step prompts, tool calls inside a step) or down (a single “outline then answer” prompt), but the lever is the same — separate planning from doing, and thread results forward so the steps cohere.
Plan-Then-Execute vs. ReAct: The Trade-off
Plan-then-execute has a real strength and a real limitation, and it’s worth being precise about both, because the next lesson exists to fix the limitation.
The strength: it commits to a plan up front. When the steps are knowable in advance — and for a trip like this they are: pick where, set a budget, draft days — a clear plan keeps the agent organized, prevents it from wandering, and makes the run easy to follow and debug. You can see the whole sequence before a single step executes.
The limitation is the flip side of that same commitment: it can’t adapt mid-flight. The plan is fixed before execution begins, so if an early result changes what the right steps are, plan-then-execute has no way to revise. Imagine step 1 discovered the chosen region was fully booked for autumn — the remaining steps (budget it, plan its itinerary) are now pointed at the wrong place, but the loop marches on through them anyway. Decomposition planned once and is committed.
That’s exactly what ReAct, the next lesson, fixes. Instead of planning everything up front, ReAct interleaves reasoning and acting during the loop — think, act, observe, think again — so it can change course the moment a result invalidates its assumptions. The rule of thumb: reach for plan-then-execute when the steps are predictable, and for ReAct when the path depends on what you discover along the way. They’re not rivals — a serious agent often plans at a high level and reasons adaptively within each step.
Practice Exercises
Exercise 1: Plan or no plan?
For each task, decide whether an explicit plan-then-execute pass earns its keep or is overkill: (a) “What’s the time difference between Kyoto and New York?” (b) “Plan a budget 5-day trip that picks a region, sets a daily budget, and drafts an itinerary.”
Hint
(a) is a single step — one lookup and done; decomposing it into a plan just adds an extra model call for no gain. (b) is exactly where decomposition shines: it’s multi-part with steps that depend on each other (the budget and itinerary both hinge on the region), so planning the ordered steps up front — and threading each result forward — keeps the agent organized and the output coherent. The rule: reserve plan-then-execute for tasks whose steps are several and knowable in advance.
Exercise 2: Why thread done forward?
The execute loop builds a context string from done and feeds it into each step’s prompt. Suppose you deleted that — each step ran with only the goal and the step text, never seeing prior results. What would break in the verified run, and why?
Hint
The steps would stop building on each other. Step 3 (“draft a 3-day itinerary”) would have no idea step 1 picked Kyoto, so it might draft a generic or even contradictory itinerary; step 2 (“estimate a daily budget”) wouldn’t be anchored to anything chosen earlier. You’d get three plausible-looking answers that don’t fit together — Kyoto temples next to a Tokyo budget next to an Osaka itinerary. Threading done forward is the difference between a plan (steps that compound) and a mere checklist (independent items run in sequence). That coherence — Kyoto in step 1, a Kyoto itinerary in step 3 — is precisely what the threading buys.
Exercise 3: Letting a step re-plan
Plan-then-execute fixes the plan before execution starts. Suppose step 1’s result invalidated the remaining steps — say it found the chosen region unavailable. Sketch how you’d let the agent re-plan mid-run instead of marching through a stale list, and name the pattern that does this natively.
Hint
One approach: after each step, make an extra model call that asks “given this result, are the remaining steps still right, or should we revise the plan?” — and if it says revise, regenerate steps (the un-executed tail) from the current done context before continuing. That bolts adaptivity onto plan-then-execute, but at the cost of an extra check every step. The pattern that does this natively is ReAct (next lesson): rather than committing to a plan up front, it interleaves reasoning and acting during the loop, so it can change course the instant a result invalidates its assumptions — no separate re-plan step needed, because planning and acting are one and the same.
Summary
Task decomposition powers the plan-then-execute pattern: ask the model to plan first — produce an ordered list of steps before doing any work — then execute each step in order. The planning pass is one model call that returns steps “one per line,” which we parse into a Python list. The execution pass loops over that list, and its essential move is to thread prior results forward: a running done list of (step, result) pairs becomes the context fed into each new step, so later steps build on earlier ones. That threading is what separates a plan (steps that compound) from a checklist (steps run in isolation) — in the verified run, it’s why step 3’s itinerary was clearly for Kyoto, the region step 1 chose. Plan-then-execute’s strength is committing to a plan up front, which is great when the steps are knowable in advance; its limitation is that it can’t adapt mid-flight if an early result changes the plan — exactly what ReAct fixes next. The whole pattern layers onto the same Claude client you already have, and each step could itself call tools in a fuller agent.
Key Concepts
- Decomposition — plan first (produce an ordered list of steps), then execute, one step at a time.
- The plan parse — the model returns steps one per line; strip and split into a list your loop can iterate.
- Threading results forward — feed prior
(step, result)pairs into each new step so steps build on each other, not in isolation. - Plan-then-execute vs. ReAct — commit to a plan up front (great when steps are knowable) vs. adapt mid-flight (ReAct, next lesson).
Why This Matters
Most genuinely useful agent tasks aren’t one move — they’re several moves that depend on each other, and an agent that tries to do them all at once tends to drop a part or answer out of order. Decomposition is the simplest, most reliable fix: separate planning from doing, then make sure each step sees the last. Knowing how to build it — and, just as important, knowing its limit (it can’t change a fixed plan) — tells you exactly when to reach for it and when to reach for ReAct instead. With plan-then-execute in hand, you’ve built the first of the module’s three patterns. Next you’ll add the one that adapts as it goes.
Next Steps
Continue to Lesson 3 - ReAct: Reasoning and Acting
Interleave reasoning and acting during the loop so the agent can adapt as it discovers what it needs.
Back to Module Overview
Return to the Planning and Reasoning module overview
Continue Building Your Skills
You can now give Atlas a plan-then-execute step: it breaks a hard goal into an ordered list of steps, then carries them out one at a time, threading each result forward so the steps build on each other into a coherent whole. That’s the first of the module’s three planning patterns — decompose before acting. Its one blind spot is that the plan is fixed once execution starts, so it can’t adapt when an early result changes what should come next. The next lesson fixes exactly that, with ReAct: reasoning and acting interleaved during the loop, so the agent thinks again every time it learns something new.