Layered Design and Engineering Governance for AI Coding Agents
The value of AI coding agents comes not from generating longer code in one pass, but from turning task understanding, repository modification, and result verification into a repeatable loop. This article presents a six-layer system view, five diagnostic surfaces, context governance practices, the division between skills and hooks, controlled subagent autonomy, prompt-cache boundaries, project-instruction design, and a minimal implementation loop for making coding agents more auditable, controllable, and reliable in engineering workflows.
The value of an AI coding agent is not that it generates a longer piece of code in one attempt. Its value is that it turns “understand the task, modify the repository, verify the result” into a repeatable loop. Many teams initially treat such an agent as a chatbot: put a problem in, paste an answer back. As context grows, rules become more detailed, and more tools are connected, the agent may instead miss file changes more often, violate conventions, repeat work, or keep committing changes in the wrong direction. Experience suggests that the bottleneck is rarely that “the model is not smart enough.” More often, the system gives the agent the wrong persistent information, or it produces a result without any way to judge correctness, roll back, or audit the work.
1. Start with the operating loop, not a single answer
The core of a coding agent is repeated execution: collect context, take action, verify the result, and return to collection if the task is not complete. Rule files, memory, skills, tools, permissions, sandboxes, and hooks are inputs to or constraints on this loop. They are not independent features stacked on top of one another.
The collection phase determines what the model “sees”: repository structure, the current diff, relevant tests, interface contracts, and recent failure logs. The action phase determines what it “can change”: read files, edit files, run checks, and call external capabilities. The verification phase determines whether it “can stop”: tests, static checks, builds, screenshots of critical pages, logs, and continuous integration results. If any of the three is missing, the agent can reinforce its own errors inside an ambiguous goal.
In engineering terms, completion conditions should be written as observable facts, not subjective feelings. For example: “relevant tests pass, static checks show no new issues, the diff touches only agreed directories, and key interface contracts are not broken.” Without these facts, the loop cannot stop reliably, and people lose the basis for rollback.
2. View the system in six layers instead of strengthening one point
A coding agent can be understood as six layers, each answering a different question.
The long-term context layer answers “what is this?” Project descriptions, coding conventions, architectural boundaries, prohibited actions, and stable memory belong here, but they must be short, stable, and versioned. This layer tells the agent the invariant facts of the repository; it should not contain the steps for every task.
The action layer answers “what can it do?” Built-in read, write, and execution capabilities, plus external tools connected through protocols, form the action surface. Actions should be few and clear: names express intent, parameters express boundaries, and failure messages are diagnosable. When there are too many tools, the model has to guess between similar capabilities. Wrong calls consume context and further reduce the quality of subsequent choices.
The method layer answers “how should it be done?” Skills or operating manuals should be loaded on demand: one short document each for debugging defects, adding tests, database changes, and release checks. What remains resident is the index and trigger conditions; the body enters context only when the task matches. This preserves specialized methods without letting irrelevant steps pollute every conversation.
The constraint layer answers “what must happen?” Permissions, sandboxes, and hooks do not depend on the model’s self-discipline. Dangerous commands are denied by default, sensitive directories are read-only, checks must run before commit, and external writes must leave an audit trail. Judgment can be delegated to the model; mandatory actions should be delegated to the system.
The isolation layer answers “who is working independently?” Subtasks, worktrees, or forked sessions are used for parallel exploration, broad retrieval, and experiments with side effects. They bring back conclusions and evidence instead of pouring the entire intermediate process back into the main session.
The verification layer answers “is the result trustworthy?” Tests, checkers, screenshots, logs, and pipelines form the closed loop. A task is allowed to be marked complete only when verification passes; on failure, the minimum necessary error information returns to the collection phase.
Strengthening only one layer causes imbalance. If the instruction file is too long, context pollutes itself first. If tools fill the surface, the choice space collapses. If subtasks are opened everywhere, state drifts. If verification is skipped, failures cannot be attributed to context, action, or environment.
3. Five working surfaces for locating failures
When troubleshooting, do not blame the model first. Ask questions against five surfaces.
Context surface: which information is resident and which is loaded on demand. Resident information should contain only project identity, directory boundaries, quality gates, and explicit prohibitions. Task details, long logs, and full file contents should be injected on demand and can be discarded or summarized after use.
Action surface: which actions are actually available, and whether their descriptions overlap. Overlapping tools should be merged or given mutually exclusive descriptions; otherwise the agent will waver between equivalent paths.
Control surface: which actions must be blocked, require human confirmation, or must be audited. Deletion, push, production configuration, and secret reading should not rely on a prompt saying “please be careful.”
Isolation surface: which tasks would dirty the main context. Broad searches, comparisons of multiple approaches, and generation of many candidates are suitable for isolated executors that return only diffs, conclusions, and failure reasons.
Verification surface: how to judge that a task is complete and trustworthy. “It looks right” without automated evidence cannot be a stopping condition.
A practical triage order is: first check whether completion conditions are decidable, then check whether resident context is outdated or too broad, then check whether there are too many tools, and only then consider whether the model is unsuitable for the task.
4. Why context becomes messy, and how to govern it
Context usually becomes messy through four paths. First, historical conversation is treated as memory, so early wrong assumptions remain present. Second, entire repository descriptions, all specifications, and irrelevant comments are inserted at once. Third, tool returns contain extremely long logs that crowd out the code that actually matters. Fourth, multiple subtasks each change state, while the main session sees only fragments.
The governance principles are layered retention, on-demand expansion, and regular compression.
The stable layer holds project descriptions in the versioned repository: technology stack boundaries, module responsibilities, test commands, generated directories that must not be modified, and interface compatibility requirements. It should be reviewable through code review and change together with the code. Its length should be something a person can read in one sitting; if it exceeds that, split it into on-demand rules.
The task layer serves only the current goal: relevant files, failing test names, expected behavior, and things not to do. When the task ends, archive a summary instead of leaving the entire process for the next round.
The evidence layer keeps only reviewable fragments: failed assertions, key stack frames, and diff summaries, not full build logs. Long outputs should first be truncated and aggregated externally, and then the conclusions should be sent back to the model.
Memory must distinguish facts from inferences. Dependency versions and directory conventions are facts. “This module probably handles payments” is only an inference unless verified, and should not be written into long-term memory. Outdated facts are more dangerous than missing facts because they mislead later changes with an authoritative tone.
As an illustration, a project description can maintain this density instead of becoming an encyclopedia:
Goal: Maintain compatibility and testability of the order serviceBoundary: Change only the service implementation and corresponding tests; do not hand-edit generated code or lock filesGate: Run unit tests and static checks before committingForbidden: Print secrets, skip failing tests, or expand public interfaces without contract documentationDone: Relevant tests pass, and the change description lists behavior changes and rollback method
5. Skills and hooks: one relies on discipline, the other on enforcement
Skills are suitable for “methodology,” not for “things that must never be violated.” For example, the steps for locating a regression: reproduce the failure first, reduce it to a minimal case, change only the necessary code, and finally add a check that can block the regression. Such content can be loaded by task and improves consistency, but the model may still skip steps.
Hooks are suitable for non-negotiable checkpoints: before writing, check whether the path is within the allowed range; before execution, block interactive or destructive commands; after completion, force the agreed checks to run and disallow claiming completion if they fail. Hook inputs and outputs should be stable and loggable, and failure messages should be short and actionable, avoiding the insertion of another long document into context.
When designing, list risks first, then decide which layer they belong to. Style preferences belong in descriptions or skills; data loss, privilege escalation, and secret leakage belong in permissions and hooks; exploratory refactoring belongs in isolated tasks; correctness belongs in verifiers. Writing every hope as a prompt is equivalent to handing the safety boundary to probability.
6. The correct use of subtasks is controlled autonomy
A subtask is not simply opening more chat windows to share the load. It is a worker with isolated context and permissions. Suitable scenarios include reading independent modules in parallel, comparing two implementations and returning only the trade-offs, and testing a migration in a temporary working copy.
It is not suitable for the main path that requires continuous modification of the same set of files. When multiple executors change the same state at the same time, it is impossible to determine during merge which assumption still holds. The correct contract is: the main session owns task decomposition and the final diff; subtasks receive explicit inputs, permission limits, and return formats; returns contain only conclusions, evidence, and unresolved questions. Subtasks should not inherit all history, nor should they have broader write permissions than the parent task.
Typical signals of state drift are: the file content in the main session is inconsistent with disk, subtasks continue working from outdated interfaces, and the same problem is fixed repeatedly. Mitigation: re-read critical files before each action, treat the workspace as the single source of truth, and use memory only as an index.
7. Prompt caching changes architecture, not just cost
Long system prompts, stable tool descriptions, and invariant project descriptions are suitable for a cacheable prefix; volatile diffs, logs, and the current question belong in the suffix. This can reduce repeated transmission and latency, but it introduces architectural constraints: once the prefix contains outdated rules, the error is reused at high speed; if frequently changing content is stuffed into the prefix, cache hit rates fall, and the boundary between “stable” and “volatile” becomes blurred.
Therefore, cache boundaries should align with information lifecycles. Project descriptions, tool lists, and security policies belong to the slow-changing prefix; the current branch, failure output, and user follow-up questions belong to the fast-changing suffix. After modifying rule files, treat it as a cache invalidation event to avoid mixing old and new rules. During evaluation, look at hit rate, error rate, and rollback cost together, not only at whether a single call becomes cheaper.
8. How to write project instructions that are actually useful
A useful instruction file is like an interface, not a tutorial. A fixed five-part structure is recommended: what the system is, where changes are allowed, how to verify, when to stop and ask a human, and what evidence to provide at completion. Each part should use executable statements and avoid undecidable words such as “be as elegant as possible” or “refactor appropriately.”
Anti-patterns include pasting an entire specification, listing every historical incident, using instruction files to replace tests, turning personal preferences into global prohibitions, and embedding a long series of tool tutorials in the instructions. The longer the instructions, the harder it is for the model to distinguish priorities, and the more likely the later sections will contradict earlier ones.
Maintenance can be lightweight: every time the agent violates a stable convention, add one short rule and pair it with a check that can fail; every time a rule is found to be outdated, delete it instead of appending exceptions. The number of rules should decrease as automated checks increase. If something can be guaranteed by a test or hook, do not write it into the prompt again.
9. The minimal closed loop for implementation
Teams do not need to implement every layer at once. The minimum viable closed loop is: a short project description, a set of non-overlapping base actions, one mandatory pre-commit check, and clear stopping conditions. On top of that, add on-demand skills, isolated subtasks, and a cache prefix.
When reviewing agent output, look at three things: whether the diff falls within the authorized scope, whether the verification evidence is reproducible, and whether a failure can return to the last known good state. Only when these three are in place does a coding agent move from “a conversation that can write code” to a governable engineering system. For enterprise deployment, object storage can hold task summaries and evidence, logs and monitoring can audit tool calls, and containers and permission policies can limit the execution surface. These are general capabilities; the key remains clear layered responsibilities and decidable completion conditions.
