Building AI Agents from Scratch

Planning Multi-Step Tasks

Handle tasks that need several actions, dependencies, and a replan after new observations.

A single tool call is a reflex. “Compare README claims to the code, then hit the health URL” is a plan. You can let the model improvise, or you can make it write the plan first.

Plan as text, then execute

Add a write_plan tool that only stores a short numbered list on the agent, and a system rule: “For tasks with two or more steps, call write_plan before other tools. After each observation, revise the plan if a step failed.”

PLAN: list[str] = []


def write_plan(steps: list[str]) -> dict:
    PLAN.clear()
    PLAN.extend(s.strip() for s in steps if s.strip())
    return {"ok": True, "steps": PLAN.copy()}


def read_plan() -> dict:
    return {"ok": True, "steps": PLAN.copy(), "remaining": len(PLAN)}

The plan is not a workflow engine. It is a note the model can see on the next think. If http_get fails, the next completion should rewrite step 3 instead of repeating a dead URL.

Dependencies

Do not read a file before list_dir has shown it exists — unless the user named the path. Put that in the system prompt. Your tools already refuse missing files; the plan just reduces wasted calls.

Check it

  1. Give a three-part request. The first tool call should be write_plan with at least three steps.
  2. Point http_get at a closed port (or force a failure). The next plan should change.
  3. A one-shot “what is 3+4?” should skip the plan tool.

Next: make failure a first-class observation.