Coding Agent Architecture: Six Core Modules and the Agent Loop
This article explains how a coding agent turns a general-purpose model into a task-oriented engineering system. It clarifies the differences between LLMs, reasoning models, and agents, describes the observe-inspect-choose-act loop, and examines six core modules: tool design, context management, memory, prompt caching stability, loop control, and long-session continuity. It also includes a minimal implementation, engineering recommendations, and a troubleshooting checklist.
Coding Agent Architecture: Six Core Modules and the Agent Loop
What a Coding Agent Is: From Answering Questions to Completing Tasks
In real software engineering scenarios, what is a coding agent, why is a normal chat interface insufficient, and how can you evaluate whether an agent harness is reliable? These questions cannot be answered by model parameters alone. The same large language model may passively generate answers in a chat window, while inside a coding agent it can browse a repository, locate files, modify code, run tests, and continue revising its plan based on execution results. The key difference is not only the model itself, but whether there is an engineering system around the model.
This surrounding system is usually called an Agent Harness. It sits at the application layer and is responsible for connecting the model to a real task environment. It organizes codebase context, designs tool interfaces, manages memory and state, maintains continuity over long sessions, and improves stability through prompt caching, error recovery, and loop control. In other words, the competitiveness of a coding agent comes from the combination of “model + tools + context + control flow”, not from a single model output.
Three Concepts to Clarify: LLM, Reasoning Model, and Agent
Before understanding coding agent architecture, it is useful to distinguish three concepts that are often confused.
A large language model (LLM) is the most basic capability layer. It is fundamentally a probabilistic model that predicts subsequent tokens based on preceding context. It can generate text, but it does not by itself access files, execute commands, or observe runtime results.
A reasoning model usually performs more internal reasoning before generating an answer, such as explicit chains of thought or multi-step reasoning. It is suitable for complex logical problems. However, it is still reactive: after thinking, the model outputs a result and does not automatically execute actions in a real environment.
An agent adds action capabilities on top of an LLM. It can receive a task, call tools, observe results, decide the next step, and continue iterating across multiple steps. A coding agent belongs to this category. It does not rely on the model producing a perfect answer in one shot; instead, it gradually approaches the goal through a process of trying, observing, and correcting. This is closer to how human engineers handle complex tasks.
The Core Loop: Observe, Inspect, Choose, and Act
The working skeleton of a coding agent can be abstracted as a continuous loop:
- Observe: Obtain the current task state, including the user goal, available information, and the result of the last tool execution.
- Inspect: Analyze the context, determine whether the information is sufficient, and decide whether more files need to be read, commands need to be run, or searches need to be added.
- Choose: Select the next action from available tools, such as reading a file, editing code, running tests, or searching for a symbol.
- Act: Call the tool, obtain the result, write the result back into the context, and enter the next iteration.
This can be understood as a minimal state machine:
Start -> Inspect -> Choose -> Act -> Observe -> Inspect|vPlan adjustment|vContinue execution / request clarification / terminate
This loop must have exit conditions. Common exit conditions include task completion, reaching the maximum number of steps, consecutive failures, detecting repeated actions, additional user input, or the system detecting a security risk. A loop without termination conditions can easily fall into ineffective repetition, waste resources, and reduce reliability.
Six Core Modules of a Coding Agent
1. Tool Design and Invocation
Tools are the channels through which an agent interacts with the external world. The quality of tool design directly affects the upper limit of the agent. Good tools should have moderate granularity: they should not be too broad, making it difficult for the model to determine parameters, and should not be too fine-grained, causing too many invocation rounds. Tool names, descriptions, and return structures should be clear so that the model can parse them.
It is especially important to emphasize that command execution tools must be controlled. In production environments, it is not recommended to directly accept arbitrary strings and call a shell. A safer approach is to use parameterized commands, allowlists, timeout control, permission isolation, and output truncation. The following is an example:
import subprocessALLOWED_COMMANDS = {"git", "pytest", "ls", "python"}def run_safe_command(argv: list[str],cwd: str = "/workspace",timeout: int = 30) -> dict:"""Controlled command execution example.- argv must be a list of arguments, not an arbitrary shell string.- Only allowlisted commands are allowed.- Timeouts and output truncation are required.Production systems should also add containerization, user permission isolation, and read-only mounts."""if not argv:return {"ok": False, "error": "empty command"}if argv[0] not in ALLOWED_COMMANDS:return {"ok": False, "error": "command not allowed"}try:result = subprocess.run(argv,cwd=cwd,timeout=timeout,capture_output=True,text=True,shell=False)return {"ok": result.returncode == 0,"exit_code": result.returncode,"stdout": result.stdout[:4000],"stderr": result.stderr[:2000],}except subprocess.TimeoutExpired:return {"ok": False, "error": "timeout"}except Exception as e:return {"ok": False, "error": str(e)}
This version avoids directly executing arbitrary shell commands while preserving a failure return structure. This allows the agent to observe errors and adjust the next step.
2. Context Management
A real code repository may contain hundreds of thousands of lines of code, so it cannot be placed into the context all at once. Therefore, a coding agent must learn to fetch only the information it needs. The key to context management is not stuffing in more information, but making key information easier for the model to see.
A fixed-priority template is recommended:
- System constraints and security rules
- Current task goal
- Current progress and task list
- Latest tool observation result
- Key file fragments
- Historical summaries and completed decisions
Common strategies include on-demand retrieval, log compression, long-file summarization, retention of key decisions, and truncation of overly long outputs. Context is not better when it is larger; it is better when it is more relevant.
3. Memory System
Short tasks can rely on the current context, but complex projects often require memory across turns and even across sessions. Memory can be divided into short-term memory and long-term memory.
Short-term memory is used for intermediate state in the current session, such as files that have been read, locations that have been modified, commands that have been executed, and the current blocking cause. Long-term memory is used to preserve project conventions, historical decisions, user preferences, and common build methods.
Long-term memory fields can refer to the following structure:
{"type": "project_convention","content": "The project uses pytest for testing","reason": "Team-wide convention","source": "README.md","timestamp": "2026-01-01T10:00:00Z"}
It should be noted that memory storage capabilities depend on the specific model, platform, and provider implementation. Some systems support external vector databases, while others can only rely on the file system or a structured database. The actual solution should be verified according to the relevant API documentation.
4. Prompt Caching Stability
Many platforms cache prompt prefixes to reduce cost and latency. If the system prompt, tool definitions, or the beginning of the context are modified every turn, the cache may frequently be invalidated.
From an engineering perspective, it is recommended to put stable content first and append dynamic content later. For example:
- Stable parts: system rules, security constraints, tool definitions, and fixed task frameworks
- Dynamic parts: latest observations, latest execution results, and temporary supplementary information
This structure can help improve cache hit rates, but the specific caching strategy still depends on the model platform implementation and should be verified through the actual API.
5. Iteration Loop Control
Loop control is responsible for preventing the agent from losing control. Without control mechanisms, an agent may repeatedly call failing tools, search indefinitely, or repeatedly modify the same file.
Common control methods include:
- Setting a maximum number of steps, such as 20 or 50.
- Detecting repeated actions, such as executing the same failed command twice in a row.
- Accumulating failure counts and requiring the model to replan after exceeding a threshold.
- Requiring “plan first” in complex tasks: output the steps before executing them.
- Pausing and requesting confirmation when high-risk operations are detected.
The goal of loop control is not to limit the model’s capability, but to make the model’s behavior predictable, recoverable, and terminable.
6. Long-Session Continuity
In long sessions, the context may change continuously, and early information may be compressed or forgotten. To maintain task continuity, state must be explicitly maintained.
Common practices include:
- Maintaining a task list that records completed items, in-progress items, and pending items.
- Periodically generating progress summaries that cover modified files, verified features, and current issues.
- Preserving key decision nodes when compressing history, instead of only keeping recent outputs.
- Placing important constraints at the front of the context to prevent them from being drowned out.
The essence of long-session continuity management is to give the agent a “work record” like an engineer, rather than relying only on the model’s short-term memory.
Minimal Implementation: Getting the Loop Running
The following is a simplified example showing how the six modules work together. This example omits security isolation and observability components from real engineering systems, so it is more suitable as an architectural illustration.
def coding_agent(task: str,tools: dict,model_decide,max_steps: int = 20):context = {"task": task,"todo": [],"history": [],"last_observation": None,}for step in range(max_steps):# 1. Let the model decide the next step based on the current contexttry:decision = model_decide(context=context,tool_names=list(tools.keys()))except Exception as e:return f"Model decision failed: {e}"# 2. Termination conditionsif decision.get("type") == "finish":return decision.get("result")if decision.get("type") != "tool_call":return "Unrecognized model output"name = decision.get("name")args = decision.get("args", {})# 3. Tool validationif name not in tools:return f"Tool not found: {name}"# 4. Execute the tool and catch exceptionstry:observation = tools[name](**args)except Exception as e:observation = {"error": str(e)}# 5. Write the observation back into the contextcontext["last_observation"] = observationcontext["history"].append({"step": step,"tool": name,"args": args,"observation": observation,})return "Maximum steps reached; task not completed"
Here, model_decide is the model decision function. Its input should include the task context and available tool names, and its output should be a structured result. For example:
{"type": "tool_call","name": "read_file","args": {"path": "src/app.py"}}
Or:
{"type": "finish","result": "The fix is complete and tests have passed"}
Real systems also need to add exception recovery, logging, permission validation, output compression, and security interception.
Engineering Practice Recommendations
To build a reliable coding agent, it is recommended to prioritize the following items.
First, prioritize improving tools and context. In many cases, improving tool descriptions, file retrieval methods, and context organization is more effective than switching to a stronger model.
Second, design security boundaries. Command execution should use allowlists and parameterized methods, avoiding direct execution of arbitrary shell strings. File writes should be restricted to isolated directories, and tools should run with the minimum necessary permissions.
Third, protect sensitive information. Do not write secrets, access tokens, personal information, or internal private data into the context or logs. Log output should be sanitized to avoid leaking source code fragments or environment variables.
Fourth, keep the prompt prefix stable. System prompts, tool definitions, and security rules should be kept as fixed as possible, while dynamic observation results should be appended later to improve cache friendliness.
Fifth, explicitly maintain task state. In long tasks, use task lists, progress summaries, and key decision records to prevent the agent from forgetting early goals.
Sixth, establish observability. Record the decisions, tool calls, inputs and outputs, and elapsed time of each step so that problems can be located more easily.
Common Troubleshooting Checklist
When a coding agent behaves abnormally, you can use the following checklist.
- Frequent cache invalidation: Check whether the system prompt, tool definitions, or fixed prefix are frequently modified.
- Tool call failures: Check whether the command is in the allowlist, whether parameter types are correct, whether paths exist, and whether permissions are sufficient.
- The loop does not terminate: Check whether the maximum step count, repeated-action detection, failure counting, and task-completion judgment are effective.
- Context is too long: Check whether a large number of files are read at once, whether historical logs are compressed, and whether only key fragments are retained.
- The model repeatedly modifies the same file: Check whether the task list is missing and whether there is a “plan before execution” constraint.
- Unstable results: Check whether tool returns are structured, whether error messages are clear, and whether the model can distinguish the causes of failures.
Conclusion
The reason a coding agent is more reliable than a bare model is not that the model suddenly becomes smarter. It is that the Agent Harness places the model inside an engineering framework that can act, observe, and correct. Tools, context, memory, caching, loop control, and long-session continuity together determine whether a coding agent can complete tasks stably. Mastering these modules is more valuable from an engineering perspective than simply pursuing larger model parameters.
