keepcalculator

06 Numbers and Powers

Coding Agent Architecture: Making Rules Stick

Card No. 06·33106 · Updated · Standard formula, shown below

Coding agent architecture is the structural design of AI systems that write, edit, and maintain code, and making rules stick within these agents requires moving from vague instructions to explicit, enforceable constraints embedded in the agent’s workflow. This guide explains the practical patterns that let you define rules once and have them reliably influence every code change, from simple prompts to sandboxed execution and automated verification.

Why Rules Fail in Naive Agents

The most common reason coding agents ignore rules is that the rules live only in a system prompt. Large language models treat prompts as probabilistic suggestions, not hard constraints. If a rule conflicts with the model’s training bias or the immediate task, the model may silently drop it. For example, telling an agent “always use type hints” works until the agent is in the middle of a long refactor and the token window pushes the instruction out of attention. Similarly, rules written in natural language are ambiguous: “avoid deprecated APIs” requires the model to know which APIs are deprecated in the current codebase, which it often doesn’t.

Another failure mode is that agents often operate on a single file in isolation, so cross-file rules (like “all database access goes through the repository layer”) are invisible. The agent sees the function it’s editing, not the architectural boundary. Finally, many agents have no feedback loop: they generate code, but nothing checks whether the output actually conforms to the rules. Without enforcement, a rule is just a suggestion.

Core Architectural Layers for Rule Enforcement

Making rules stick requires distributing them across four layers of the agent’s architecture:

  • Static context layer: Rules are injected into the prompt as structured data (e.g., a JSON schema of allowed patterns) rather than prose. This makes them more likely to be followed because structured formats are easier for the model to parse and apply.
  • Runtime sandbox layer: The agent executes code in a container or virtual machine where filesystem access, network calls, and process execution are restricted. Rules like “no file writes outside /tmp” become enforced by the sandbox, not by the model.
  • Verification layer: After the agent produces a change, automated tools (linters, type checkers, unit tests, custom scripts) run against the code. If a rule is violated, the agent receives the error output and must fix it before the change is accepted.
  • Memory layer: Rules are stored in a persistent knowledge base that the agent queries at each step, rather than relying on the model’s context window. This allows rules to be long, detailed, and consistent across sessions.

Each layer addresses a different failure mode. The static context layer improves initial compliance; the sandbox makes violations impossible; the verification layer catches what the model missed; and the memory layer ensures rules survive across long tasks and multiple sessions.

How to Structure Rules for Maximum Adherence

Rules themselves need to be written in a way that models can reliably follow. The most effective format is a combination of:

  • Explicit “must” and “must not” statements with concrete examples. Instead of “write clean code,” say “every function must have a docstring that explains parameters and return value. Example: def add(a, b): ...”.
  • Machine-readable constraints where possible. For instance, a rule like “max line length 100” is better expressed as a linter configuration than as a sentence.
  • Scoped rules that specify where they apply. “Use the repository pattern for all database access” is clearer than “use good architecture.”
  • Priority ordering so the agent knows which rule wins when two conflict. For example, “safety rules override style rules.”

In practice, a rule file might look like this (in a pseudo-config):

rule: no_console_log
  pattern: "console.log"
  action: reject
  message: "Use the logger utility instead."
rule: type_hints
  pattern: "def .*:"
  action: require
  check: "python -m mypy"

This is far more effective than a prompt that says “don’t use console.log.” The agent can see the exact pattern and the exact consequence.

Implementing the Verification Loop

A coding agent without a verification loop is like a writer without an editor. The loop works like this:

  1. The agent generates a patch or a new file.
  2. The patch is applied to a clean checkout of the repository in a sandbox.
  3. Automated checks run: linters, formatters, type checkers, unit tests, and any custom rule scripts.
  4. If checks pass, the change is accepted and committed.
  5. If checks fail, the error output is fed back to the agent, and it must revise the code to fix the errors.
  6. Steps 2–5 repeat until checks pass or a maximum retry count is reached.

