Elements of Agentic System Designa map of the code around a model
Elements of Agentic System Design maps ten behaviors people attribute to AI agents to the code that produces them. I wrote it while building an agent runtime because I needed to decide which capabilities the runtime should own and which ones applications should supply.
Motivation
That boundary kept moving. Memory could live in the runtime or in application storage. A planner could be a built-in primitive or another prompt. Tool execution could belong to the model harness, a plugin system, or the application itself. A feature list did not help because every feature could plausibly sit on either side.
I started writing a book to force the decision. Each chapter needed working examples, and each example needed real code. If I could not explain a behavior without assigning it to a component, I had not found the boundary yet.
I kept the book independent from Idyllic. The examples could use my runtime, but the explanations had to begin with language models and ordinary software. Otherwise I would have documented one framework instead of producing a map I could use to design it.
Breaking down "intelligence"
I started with a narrow description of a language model: it takes text and returns text. It does not retain your last message, know who you are, or affect anything outside its response.
The surrounding program creates those behaviors.
- An agent remembers your name because the program loads your name into the prompt.
- It searches the web because the program parses its output, matches a tool name, runs a function, and sends the result back in another prompt.
- It works overnight because a scheduler starts it and reconstructs its context from stored data.
The model still reads text and writes text in every case. Storage, loops, schedulers, parsers, policies, and function calls turn those responses into a system.
Most references organize that system by technique: retrieval, function calling, planning, caching, and multi-agent coordination. Those categories match libraries and papers. They do not match the problem a developer brings to a debugger. A developer says, "The agent forgot what I told it," or, "It keeps wandering off."
So I worked backward from each observed behavior to the code that could have produced it.
| "It seems to..." | The program actually... |
|---|---|
| Remember what I said | includes conversation history in the next prompt |
| Have long-term memory | stores data and retrieves selected records into context |
| Do things in the world | parses structured output and dispatches a function |
| Think step by step | runs several model calls and passes state between them |
| Plan before acting | asks for a plan, then executes each step |
| Check its own work | runs a separate verification call and retries on failure |
| Have multiple experts | routes work among prompts with different instructions |
| Work while I sleep | starts from a timer or external event |
| Learn from experience | stores outcomes and retrieves them during later work |
When an agent forgets a fact, I can inspect the context assembled for that call and the storage and retrieval code that supplied it. I do not have to search a catalogue of techniques and guess which chapter contains the symptom.
The ten elements
The behavior-to-code pass produced ten elements:
| # | Element | What it describes | Where I look in the code |
|---|---|---|---|
| 1 | Context | information available during one model call | token budget and context construction |
| 2 | Memory | stored information retrieved into later contexts | storage and retrieval |
| 3 | Agency | conversion of model output into effects | parser, policy, and execution boundary |
| 4 | Reasoning | chains, loops, and branches across model calls | call structure and computation between calls |
| 5 | Coordination | communication and sequencing between reasoning processes | execution flow and data flow |
| 6 | Artifacts | shared persistent state | typed objects, operations, and lifecycle |
| 7 | Autonomy | triggers and ownership of the main loop | schedulers, event handlers, and context reconstruction |
| 8 | Evaluation | measurement of success | quality signals and scoring functions |
| 9 | Feedback | signals that steer current work | signal sources and injection points |
| 10 | Learning | feedback stored for future work | extraction, storage, and update pipeline |
Each element had to point to a code address. If I could not say where a developer would implement or debug it, I left it out or folded it into another element.
Consider a research agent that keeps reading material nobody requested. The complaint can come from four places:
Context
The task description permits a broad search.
Reasoning
The loop never checks whether the current question still serves the task.
Agency
The search tool has no scope parameter, so the model cannot request a narrow search.
Evaluation
Nothing checks whether the agent used the documents it retrieved.
Those diagnoses lead to changes in different files. The map does not choose one without evidence. It gives me the four places to inspect before I spend a week rewriting the prompt.
Agency
Tool calling almost became an element because every model SDK presents it as a core capability. It only covers one path from model output to an application effect.
A tool-calling API standardizes three parts:
| Part | What the application does |
|---|---|
| Format | asks the model for structured output instead of parsing prose |
| Vocabulary | gives the model a closed set of names and schemas |
| Router | translates the selected name and arguments into a function call |
The model only produces a string. delete_all_records remains inert until application code parses it, finds a registered function, checks the policy, and runs it.
| Stage | Example |
|---|---|
| Model output | {"tool": "delete_all_records"} |
| Application boundary | parse, look up, authorize, dispatch |
| Effect | delete rows, write a file, or send an email |
Application code creates agency in the middle row. The registry and policy also determine which strings can become effects. If the dispatch table has no deletion function, the model cannot delete anything through that path.
That gives me three debugging questions when an agent takes a bad action:
- Did the model select a bad action from the instructions and context it received?
- Did the execution layer authorize an action it should have blocked?
- Did I expose a capability or policy that made the outcome possible?
The same classification covers plugin protocols and skills. A plugin protocol extends the functions available to the router. A skill loads procedural instructions into context. Both matter, but neither needs a new element because the ten elements already identify the code involved.
Editing the map
My first outline borrowed levels from science: philosophy, physics, chemistry, engineering, and applications. I removed that structure once the examples showed that it separated principles from the code that used them. I introduced each principle where it affected a design choice instead.
The element list also changed as I built examples. I applied the code-address test to every edit:
| Edit | Reason |
|---|---|
| Renamed proactivity to autonomy | Proactivity describes how the behavior feels. Autonomy identifies triggers and ownership of the main loop. |
| Folded grounding into context | Grounding changes which facts the program places in the prompt. |
| Folded planning into reasoning | Planning uses one particular arrangement of model calls. |
| Renamed semantic objects to artifacts | The broader name covers any shared typed state used for coordination. |
| Separated feedback from learning | Feedback changes current work. Learning stores a change for later work. |
Two names collapsed when they led to the same code. One name split when it led to two different implementations. I generated more examples whenever a boundary remained unclear and watched for the same code appearing across them.
Externalization
Three elements move information out of one model call so another call can use it:
Memory stores context for one agent to retrieve later
Artifacts store shared state that several agents can change
Learning stores feedback that changes future behavior
They use the same broad operation and serve different consumers. Memory reconstructs what one agent should know. Artifacts coordinate work around a shared object. Learning changes how later work runs.
Evaluation, feedback, and learning form another dependency:
Evaluation measures the result.
Feedback uses that measurement to change the current task.
Learning stores the change for future tasks.
A system can measure a bad result and continue unchanged. It can also repair the current task and repeat the same mistake tomorrow. Keeping the three elements separate tells me which connection the implementation lacks.
Writing the book
I gave every chapter the same four sections so a reader could apply each element in the same order:
### Introduction
### Demystification
### Design Considerations
### The ReframeThe introduction names the behavior. Demystification traces it to code. Design Considerations covers the implementation choices. The Reframe converts a complaint about the agent into a change a developer can make.
For context, the reframes look like this:
Before: "Why does the AI keep forgetting things?"
After: "I need to load the relevant history into context on each call."
Before: "The model is hallucinating."
After: "I left out the facts needed to answer, so the model filled the gaps."
Before: "The AI's personality is inconsistent."
After: "The system prompt or reconstructed context changed between calls."I wrote each reframe so the reader would know which code to open.
Diagrams
My first diagrams repeated the prose. I replaced them with diagrams that locate the component responsible for a behavior.
The tool-calling diagram gives the parser and policy boundary more space than the model and tool because that code decides whether text causes an effect. The continuity diagram shows what the program stores between calls and what it reconstructs for the next one. The identity diagram holds the conversation history constant while it changes the model, then holds the model constant while it changes the history.
The diagrams let me point at the component that caused the observed behavior.
Context reconstruction
I used conversation continuity to test the map. On every turn, the application assembles a new context from stored messages and other data. The model receives that context as text. It does not carry the previous call inside itself.
This changes how I debug several common failures:
- If an agent loses a fact, I check whether storage retained it and whether retrieval placed it in the next prompt.
- If an agent contradicts an earlier answer, I compare the two contexts.
- If its personality changes, I compare its instructions, retrieved history, and model configuration.
I can also test where continuity comes from:
Keep the history and replace the model. The character mostly remains.
Keep the model and replace the history. The character changes.
The application produces continuity by preserving state and reconstructing context. I can inspect both operations in the logs and compare the results across runs.
Shipping the map
The map targets people who build frameworks, languages, SDKs, and agent platforms. They decide where memory lives, who owns the execution loop, how tools cross the policy boundary, and which state agents share.
Building Effective Agents, 12-Factor Agents, and agentic design patterns teach construction patterns. Elements gives a developer a way to take an existing system apart: identify which elements it implements, find them in the repository, and see what is missing.
I ship the framework as a Claude Code skill:
---
name: intelligence-designer
description: Analyze and design agentic AI systems using the Elements of Agentic
System Design framework. Use when asked to analyze an agent architecture,
understand how an agentic system works, or design a new agent system.
argument-hint: <system or question to analyze>
allowed-tools: Read, Grep, Glob, WebFetch
---The skill receives four read-only tools. It can inspect a repository and apply the map, but it cannot change the code. That keeps analysis separate from implementation and lets a developer review the diagnosis before acting on it.
Harness engineering
I initially called the field agentic system design. A LangChain post led me to the term harness engineering, which HumanLayer and others were already using for the code around a model. I adopted the common term because it named the same work and saved readers from translating another private vocabulary.
The ten elements still describe the decisions inside a harness. A model, a system prompt, and a tool list do not provide memory across sessions, autonomous execution, shared state, evaluation, or learning. Storage, schedulers, execution policies, context builders, and feedback pipelines provide them.
I now use the elements to settle the boundary that started the project. When an agent appears to remember, plan, act, coordinate, or learn, I trace the behavior to one of those mechanisms, find the file that owns it, and decide whether it belongs in the runtime or in the application.