AI Coding Agent Architecture: How the Harness Shapes What Agents Can Do
The same foundation model, wrapped in different engineering layers, can deliver very different results in coding tasks. Drawing on a static reverse-engineering analysis of a command-line coding agent, this article explains the Harness, meaning the engineering layer around the model that governs its loop, context, tools, permissions, and state. It then covers the main plan-act-observe loop, layered context management, tool and permission design, state persistence, subagents and hooks, and using an agent to compile a personal knowledge base. It closes with transferable design guidelines, a progressive rollout path, and the limitations of drawing conclusions from a single implementation. The architecture conclusions come from one publicly distributed implementation and are not intended as a production standard.
Introduction: Where the Real Engineering Happens, Outside the Model
AI coding tools are now widely used, and one fact is easily overlooked. When the same model foundation is paired with different engineering shells, task completion quality and reliability can differ enormously. While reverse-engineering an AI coding agent implementation, the community adopted the term “Harness Engineering.”
“Harness” is often rendered as “tack” or “wiring harness.” In software, it has long described a test harness or driver shell: an outer program that wraps the component under test and drives and verifies it. In the agent context, the Harness is the engineering layer that wraps the model. It determines what the model can do, how it does it, and to what extent.
This article uses that idea as a starting point. It distills the general engineering principles of coding agent architecture. It then looks at a practical method for using a large model to compile a personal knowledge base, showing how agent output can accumulate into reusable knowledge artifacts. All of the architectural conclusions here come from a static analysis of one publicly distributed implementation. They may reflect version differences or incidental design choices, and should not be taken as a production architecture standard.
1. From Source Maps to a Code Map: Key Steps in the Analysis
The analyzed subject is a command-line tool distributed as a compressed archive. The archive contains the bundled scripts and their source map files. Source maps record the positional correspondence between bundled code and the original source code. Browser debugging tools use them to restore breakpoint locations. Analysts can use them to reconstruct code much closer to its original structure. The analysis roughly followed four steps:
- Reconstruct the source tree. Parse the original path fields in the source map, reassemble modules according to the directory structure, and obtain a clearly organized source tree that can be read statically.
- Map the module graph. Count the imports and exported interfaces of each module to identify the “hub modules” that are imported most often and concentrate the most dependencies.
- Locate the main loop. Starting from the entry module, trace the control flow to find the core loop that drives multi-turn model reasoning and tool calls.
- Distill design patterns. Against the implementation details, generalize the common approaches to context organization, state management, and access control.
Reverse engineering should also stay within what legal authorization and license terms permit. The goal here is to understand the engineering approach, not to copy code or work around licensing restrictions.
2. Harness Engineering: The Engineering Shell Around the Agent
The mainstream view in the industry is that an agent is a “model + tools + loop.” The model reasons and makes decisions, the tools interact with the external world, and the loop continually couples the two. In practice, what makes an agent effective is often not the model itself, but the scheduling and constraint logic around the loop, which is the Harness. It typically covers the following responsibilities:
- Loop control: Deciding when to continue, when to stop, and when to ask the user for confirmation.
- Context management: Deciding what to show the model, what to keep, and what to compress in each round.
- Tool governance: Defining tool interfaces, validating parameters, executing commands, and trimming results.
- Security and permissions: Defining the accessible scope, the operations that require approval, and the boundaries that can be rolled back.
- State persistence: Making sure a session can be recovered and traced after it is interrupted.
- Extension mechanisms: Fitting into a team’s existing workflows through hooks, subagents, and similar mechanisms.
The division of labor is clear. Models are good at semantic understanding and open-ended reasoning, but they lack a stable execution environment and persistent memory. The Harness exists to offset the model’s uncertainty with deterministic engineering. In short, determinism sits outside, and uncertainty stays inside. The model’s internal reasoning is the uncertain part. Conditionals, state machines, timeouts, and retries in the scheduling framework are the deterministic part. The analyzed implementation contains a large amount of auxiliary logic that has nothing to do with the model, such as:
- environment checks at startup
- tool-list assembly
- output formatting
These pieces may seem trivial, but they directly shape the actual experience. Focusing only on prompts or model selection, and ignoring this layer, rarely produces a stable agent application.
3. The Main Loop: Plan, Act, and Observe, Round by Round
Most coding agents essentially run a loop of “model reasoning → tool execution → result feedback.” The pseudocode below illustrates this structure:
while not task_done and step < max_steps:# 1. Assemble context: system instructions + tool definitions + task and environment info + message historymessages = build_context(session)# 2. Call the model to get a natural language reply and (optional) tool call requestsreply = llm.invoke(messages, tools=tool_registry.schemas())# 3. Execute tool calls one by one; each tool validates its parameters, runs, and trims the resultfor call in reply.tool_calls:result = tool_registry.execute(call) # Includes parameter validation, timeout, and error handlingmessages.append(tool_result_message(call.id, summarize(result)))# 4. Check termination conditions: task completed, user confirmation required, budget exhausted, etc.if reply.finished:task_done = True
In practice, the key details usually include:
- Budget constraints: Set upper limits on the maximum number of steps, the timeout for each tool call, and the total elapsed time, so that the agent doesn’t get stuck in an endless loop.
- A closed error-feedback loop: When a command fails, feed stderr and the exit code back to the model unchanged. This lets the model adjust its approach based on the error, rather than simply retrying.
- User-facing confirmation points: Before side-effecting actions such as writing files or running commands, show the plan and wait for the user’s approval.
- Separating planning from execution: First generate a task list, then work through the items one by one and record progress in a persistent file. This makes it easier for users to track progress and for an interrupted session to resume.
4. Context Engineering: Managing Information Within a Finite Window
The context window is one of an agent’s scarcest resources. Every round has to carry the system instructions, tool definitions, and message history again. Tool results, such as file reads and command output, can also grow quickly. The analyzed implementation uses a layered curation strategy built around the context window:
- Input compression. When reading a large file, extract only the relevant portions. When command output is too long, keep only the beginning and the end, and tell the model it can view more on demand.
- History compression. When the message history approaches the budget limit, summarize the early conversation into a structured summary. That summary can cover completed work, key decisions, files involved, and outstanding tasks. The summary then replaces the original messages.
- Context offloading. Write the full records to disk and keep only a reference in the context. When the model needs the details, it retrieves them through search or by reading the files.
This is what the industry calls context engineering. It is a system design built around “what to show the model,” and it is far more involved than stuffing all the information into a prompt. A practical rule is that every piece of content that enters the context should answer one question: “Why does the model need this right now?” Content that can’t answer it should be summarized, retrieved on demand, or offloaded.
5. Tool Design and Permission Control: Making Capability Boundaries Explicit
Tools are the agent’s only channel for affecting the real world, so their design directly determines how safe and reliable it is. The analyzed implementation reflects several principles worth borrowing:
- Moderately sized tools: Tools should be neither so abstract that the model struggles to combine them nor so granular that the number of calls explodes. Capabilities such as reading and writing files, searching content, executing commands, and searching the codebase usually become separate tools. Each one has clear parameter descriptions and usage instructions.
- Descriptions are the contract: A tool’s name, parameter descriptions, and return format are effectively its usage documentation for the model. Vague tool descriptions often lead to many invalid parameter constructions and failed calls.
- Layered permissions: Read-only operations can run automatically. Writes and command execution typically require user confirmation. Operations such as network access and reading environment variables can be disabled by default. Permission rules can be configured per directory and per command pattern. The runtime environment is also checked at session start for required preconditions.
- Intercepting dangerous operations: Some implementations run user-defined validation logic before and after tool execution. For example, they may block writes to system directories or forbid destructive commands. Exit codes express three outcomes: block, allow, or require confirmation.
This “least privilege by default, explicit authorization on demand” approach follows the idea of capability isolation in operating systems. For agents, permission design isn’t only a security requirement. It is also what allows the model to explore boldly within clear boundaries.
6. State Persistence: Making Long Tasks Recoverable and Traceable
A single programming task can involve dozens of tool calls. If the process is interrupted, starting over from scratch wastes cost and loses context. Persisting state as files or structured records is a general way to improve robustness:
- Externalizing the task list: Write the plan items to a task list file and mark each one’s status as it is completed. After an interruption, the agent can use the file to decide where to resume.
- Persisting session records: Save the full message history to a session file to support resuming, branching, and going back to earlier points.
- Layered configuration: Merge user-level, project-level, and directory-level configuration in order. This lets team conventions be versioned together with the code repository.
- Checkpointing: Record the current workspace state before key steps, so that when a problem occurs, you can return to a known-good point.
This also explains why many agent tools use the file system as their memory. Files are a universal format that both the model and humans can read. They can also be version-controlled, reviewed, and moved between environments.
7. Subagents and Hooks: From a Monolithic Loop to an Orchestrated System
When a task is too large for a single session, you need more complex collaboration structures. Two patterns are common:
- Subagent delegation: The main agent only handles planning and summarization. It delegates independent subtasks to subagents, each with its own context, and they return only their conclusions when they finish. This allows multiple tasks to run in parallel without the main context being flooded with intermediate details.
- Hooks: User-defined logic runs at lifecycle points, such as session start, user submission, and before or after a tool call. Hooks can inject project conventions, enforce consistent format checks, record audit logs, or adjust permissions dynamically based on command content.
Both patterns point to the same trend: agents are evolving from “a script” into “an orchestratable system.” Developers need to think about module boundaries, communication protocols, and failure handling the way they would when designing a distributed system.
8. From Code to Knowledge: Compiling a Personal Knowledge Base with an Agent
Researchers in the field have recently shared a practice for using a large model to build a personal knowledge base around a research topic of interest. This practice closely mirrors Harness engineering. The workflow roughly goes as follows:
- Data ingestion: Index raw materials such as articles, papers, code repositories, datasets, and images into a
rawdirectory. That directory serves as the single source of truth. - Compiling into structured text: Have the large model progressively “compile” the material into a set of interlinked text files, following the directory structure. Each file contains a summary of the source material, backlinks, and concept categorization. Different concepts cross-reference each other.
- Using an editor as the frontend: Treat the local editor as a single entry point for viewing source material, browsing compiled results, and visualizing charts. The model writes and maintains most of the compiled results. People mainly handle review and decision-making.
- Question answering over the knowledge base: Once the knowledge base grows to a certain scale (for example, hundreds of articles and several hundred thousand words), let the agent search and organize answers on its own. At a moderate scale, it often doesn’t need an additional, complex retrieval-augmented setup.
- Diverse outputs: Produce results as text files, slides, charts, and other formats. These can then be viewed and refined in the editor.
This method contains two ideas worth borrowing.
The first is “compile” rather than “retrieve.” Knowledge accumulates over the long term as human-readable, structured files. The model processes only the parts relevant to each question, which controls context overhead at the source.
The second is a shift in the roles of people and the agent. Instead of confirming each step, people move to being “on the loop.” They set goals, review results, and step in at key points. This lets them spend far more tokens on the knowledge itself than on code.
For enterprise teams with large volumes of documents, specifications, and historical tickets, this “compiled knowledge base” approach also works for building internal knowledge assets.
9. From Source Analysis to Engineering Practice: Transferable Design Guidelines
Taken together, the analysis above yields several engineering guidelines that apply to most agent applications:
- Budget the context: Set separate budgets for system instructions, tool definitions, history, and tool results. Define clear priorities and trimming strategies for each.
- Define tool contracts: Write clear tool descriptions, validate parameters strictly, and trim results appropriately, so the model can “understand them and use them correctly.”
- Turn state into artifacts: Persist plans, progress, and knowledge as version-managed files. This makes tasks recoverable, auditable, and reusable.
- Minimize permissions: Default to read-only and grant access on demand. Add human confirmation steps before critical operations.
- Make control points explicit: Reserve extension points at key lifecycle stages, so team conventions can be enforced in code.
- Make evaluation routine: Build an offline task set to continuously track task completion rate, average interaction rounds, tool call success rate, and token cost. Use this data to drive iteration.
10. Rollout Recommendations and Caveats
In real projects, a gradual approach works best: constrain first, grant permissions later. Start by limiting the agent to read-only analysis and suggestions. Once it proves stable, gradually open write and execution permissions, and add log retention and behavior auditing.
In the cloud, you can build an elastic, observable agent runtime environment using general capabilities such as container services, object storage, log services, and monitoring and alerting. Cloud providers such as Baidu AI Cloud offer general support in compute, storage, and observability. This lets teams focus on designing and tuning the Harness layer.
At the same time, three limitations should be kept in mind:
- Single-implementation findings aren’t universally applicable. Reverse-engineering conclusions from one implementation may not generalize and need to be validated against your specific business.
- Model capabilities are evolving quickly. Some responsibilities currently handled by the engineering layer may eventually be absorbed by the models themselves.
- Context windows and inference costs are hard constraints. Blindly chasing “longer context” is not the optimal solution.
For developers who want to understand agent systems more deeply, source code is excellent teaching material. But what ultimately determines results is still accurately breaking down the business problem and continually refining the engineering details.
