Place the scratchpad as the latest assistant turn at the recency end; each iteration, evict consumed tool results and stale reasoning, keep only the live plan and open sub-goals.
Think of a chef working through a complicated order. Next to the stove is a small notepad with what to cook next, the dish in progress, and ingredients still needed. The chef does not pin every chopped onion ticket from the last two hours to that pad. Those go in the bin once used. The pad stays small and current so a quick glance answers what comes next. An agent scratchpad works the same way. It sits where the model is about to read next, holds only the plan and live sub-goals, and drops anything already used. The kitchen receipts (full reasoning history, tool logs) belong in the back office, which for an agent is the telemetry system, not the prompt.
Detailed answer & concept explanation~6 min readEverything you need to truly understand this topic: intuition, mechanics, step by step explanation, code, formulas, and worked example. Click to expand.
Everything you need to truly understand this topic: intuition, mechanics, step by step explanation, code, formulas, and worked example. Click to expand.
Everything you need to truly understand this topic: intuition, mechanics, step by step explanation, code, formulas, and worked example.
Everything important, quickly.
6 minutes: placement at the recency end, what to prune and what to keep, the separation of scratchpad and trace, and how production frameworks wire it through typed state.
from langgraph.graph import StateGraph
from typing import TypedDict, Annotated
class AgentState(TypedDict):
user_query: str
plan: list[str] # live, mutable
open_subgoals: list[str] # live, mutable
last_tool_result: str # only most recent
iteration: int
def prune_scratchpad(state: AgentState) -> AgentState:
# Drop completed sub-goals
state['open_subgoals'] = [g for g in state['open_subgoals'] if not g.startswith('[done]')]
# Keep only the latest tool result; previous ones already folded into plan
return state
def render_prompt(state: AgentState) -> str:
# Scratchpad sits at the recency end, just before the next decision
return (
f'PLAN:\n{chr(10).join(state["plan"])}\n\n'
f'OPEN SUBGOALS:\n{chr(10).join(state["open_subgoals"])}\n\n'
f'LATEST OBSERVATION:\n{state["last_tool_result"]}\n\n'
f'Next step?'
)Real products, models, and research that use this idea.
- LangGraph's typed state lets you declare a `scratchpad: str` field that the agent node rewrites each tick; checkpointers persist it without forcing it into the prompt verbatim.
- Claude Code maintains a planning block that gets rewritten across tool calls, old plan steps are crossed out and the live plan stays at the bottom of its working context.
- Cursor's agent mode threads tool results inline with reasoning and evicts file reads once their content has been folded into a code-edit decision.
- Letta (formerly MemGPT) exposes explicit memory-management tools so the model itself can compact its working memory when pressure crosses a threshold.
What an interviewer would ask next. Try answering before peeking at the approach.
QHow would you decide the watermark at which the scratchpad triggers compaction?
QIf the agent runs in parallel branches that later merge, how do you reconcile separate scratchpads?
Don't say thisRed flags and common mistakes that signal junior thinking. Click to expand.
Red flags and common mistakes that signal junior thinking. Click to expand.
Carrying every prior reasoning trace and tool result forward as if the scratchpad were a transcript. Each iteration the prompt grows linearly and the live plan drowns.
The night-before-the-interview bullets. Scan these on the way to the call.
Primary sources. Skim if you want the original framing.
Same topic, related formats. Practice these next.