Planning gives an agent direction before it acts on a complex task. Instead of immediately trying tools and reacting to each result, the agent breaks the goal into ordered, manageable tasks. The resulting plan stays in the agent’s context, where it can guide later decisions. Planning does not perform the research or calculations itself. section 7.0 section 7.1.3
Decompose a multistep question
To estimate how many thousand hours a marathon runner would take to reach the Moon at record pace, an agent can plan to find the record time, calculate speed, find the Moon’s distance, then calculate and round the travel time. Each task has a checkable result. Searching for the final answer immediately offers less direction when the first query fails. section 7.2
Use planning when a question needs several research steps or combines information from different sources. Skip it for a single-search question or a task with an obvious procedure: creating and updating a plan costs LLM calls, tokens, and time. Group related lookups into meaningful tasks rather than updating the plan after every small action. section 7.2.1 section 7.2.3
A minimal planning tool can keep its state simple:
- Keep one plan per question. Represent each task with content and a status: pending, in_progress, or completed. section 7.2.2
- Have create_tasks accept the full task list and return a readable checklist. Its ToolResult enters the agent’s context, so later steps can consult the current plan. section 7.2.2 section 7.2.3
- When progress changes, regenerate the whole list: mark finished work completed, the next task in_progress, and future work pending. This avoids partial-update synchronization logic at a modest token cost for short plans. section 7.2.2
Listing 7.2 Planning-tool implementation
from typing import List
from scratch_agents.tools import tool
@tool
def create_tasks(tasks: List[Task]) -> str:
"""Create or update a task plan.
WHEN TO USE:
- Complex queries requiring multiple steps of research
- Questions that need to combine information from different sources
WHEN NOT TO USE:
- Simple questions answerable with a single search
- Tasks with obvious, straightforward procedures
HOW TO USE:
- Regenerate the entire task list with updated statuses
- Mark completed tasks as 'completed'
- Mark the next task to work on as 'in_progress'
- Keep future tasks as 'pending'
"""
result = []
for task in tasks:
result.append(str(task))
return "\n".join(result)
The Python tool’s docstring specifies when to plan, when not to plan, and how to update task statuses; the function renders the supplied tasks as a checklist. section 7.2.2
Step 2: search_web("Kipchoge marathon world record") call
Step 3: create_tasks call (state update)
Result:
[x] ~~Find Kipchoge marathon world record time~~
[>] **Calculate pace in km/h**
[ ] Find Earth-Moon distance at perigee
[ ] Calculate time and convert to thousands of hours
The execution trace shows a completed research task and a newly active calculation task after a status update. section 7.2.3
Planning works with reflection in a cycle: plan, execute tool calls, check progress, then continue or revise. A failed lookup may call for a different tool without changing the goal; evidence that invalidates the task’s premise calls for replanning. The plan preserves direction, while reflection decides whether that direction still fits. section 7.4 section 7.5





