Building a Code Agent: From Model Calls to an Engineered Closed Loop
A practical code agent is more than a large language model connected to a code editor. This article explains the architecture behind a working code agent, covering its core layers, harness engineering, the execution loop, tool design, context management, planning, verification, error recovery, security controls, evaluation metrics, and a phased implementation roadmap.
In recent years, intelligent programming tools have developed rapidly. Many people encountering these systems for the first time tend to understand them as “wrapping a large model in a code editor”: the user enters a requirement, the model generates code, and the task is complete.
But a code agent that can handle complex engineering tasks is far more than a chat window or a code completion module. It needs to read the project structure, understand context, choose appropriate tools, modify multiple files, run tests and build commands, continue fixing based on error messages, and control risk throughout the process. This means the core competitiveness of a code agent comes not only from the model itself, but also from the engineered “control system” built around the model.
This can be abstracted into a closed loop:
Task understanding → environment perception → planning → tool invocation → execution verification → result analysis → continue fixing or finish
This loop is the key difference between a code agent and an ordinary question-answering system.
1. Basic Components of a Code Agent
A complete code agent usually consists of the following layers:
- Interaction layer: receives user requirements and displays the execution process and results.
- Task orchestration layer: splits tasks, maintains state, and controls the loop.
- Model reasoning layer: understands natural language, analyzes code, and generates the next action.
- Tool layer: provides capabilities such as file reading, file modification, search, and command execution.
- Execution environment layer: runs tests, builds, and static checks in a controlled environment.
- Security and audit layer: restricts high-risk operations and records the complete process.
- Context management layer: controls input length and retains genuinely valuable information.
Among these, the model is only the reasoning engine. Tools and the orchestration system determine whether it can actually complete engineering tasks.
Without tools, the model can only “describe how to modify”; with tools, it can read real files and execute operations. Without state management, the model starts from scratch every time. Without a verification step, the code it generates lacks a reliability guarantee.
2. Why Harness Engineering Is Needed
In code agent scenarios, the model is more like a powerful but not fully stable general-purpose engine. It may understand the requirement, or it may misjudge the project structure. It may generate correct code, or it may guess at interfaces that do not exist based on experience.
Therefore, the engineering system needs to establish boundaries for the model, mainly in the following areas:
- Clarify the current task objective;
- Limit accessible directories and files;
- Specify which tools can be called;
- Constrain tool parameter formats;
- Require verification after each modification;
- Request confirmation before dangerous operations;
- Provide feedback on failed results;
- Set maximum loop counts and resource limits.
This mechanism can be understood as the agent’s “harness.” It does not suddenly make the model smarter, but it can reduce the model’s room for free-form behavior and concentrate the model’s capabilities within a controllable workflow.
3. The Core Loop of Task Execution
Code agents usually adopt a loop-based execution model rather than generating an answer in one shot. A simplified pseudocode example is as follows:
Receive user taskInitialize project contextwhile termination condition not met:Analyze current goal and existing resultsSelect next actionValidate whether the action is legalCall file or execution toolsCollect tool outputDetermine whether the task is completeIf failed, generate a repair planReturn final result
What matters most here is not the loop itself, but the “termination condition” and “state update.”
For example, for a task that modifies an interface, the system cannot finish simply because the model says “it is done.” The system should at least check:
- Whether the target file has actually changed;
- Whether the modification content is within the task scope;
- Whether the code can pass syntax checks;
- Whether relevant tests pass;
- Whether unresolved errors have been introduced;
- Whether there are unhandled edge cases.
Therefore, an agent’s termination conditions should be based on verifiable facts as much as possible, not on the model’s subjective judgment.
4. Tool System: Enabling the Model to Operate Real Projects
The most basic tools for a code agent usually include the following categories.
1. File reading tools
File reading should not simply stuff the entire project into the model. A more reasonable approach supports:
- Reading by path;
- Reading by line number;
- Reading a specified range;
- Truncating based on file type;
- Automatically marking file sources and locations.
This reduces context consumption and prevents the model from getting lost in large amounts of irrelevant content.
2. File search tools
Search tools are used to locate symbols, call relationships, configuration items, and error messages. They can support:
- File name matching;
- Keyword search;
- Regular expression search;
- Directory filtering;
- File type filtering.
In practice, search is often more important than direct reading. The model does not need to understand the entire project from the beginning. It can first locate the entry point and then gradually expand the relevant context.
3. File modification tools
There are two common designs for file modification tools.
One is to submit the complete file content directly. The advantage is simplicity, but the disadvantage is a large transfer volume and the risk of overwriting concurrent modifications.
The other is based on patches or local replacements, submitting only the parts that need to change. This can reduce the modification scope and make auditing easier, but it needs to handle matching failures, duplicate matches, and context inconsistencies.
A robust modification tool should have:
- Validation of content before and after modification;
- Unique match checking;
- Change summaries;
- Automatic diff generation;
- Clear reasons when a modification fails;
- Rollback support.
4. Command execution tools
A code agent must be able to execute tests, builds, formatting, and static check commands. But command execution is also one of the highest-risk capabilities.
The system should not give the model unrestricted terminal permissions. It should at least limit:
- Working directory;
- Accessible files;
- Network access;
- Number of processes;
- CPU and memory;
- Execution duration;
- Runnable commands;
- Environment variables;
- Output size.
For operations such as deleting files, modifying system configuration, or accessing sensitive directories, human confirmation should be required or the operations should be prohibited outright.
5. Context Management Determines Actual Results
Large models have limited context capacity, while real projects usually contain a large amount of code, configuration, documentation, dependencies, and generated files. How to select context is a key issue in code agent design.
1. Layered loading
Context can be divided into three layers:
The first layer is task context.
This includes user requirements, constraints, acceptance criteria, and current progress.
The second layer is project context.
This includes directory structure, build method, main modules, coding conventions, and existing documentation.
The third layer is local context.
This includes the file currently being modified, related functions, callers, test cases, and the latest execution result.
The agent should not load all content at once. Instead, it should dynamically expand context according to the current step.
2. Retain high-value information
When compressing context, the following content usually has higher priority:
- Constraints explicitly stated by the user;
- Confirmed project structure;
- The most recent modification;
- The most recent failure information;
- Unresolved issues;
- Test and build results;
- Key outputs from tool calls.
Repeated code snippets, verbose logs, and issues that have already been resolved can be summarized.
3. Establish a state summary
During long-running tasks, a structured state can be maintained:
Task goal:- Add a feature- Keep existing interfaces compatibleCompleted:- Found the entry module- Modified core logic- Added test casesCurrent issues:- Two tests are failing- Failure cause suspected to be missing configurationNext step:- Check the test initialization process
This kind of state is more effective than simply piling up historical conversation, because it continuously reminds the model of the problem that actually needs to be solved.
6. Planning Is Not Blind Decomposition
For complex requirements, a code agent usually needs to make a plan first. But planning also has two extremes:
- No planning at all, modifying directly, which easily misses dependencies;
- Overly detailed planning, resulting in many meaningless steps and reduced execution efficiency.
Reasonable planning should revolve around verifiable stages, for example:
- Identify relevant modules;
- Review existing behavior;
- Clarify the interfaces that need to be modified;
- Modify the implementation;
- Add or adjust tests;
- Run verification;
- Fix based on results;
- Summarize changes and residual risks.
After each stage is completed, the state should be updated rather than mechanically executing a long plan generated in advance. This is because test results, dependency relationships, and code structure in a real project may differ from the initial judgment.
7. Verification Mechanisms Are the Core of Reliability
Without verification, a code agent is essentially just a code generator. Verification mechanisms should cover at least four levels.
1. Syntax validation
Confirm that the code can be parsed and avoid basic issues such as missing brackets, indentation errors, and incorrect type declarations.
2. Static checks
Use type checking, rule checking, and dependency analysis to find potential issues. Static checks cannot necessarily prove functional correctness, but they can quickly filter out a large number of low-level errors.
3. Unit tests
Verify whether local logic meets expectations. The agent should not only run tests but also understand why tests fail, rather than blindly rewriting code after seeing a failure.
4. Integration validation
Confirm that multiple modules work together, including interface calls, data formats, configuration loading, and runtime behavior.
A mature agent should pass verification results to the model in a structured way, for example distinguishing between:
- Command executed successfully;
- Command execution failed;
- Test failed;
- Environment is missing dependencies;
- Timeout;
- Output was truncated;
- Insufficient permissions.
The clearer the error classification, the easier it is for the model to adopt the correct repair strategy.
8. Error Recovery: From “Retry” to “Diagnosis”
Simple retries cannot solve complex problems. Effective error recovery usually consists of three steps:
Step 1: Confirm the error type
Determine whether the problem is a code error, environment error, dependency error, permission error, or a change in test expectations.
Step 2: Narrow the impact scope
Do not make large-scale changes immediately. First read the code near the failure location, search for related symbols, check recent changes, and confirm whether the error can be reproduced consistently.
Step 3: Propose the minimal fix
Prioritize the modification with the smallest impact scope and rerun the relevant verification. If failures continue, the system should stop the automatic loop and show the diagnostic results to the user rather than attempting indefinitely.
At the same time, maximum execution rounds, maximum runtime, and maximum number of modified files should be set to prevent the agent from falling into a loop or expanding the damage scope.
9. Security Design Cannot Be an Add-on
A code agent can read and modify real engineering projects, so security must be considered at the architecture level.
Common measures include:
- Executing commands in an isolated environment;
- Denying access to directories outside the project by default;
- Redacting sensitive files;
- Restricting external network access;
- Requiring secondary confirmation for high-risk operations;
- Saving a record of every file change;
- Supporting one-click rollback;
- Logging model decisions, tool parameters, and execution results;
- Detecting sensitive information in output content.
In particular, the model may bring keys, tokens, or internal addresses from configuration files into its answers. Therefore, sensitive information should be identified before input reaches the model and checked again when results are output.
10. How to Evaluate a Code Agent
Evaluating a code agent should not focus only on “the amount of generated code.” It should also focus on the delivery quality of complete tasks.
The following metrics can be observed:
- First-pass task completion rate;
- Test pass rate;
- Average number of repair rounds;
- Ratio of invalid tool calls;
- Whether the modification scope is controllable;
- Number of mistakenly modified files;
- Task duration;
- Resource consumption;
- Number of human interventions;
- Interception rate of high-risk operations;
- Recovery success rate after failure.
Among these, the “task completion rate” must be based on verifiable standards. For example, code having been written to a file does not mean the requirement is complete. Only when relevant tests, builds, and checks meet expectations can it be considered an effective delivery.
11. A Practical Implementation Roadmap
If building a code agent from scratch, it can be advanced in the following stages:
Phase 1: Implement the minimal closed loop
First support task input, file reading, file modification, and test execution, completing the basic “read—modify—verify” flow.
Phase 2: Add project awareness
Add directory scanning, symbol search, project documentation reading, and context summarization so the model can understand project conventions.
Phase 3: Introduce state management
Record the current plan, completed steps, failure reasons, and next actions to avoid losing context during long tasks.
Phase 4: Strengthen security controls
Add sandboxing, permission control, command allowlists, change auditing, and rollback capabilities.
Phase 5: Optimize verification and recovery
Classify test failures and support local retries, automatic diagnosis, and human takeover.
Phase 6: Establish an evaluation system
Use a set of repeatable engineering tasks to continuously assess completion rate, stability, security, and resource efficiency.
Conclusion
The essence of a code agent is not connecting a large model directly to a terminal. It is building an engineering system that runs around the model. The model is responsible for understanding and reasoning, tools are responsible for interacting with the environment, the orchestration layer is responsible for controlling the flow, verification mechanisms are responsible for confirming results, and the security layer is responsible for limiting risk.
A truly high-quality code agent is often not the most “free” system, but the one that best understands constraints, verification, and recovery. Future improvements in intelligent programming capability will not depend only on model parameter scale, but also on context organization, tool design, execution isolation, feedback loops, and engineering observability. In other words, whether an agent can reliably deliver code depends on both model capability and the entire harness engineering system built around the model.