This loop turns rules from suggestions into hard gates. The key is that the verification must be fast enough to keep the agent productive. For large codebases, you can run only the checks relevant to the changed files first, then run the full suite later. Also, the error messages must be specific: “line 12: missing type hint for parameter ‘x’” is actionable, while “lint failed” is not.

Common Pitfalls and How to Avoid Them

  • Too many rules: If you give the agent 200 rules, it will ignore most of them. Prioritize the 10–20 that matter most, and enforce the rest with automated tools.
  • Vague rule language: “Use best practices” is meaningless. Every rule should be testable by a script or a linter.
  • Rules that conflict with each other: For example, “never use global variables” and “use a global config object” can’t both be true. Resolve conflicts explicitly in the rule file.
  • No feedback on rule violations: If the agent breaks a rule and nothing happens, the rule is effectively dead. Always attach a consequence (reject, warn, or auto-fix).
  • Rules that are not versioned: Rules should live in the repository, not in the agent’s prompt, so they change with the codebase and are reviewed like code.

Comparing Different Agent Architectures

There are three common architectures for coding agents, each with different rule-enforcement capabilities:

  • Single-pass generation: The agent generates the entire code in one go from a prompt. Rules are only in the prompt, so enforcement is weak. This is fine for small, one-off tasks but not for maintaining a large codebase.
  • Iterative edit with feedback: The agent makes small edits, runs tests, and fixes errors. This supports a verification loop and is the most common architecture for production use. Rules can be enforced via tests and linters.
  • Multi-agent systems: Different agents handle different roles (e.g., one writes code, another reviews it, another runs tests). Rules can be enforced by the reviewer agent, but this adds complexity and latency.

For most teams, the iterative edit with feedback architecture is the sweet spot: it’s simple enough to reason about, and it allows rules to be enforced through the standard development toolchain.

Cost, Safety, and Alternatives

Enforcing rules adds cost: each verification loop consumes API tokens (for the agent’s retries) and compute time (for running tests). To manage cost, you can run only the most critical checks during the agent loop and defer the full suite to CI. Safety is another consideration: sandboxing prevents the agent from executing arbitrary commands on your local machine, which is essential if the agent is working with untrusted code. Alternatives to a custom architecture include using existing developer tools that already enforce rules (like linters and CI pipelines) and integrating the agent with them, rather than building a separate enforcement layer. For teams just starting out, the simplest approach is to add a verification loop to an existing agent and write a small set of high-priority rules in a structured format.

Frequently Asked Questions

How do I get the agent to remember rules across sessions?

Store rules in a file in the repository (e.g., AGENT_RULES.md or a structured YAML file) and have the agent load that file at the start of each session. This is more reliable than relying on the model’s context window, which is limited and may drop early instructions.

What if the agent keeps violating a rule even after I add it to the prompt?

Move the rule from the prompt to the verification layer. Write a script or linter that checks for the violation and have the agent’s output run through it. If the check fails, the agent must fix the code. This guarantees compliance, regardless of the model’s behavior.

Can I use natural language rules or do they need to be code?

Natural language is fine for human reading, but for the agent, you need something testable. Turn each natural-language rule into a concrete check (a regex, a linter rule, a unit test). If you can’t write a check for it, it’s probably too vague to be enforced.

How many rules should I have?

Start with 5–10 critical rules. Too many rules overwhelm the agent and slow down the loop. You can add more later as you identify recurring violations. Prioritize rules that prevent bugs or security issues over style preferences.

Does the verification loop slow down the agent a lot?

It adds latency, but you can mitigate it by running only the checks that are relevant to the changed files. For example, if the agent edits a Python file, run the Python linter and the unit tests for that module, not the entire test suite. The trade-off is worth it because you catch violations immediately.

What’s the best way to handle conflicting rules?

Define a priority order in your rule file. For example, mark security rules as priority: high and style rules as priority: low. When the agent encounters a conflict, it should follow the higher-priority rule. If you have many conflicts, it’s a sign your rules are too complex—simplify them.

Related

Method: the standard formula for this calculation, rounded as each result states. See how the calculators work or report an error.

More cards in this drawer

The whole Numbers and Powers drawer →