Enforcing Architecture and Developer Taste
Enforcing Architecture and Developer Taste
Section titled “Enforcing Architecture and Developer Taste”Imagine hiring an incredibly fast, highly enthusiastic junior developer who has memorized every programming language but has never actually maintained a codebase for more than a week. If you leave them alone in your repository, they might build exactly the features you asked for, but the resulting code will likely resemble a massive bowl of spaghetti. In AI Harness Engineering, we face the exact same challenge. This chapter explores how to build mechanical boundaries to keep your AI agents disciplined and ensure they write code that aligns with your specific architectural vision.
The Threat of AI Spaghetti Code
Section titled “The Threat of AI Spaghetti Code”AI agents are optimization machines. When given a task like ‘add a user login feature,’ they will instinctively look for the path of least resistance to achieve that goal. Because they lack a human’s intuitive understanding of long-term maintainability, they are prone to architectural violations.
Without strict boundaries, an autonomous agent might commit several ‘crimes’ against your codebase:
- Layer Bypassing: Writing raw SQL queries directly inside a React UI component instead of calling an API.
- Monolithic Functions: Generating massive 500-line functions instead of breaking logic into smaller, testable helpers.
- Library Sprawl: Importing three different HTTP client libraries to solve similar problems across different files.
- Inconsistent Naming: Mixing camelCase, snake_case, and PascalCase depending on whatever code snippet the AI saw last in its training data.
You cannot prevent these issues by simply asking the AI nicely in its initial system prompt. System prompts get forgotten or ignored as the context window fills up. Instead, you must enforce your architecture mechanically.
Defining Your Developer Taste
Section titled “Defining Your Developer Taste”Before you can enforce rules, you must define your ‘developer taste.’ Taste is the subjective preference of your engineering team made objective. It represents the design patterns, coding paradigms, and structural choices that make your codebase feel cohesive.
To build an effective harness, you must translate these subjective tastes into black-and-white rules that a machine can evaluate. For example:
- Subjective Taste: ‘Keep UI components dumb and stateless.’ -> Objective Rule: React components in the
/components/uifolder are not allowed to import from the/servicesfolder. - Subjective Taste: ‘Use clean error handling.’ -> Objective Rule: Every asynchronous function must use a standard
Result<Success, Error>return type wrapper. - Subjective Taste: ‘Keep files small and readable.’ -> Objective Rule: No file shall exceed 300 lines of code.
Boundaries as Code: Custom Linters and Structural Tests
Section titled “Boundaries as Code: Custom Linters and Structural Tests”To enforce your taste, you need tools that run autonomously every time the agent attempts to save or commit code. Standard linters (like ESLint for JavaScript or Flake8 for Python) are great for catching syntax errors, but you must go further by building structural tests.
Structural tests utilize Abstract Syntax Trees (ASTs) or dependency graphing tools to map out how different parts of your code communicate. If an agent tries to wire a database connection directly to a web route, the structural test will fail, blocking the change.
| Test Type | What It Checks | Example Scenario |
|---|---|---|
| Standard Linters | Syntax, style, and basic bugs | Missing semicolons, unused variables |
| Dependency Rules | Allowed import paths between modules | Preventing the UI layer from importing the Database ORM |
| AST Custom Rules | Specific code structures and patterns | Ensuring every API route contains a logging statement |
| Size Thresholds | Complexity and length limits | Failing the build if a function exceeds 50 lines |
The Magic of Automated Remediation Prompts
Section titled “The Magic of Automated Remediation Prompts”Stopping the agent from committing bad code is only half the battle. If a test fails with a cryptic error like Error: Dependency violation in file auth.ts, the agent might not know how to fix it. It might start guessing, leading to a downward spiral of chaotic, trial-and-error code changes.
The secret weapon of AI Harness Engineering is injecting helpful remediation instructions directly into the prompt context. When an agent breaks a rule, your harness should not just yell ‘Error!’ It should gently guide the agent back to your preferred architectural path.
An effective remediation prompt includes three things:
- The Exact Error: What specifically failed.
- The Architectural Rule: A reminder of why this rule exists based on your ‘taste’.
- The Correct Pattern: A quick code snippet or instruction showing the AI exactly how to do it right.
Implementing the Remediation Loop
Section titled “Implementing the Remediation Loop”Let us look at a conceptual TypeScript example of how a harness intercepts a structural test failure and formats it into a highly effective learning moment for the agent.
// Example of a Harness Remediation Loop
function evaluateAgentCode(agentCommitFiles) { const validationResult = runArchitectureLinters(agentCommitFiles);
if (!validationResult.passed) { // The agent broke an architectural rule const errorDetails = validationResult.errors[0];
// Construct a specialized remediation prompt const remediationPrompt = ` Your recent code changes failed the architectural validation.
Error: ${errorDetails.message} in file ${errorDetails.file}
Rule Reminder: In this project, we enforce a strict separation of concerns. UI components are NEVER allowed to import directly from the database layer.
How to fix this: Instead of calling the DB directly, please import the appropriate function from the 'services/' directory. If the service function does not exist, create it there first, and then call it from your UI component.
Please rewrite your code and try again. `;
// Feed this directly back to the agent as its next instruction sendPromptToAgent(remediationPrompt); }}By wrapping your AI agents in this tight, feedback-rich harness, you mechanically enforce your architectural boundaries. The agent learns your ‘taste’ on the fly, transforming from a chaotic code-generator into a disciplined software engineer that respects your project’s structural integrity.