Day 121 · Breaking the mission into missions

Agents II — Planning & Decomposition

You will be able to
  • Contrast plan-then-execute with interleaved (ReAct) planning and choose per task shape
  • Represent a plan as explicit task state (pending/done/failed) the code — not the model — owns
  • Verify each subtask against its done_when criterion before advancing
  • Trigger replanning on subtask failure instead of pushing on or giving up
Today's ~120 minutes
Spaced-rep: due cards + recite the four stop conditions (D120)10 min
ELI5 + tech read20 min
Guided: plan-execute-verify + reflection ceiling42 min
Practice: plan linter20 min
Project: agent/planner.py with tests20 min
Quiz + flashcards8 min

Builds on: Day 120Agents I — the loop · Day 118Advanced RAG — decomposition

The analogy

Send the intern to "organize the company offsite" with only Day 120's loop and she'll improvise: book a venue, then discover the date wasn't set, then un-book, then re-book. A senior intern starts differently — she writes the mission as missions: 1) confirm date and headcount, 2) shortlist venues, 3) get budget approval, 4) book. Then she works through the list one item at a time, and — the crucial habit — CHECKS each item actually succeeded before starting the next, because booking a venue for an unapproved budget means redoing everything.

And when reality disagrees with the plan (every venue is full that week), she doesn't push on to step 4 anyway, and she doesn't quit. She goes back to the whiteboard: cross out the broken step, write a recovery step ("propose two alternate dates"), and continue. That's the whole upgrade: a visible to-do list, a checkmark test for each item, and permission to rewrite the list when the world says no. The list lives on paper — not in the intern's head — so anyone (including you, the manager) can see exactly where the mission stands.

Why this matters on the job

Raw ReAct loops wander on long tasks: they lose the thread mid-mission, redo finished work, and declare victory early. Every serious agent product — coding agents, research agents, the deep-research features you've used — runs some form of explicit planning with subtask verification, and "how would you keep an agent on track over a 20-step task?" is now a standard AI-engineering interview question. The deeper habit transfers beyond agents: state that code owns and checks is how you'll debug agent trajectories on Day 137 (trajectory evals) and how your Day 126 triage agent survives a malformed ticket without derailing the batch.

Guided practice

guided 1

Plan, execute, verify — the harness owns the list

30 min
  1. Create agent_planner.py importing your Day 120 module (or paste the starter, which is self-contained). Mission: "Produce a summary of every policy that mentions a specific dollar amount, and save it to summary.txt." Too long for one lap; perfect for a plan.
  2. Read the PLAN the scripted planner emits — in production this is one LLM call with the printed PLANNER_PROMPT; here it is fixed so the mechanics run in-browser. Note each subtask's done_when is something CODE can check.
  3. Run it. Watch the harness pull subtasks in order, execute, verify, and record results — and see subtask 3 consume subtask 2's result (dependent subtasks, Day 118's hops generalized).
  4. Now flip INJECT_FAILURE to True: the write_file tool fails once (disk full). Watch verification catch it (done_when: file exists), status flip to failed, and the replanner insert a recovery subtask (retry to a fallback path) instead of the mission dying or the failure being ignored.
  5. Print the final plan state. This table — every subtask, status, result — is the audit trail Day 137 will grade trajectories with.
🐍 python — editable, runs in your browser
Ctrl/⌘+Enter runs · Tab indents · numpy/pandas/sklearn auto-load on import (torch and network calls need a local run)
guided 2

Reflection: cheap filter, low ceiling

