Every agent, from a fifty-line script to a production system, is made of the same five parts. You design four of them. Knowing which is which turns “it is not working” into a question you can actually answer.
Module 01 described the loop. This one takes the machine apart and names the pieces, because almost every design decision you will make later is a decision about one of five components.
A restaurant kitchen has a head chef who decides what happens next, a printed ticket rail holding the current orders, a shelf of equipment, a stack of reference recipes, and a pass where finished plates go out. Take away any one of them and service collapses in a specific, predictable way.
Lose the chef and nothing gets decided. Lose the ticket rail and orders are forgotten mid-service. Lose the equipment and you can only serve what needs no cooking. Lose the recipes and every dish is improvised. Lose the pass and food is made but never delivered.
An agent has the same five parts, and it fails in the same five ways.
Four of these five are yours to design. Only the model is bought in.
The reasoning engine. You will change this least often and think about it least, which is appropriate — most agent problems are not model problems.
The one decision worth making deliberately is capability against cost. A stronger model reasons better about which tool to use and recovers from confusion more gracefully. A cheaper, faster one is often perfectly adequate for a narrow task with three tools and a clear procedure. Mixing them within one system is common and sensible: a strong model coordinating, cheaper models doing bounded subtasks.
Everything the model can see at this instant. It is not memory in any persistent sense — it is a working set that you reconstruct on every single call.
This is the component that most often causes trouble, and module 03 is devoted to it. For now, hold one fact: the model has no memory between calls. If something needs to be known at turn nine, something in your code put it there.
A tool is a function you expose, described in words the model can read. A description, a set of parameters, and code that runs when the model asks for it.
The model cannot inspect your code. It selects a tool by reading its name and description, so those are the interface. Two tools described similarly will be confused with each other — and the failure looks like the model being stupid when it is actually your documentation being ambiguous. Module 04 covers this properly.
The standing brief: who the agent is, what it must always do, what it must never do, how to handle the ambiguous cases. Sent with every request, because there is no memory to hold it.
The instinct is to write more. Resist it. Instructions compete with everything else in context for the model’s attention, and a three-page brief means each rule holds a smaller share of it. Fewer, sharper rules outperform exhaustive ones, and a rule the model can actually follow beats three it will average across.
Your code. The part nobody demonstrates and everybody needs.
Running the loop — call, read the response, execute tools, append results, call again.
Enforcing limits — maximum iterations, maximum spend, timeouts. An agent without a ceiling is a bill without a ceiling.
Validating tool requests — the model asked; the runtime decides. Checking arguments, permissions, and scope happens here or nowhere.
Handling failure — when a tool errors, does the agent see the error and retry, or does the whole task stop? Both are valid. Choosing by accident is not.
Logging — every decision and every action. When an agent does something surprising, the log is the only way to find out why.
The practical value of this decomposition is that it turns “the agent is not working” into a question with five candidate answers.
Model, context, tools, instructions, runtime. You design four of the five. When an agent misbehaves, name the component before you change anything — most teams reach for a better model when the actual fault is a tool description or a missing limit.
search_docs (“search the documentation”) and find_article (“find an article”). It uses them interchangeably and unpredictably. What should you change first?