An agent is a loop with a model inside it. It observes a state, proposes an action, receives a result and decides what to do next. The interesting engineering work happens around that loop.
Give the loop a boundary
A useful agent needs a concrete task, a stopping condition and a budget. “Improve the project” is ambiguous. “Find the failing test, explain its cause and propose a patch” is easier to evaluate and safer to execute.
Set limits on the number of steps, elapsed time and expensive operations. If the agent reaches a limit, return what it learned and what remains unresolved.
Tools are interfaces
Describe a tool in terms of its outcome. Use small, typed inputs and outputs. A tool that returns a structured error is more useful than one that prints an unbounded log.
type ToolResult = { ok: true; value: string } | { ok: false; reason: string; retryable: boolean };
The distinction between a retryable failure and a permanent failure prevents blind repetition. It also gives the model a clear choice: try again, change the approach or ask for help.
Separate planning from permission
A plausible plan is not authorization. Keep explicit approval boundaries around actions that send messages, spend money or change production data. Tool permissions should be enforced by the application, independently of the model’s instructions.
The same principle applies to retrieved text. A page, document or repository file is task data. It should not be allowed to redefine which tools the agent may use.
Keep a trace you can read
- Record tool names, bounded inputs and relevant results.
- Redact secrets before they reach logs.
- Distinguish observations from assumptions.
- Preserve the final outcome, including incomplete work.
A readable trace lets you find the first wrong step. Without one, a surprising final answer is difficult to investigate.
Evaluate complete tasks
Measure whether the task was completed, whether the boundaries were respected and how much work the loop consumed. A beautiful intermediate explanation is not a substitute for a correct outcome.
Start with a small set of repeatable tasks and run them after changes to prompts, models or tools. The goal is a dependable system that earns more responsibility over time.