12 min
  1. Subtask 2's result currently includes the travel line and the expenses line. Simulate a sloppier executor: make it also collect the vacation line (no dollar amount — a plausible LLM slip).
  2. Add a reflection pass before verification: a function reflect(goal, result) that re-checks each collected line against the goal ("mentions a specific dollar amount") and drops non-matching ones. Scripted here as a "USD" substring check standing in for an LLM self-critique call.
  3. Confirm reflection catches the slip — then construct the case it CANNOT catch: remove the travel line from the collection entirely. Reflection inspects what is present; it cannot notice what is absent. Only a done_when with an expected-count or coverage check (or Day 137's evals) catches omissions.
  4. Write the two-line summary in your notes: reflection filters visible junk cheaply; verification against independent criteria is the real gate. Both, in that order.

On your own

Plan quality is a testable artifact

20 min

Write plan_lint.py: a function that takes a plan (list of subtask dicts) and returns a list of defects, checking: (1) every needs reference points at an earlier id (no cycles/forward refs); (2) every subtask has a non-trivial done_when; (3) no two subtasks share the same goal (duplicate work); (4) the final subtask's done_when references the mission deliverable. Test it against three bad plans you write: one cyclic, one with a vague subtask ("handle the data"), one that never produces the deliverable.

Hints: this linter runs on LLM-produced plans BEFORE execution in production — rejecting a bad plan costs one retry; executing one costs the whole mission. Topological-sort thinking from Day 31 applies to check (1).

Ship before you stop

Planner module for the Week 18 agent

Extend the agent package: agent/planner.py with (1) Subtask as a dataclass (id, goal, needs, done_when, status, result); (2) run_mission(plan, executor, replanner, max_replans=2) — the verified plan-then-execute harness from the lab, generalized: executor and replanner are injected callables, and a mission fails cleanly after max_replans (the budget lesson from Day 120, one level up); (3) your plan linter, run automatically before execution; (4) tests: clean run, injected tool failure triggers exactly one replan then succeeds, an always-failing subtask exhausts max_replans and the mission reports failed-with-state (not an exception), linter rejects your three bad plans. Update the README's real-LLM mapping: planner call, executor loop, replan call.

Rubric — check what you completed (0/6)

Common mistakes & misconceptions

  • Letting the model carry the plan in its head. Unwritten plans drift and evaporate under context pressure; the harness owns the list, the model works one item at a time.
  • Advancing on unverified "done." A subtask that claims success without meeting done_when poisons every dependent step — Day 118's poisoned hop at mission scale.
  • Writing done_when criteria the code cannot check ("understands the policy"). Every criterion must be a predicate, a schema, or a concrete yes/no question.
  • Trusting reflection as verification. Self-critique catches visible junk; it cannot see omissions and grades its own work generously. Independent checks gate; reflection assists.
  • Unbounded replanning. Replan → fail → replan forever is Day 120's runaway loop wearing a suit; cap replans and escalate with the state table attached.
  • Planning everything upfront for exploratory tasks. When the path depends on discoveries, over-committed plans are re-written every step — just use interleaved ReAct there.
Knowledge check

Q1. For which task is plan-then-execute clearly better than pure interleaved ReAct?

Q2. Why must the harness (code) own plan state rather than the model?

Q3. Reflection ("critique your own output") fails to catch which class of error?

Go deeper — curated resources

articleAnthropic — Building Effective Agents (orchestrator-workers section)20 minarticleLilian Weng — LLM Powered Autonomous Agents (planning section)25 mindocsLangChain docs — agent architectures15 min
If you have a third hour
  • Plan-and-Solve & least-to-most promptingThe prompting-era ancestors of today's harness: explicit decomposition instructions measurably beat freeform reasoning on multi-step tasks. Worth knowing as the lineage.
Done means
  • Clean run and injected-failure run both traced and explained
  • Reflection catch and reflection blind spot both demonstrated
  • Plan linter rejects all three bad plans
  • agent/planner.py committed, tests green
  • Quiz ≥ 2/3
How this connects

← Back: Day 118's dependent hops became dependent subtasks; Day 120's budget discipline reappears as max_replans; Day 110's schema validation is one flavor of done_when.

Forward →: Day 122 manages the context these longer missions consume; Day 123's orchestrator-workers is this planner with multiple executors; Day 137 grades the audit trail you started printing today.

Unlocks: D122 Agents III — Memory & Context · D123 Multi-Agent & Workflow Patterns