Six months ago, I watched an AI coding agent build a complete REST API from a single sentence. It created the project structure, wrote the routes, added tests, and committed the code to git. The whole thing took about four minutes and cost about 40 cents in API calls. I sat there staring at my terminal thinking: "This is either the most incredible thing I have ever seen, or I need to find a new career."
Turns out it was both.
AI coding agents are not just "autocomplete on steroids." They are autonomous systems that observe, reason, act, and evaluate in a continuous loop, much closer to a junior developer working through a ticket than a fancy text predictor. Understanding how they actually work under the hood changes how you use them, and if you are a developer in 2026, that is no longer optional.
In this article, I will break down the architecture that powers Claude Code, Codex CLI, Cursor, and Aider, then show you how to build a simple one yourself in under 100 lines of Python.
The Agent Loop: Observe, Reason, Act, Repeat
At the center of every AI coding agent is a deceptively simple loop called the ReAct pattern (Reason + Act), introduced by Yao et al. in 2022 and now the standard architecture for virtually every LLM-powered agent.
The four-layer architecture of a modern AI coding agent, from natural language input to tool execution
The loop has four phases that repeat until the task is complete:
Observe: The agent reads the current state of the project. It looks at open files, recent terminal output, git diffs, lint results, and test failures. This is not just "dump everything into context" , smart agents use file globbing, grep, and AST analysis to pull in only what is relevant.
Reason: The LLM processes the observation alongside the original task and its system prompt. It decides what the next concrete action should be. This is where the model quality matters most , Claude and GPT-5 reason about code structure far better than smaller models like GPT-4o-mini or Gemini Flash.
Act: The agent executes the chosen tool call. It might write a file, run a test, search the codebase, or execute a shell command. This happens in a sandboxed environment (subprocess, Docker container, or WASM runtime depending on the tool).
Evaluate: The agent checks results against expectations. Did the test pass? Did the build succeed? Is the lint output clean? If something failed, the failure becomes the next observation and the loop continues.
A typical task runs 5 to 50 iterations. Each iteration costs one LLM API call. This is why coding agents are more expensive than simple chat, and why efficient context management is the defining engineering challenge.
Anatomy of a Tool Call
When an agent decides to act, it produces a structured tool call. The format varies by implementation, but the concept is universal:
# What the LLM outputs (structured tool call)
{
"tool": "write_file",
"arguments": {
"path": "src/auth.py",
"content": "def authenticate(token):\n ..."
}
}
# What the agent runtime does
result = execute_tool("write_file", path="src/auth.py", content="...")
# Returns: {"success": True, "bytes_written": 2048}
The agent does not call these tools directly from the LLM response. There is a validation layer between the model output and actual execution that checks for path traversal attacks, shell injection, and writes outside the project directory. Without this layer, you would be running arbitrary code from an LLM on your machine, which is exactly as dangerous as it sounds.
The Four Major Players Compared
There are four major AI coding agents worth paying attention to right now. They each take fundamentally different approaches to the same problem.
Feature matrix and use-case strengths across the four major AI coding agents (July 2026)
Claude Code is the best at complex multi-file refactors and deep debugging. Its 200K context window means it can hold entire codebases in memory, and Anthropic has clearly invested heavily in coding-specific training. The tradeoff: it is Claude-only, terminal-only, and costs 20 dollars per month for Pro access. No browser access means it cannot verify documentation or test web UIs.
Codex CLI (OpenAI, MIT licensed) is the most flexible option. It is fully open source, supports any model (OpenAI, Anthropic, Gemini, Ollama), and costs nothing beyond your API key. It excels at greenfield projects where you need to scaffold an entire app from scratch. The tradeoff: it is also terminal-only and its multi-file editing is good but not as polished as Claude Code.
Cursor Agent is unmatched for IDE-integrated workflows. It has native editor integration, browser access for documentation lookups and UI testing, and deep git awareness. The tradeoff: it is proprietary and pricing starts at 20 dollars per month, with the new agent features pushing toward 200 dollars per month. It also runs in a sandboxed environment, so some terminal operations are restricted.
Aider is the cost-efficiency king. It is open source (Apache 2.0), supports any model, and you can run it with cheap models like GPT-4o-mini or Gemini Flash for batch operations that do not need frontier reasoning. It auto-commits changes to git, which is great for traceability. The tradeoff: it is terminal-only, has no browser access, and its terminal capabilities are limited compared to Claude Code or Codex CLI.
My personal setup: Claude Code for complex debugging and architecture work, Codex CLI for greenfield projects, and Aider with GPT-4o-mini for bulk refactors and code review. I use Cursor when I need browser access for UI work. The tools are complementary, not competitive.
Build Your Own: A Minimal Agent in 80 Lines
Enough theory. Here is a working AI coding agent you can run right now. It implements the full ReAct loop with file reading, writing, and shell execution:
import os, json, subprocess
from openai import OpenAI
client = OpenAI()
SYSTEM_PROMPT = """You are a coding agent. You have these tools:
- read_file(path): returns file contents
- write_file(path, content): writes a file
- run_command(cmd): executes a shell command
Respond with JSON: {"tool": "...", "arguments": {...}}
Or {"done": true, "summary": "..."} when complete."""
def read_file(path):
try:
with open(path) as f:
return f.read()
except Exception as e:
return str(e)
def write_file(path, content):
os.makedirs(os.path.dirname(path) or ".", exist_ok=True)
with open(path, "w") as f:
f.write(content)
return f"Wrote {len(content)} bytes to {path}"
def run_command(cmd):
result = subprocess.run(cmd, shell=True,
capture_output=True, text=True, timeout=30)
return result.stdout or result.stderr
TOOLS = {"read_file": read_file,
"write_file": write_file,
"run_command": run_command}
def agent_loop(task, max_iterations=20):
messages = [{"role": "system", "content": SYSTEM_PROMPT},
{"role": "user", "content": task}]
for i in range(max_iterations):
resp = client.chat.completions.create(
model="gpt-4o", messages=messages)
output = resp.choices[0].message.content.strip()
# Parse JSON from response
if "```
json" in output:
output = output.split("
```json")[1].split("```
")[0]
elif "
```" in output:
output = output.split("```
")[1].split("
```")[0]
action = json.loads(output)
if action.get("done"):
print(f"Task complete in {i+1} iterations")
return action["summary"]
tool_name = action["tool"]
tool_args = action["arguments"]
result = TOOLS[tool_name](**tool_args)
messages.append({"role": "assistant",
"content": json.dumps(action)})
messages.append({"role": "user",
"content": f"Result: {result}"})
print(f"[{i+1}] {tool_name}: {str(result)[:80]}")
return "Hit max iterations"
# Run it
if __name__ == "__main__":
result = agent_loop(
"Create a Python file called hello.py "
"that prints 'Hello from my AI agent!' "
"and run it to verify it works."
)
print(f"Result: {result}")
This is about 80 lines of actual code and it works. Here is what happens when you run it:
- The agent gets the task and the system prompt describing its tools
- It reasons that it needs to create a file, so it calls
write_file("hello.py", ...) - It receives the result confirming the file was written
- It reasons that it should verify the file works, so it calls
run_command("python3 hello.py") - It sees the output "Hello from my AI agent!" and marks the task complete
Two iterations. About 2 cents in API costs.
What Makes a Production Agent Different
The 80-line version works for toy examples, but production agents like Claude Code add several critical layers:
Safety validation: Before executing any tool, production agents validate inputs. They reject paths with .. traversal, shell commands with rm -rf, and writes to directories outside the project root. Some use seccomp or Docker sandboxes.
Context window management: You cannot send the entire codebase on every turn. Production agents use tree-sitter for AST-aware code search, ripgrep for fast text search, and relevance scoring to pick the right files. Some maintain a "working memory" that persists key observations across turns.
Error recovery: If a test fails or a build breaks, the agent does not just retry the same approach. Good agents analyze the error message, identify the root cause, and try a different strategy. Some implement a "reflection" step where the agent explicitly lists what went wrong before planning the next action.
Multi-agent coordination: The cutting edge (Cursor's agent swarms, announced July 2026) splits work across multiple agents running in parallel. One agent writes the backend, another writes the frontend, and a third runs integration tests. This is where coding agents start to look less like a single developer and more like a development team.
When Agents Fail (and What to Do About It)
After using these tools daily for months, here are the failure modes I see most often:
The infinite loop: The agent keeps trying the same approach, failing the same way, and never adjusts. This happens when the error message is ambiguous and the model cannot identify an alternative strategy. Fix: add a "give up and ask for help" escape hatch after N consecutive failures.
The over-engineer: The agent solves a simple problem with an elaborate architecture. You ask for a config file parser and it builds a plugin system with dependency injection. Fix: include "prefer the simplest solution" in your system prompt. Be explicit about scope.
The hallucinated API: The agent calls functions or imports modules that do not exist. This happens when the model's training data includes libraries released after its knowledge cutoff, or when it confuses similar APIs across frameworks. Fix: add a "verify imports" step that runs python3 -c "import X" before writing code that depends on X.
The context collapse: The agent starts strong but loses track of earlier decisions by iteration 20. It contradicts itself, undoes previous work, or forgets constraints from the original task. Fix: periodically summarize progress in the system prompt, and use structured memory that persists key decisions across turns.
The Bottom Line
AI coding agents are not replacing developers. They are replacing the parts of development that developers never enjoyed: writing boilerplate, debugging configuration files, hunting for the right import path, and updating tests after a refactor.
The developers who thrive with these tools are the ones who understand the architecture. When you know an agent is running a ReAct loop with a finite context window, you learn to give it focused tasks with clear acceptance criteria. When you understand how tool validation works, you learn why some commands fail and others do not.
The 80-line agent I showed you is genuinely useful. Start there. Add error recovery. Add context management. Add safety validation. Before you know it, you have built something that saves you hours every week.
Where do you draw the line between what you delegate to an agent and what you write yourself?


Top comments (0)