Keeping agents consistent

Instructions and checks for consistent agent-written code.

11 min read Part 3 of 3

A convention needs a route into the work

I can write a careful architecture document and still receive a change that ignores it. The agent may never load the document. It may follow an older neighboring component. It may apply the filenames while missing the reason the responsibilities were separated.

That is why I want three things working together: a small set of architectural principles, a repeatable workflow for the agent, and checks that reject concrete violations while implementation is still in progress. The agent can help build those checks too; validation is part of the task, not just something a reviewer does afterward.

This follows the first two articles in the series: Architecture for delegation establishes the feature boundaries, and Verification that earns trust explains the feedback I want from them. Here, the question is how to make those choices repeatable as more work is delegated.

Give the agent a decision procedure

“Use clean architecture” leaves most of the important choices unresolved. I want instructions that help the agent decide what the requested feature actually needs.

For the workout planner, the agent should identify the duration and zone draft, the calculation, the save operation, and the observable requirements. It should keep the draft with the editing unit, derive the kJ estimate locally, and put persistence and cache behavior in a use case. A zone change does not need a server request just because saving does.

The target convention must be explicit: our example uses 60% of FTP for Endurance and 80% for Tempo, not universal zone definitions. With an FTP of 250 W, 60 minutes in Endurance gives a 150 W target and 540 kJ of estimated mechanical work. That concrete requirement is more useful than asking the agent to build a generic workout calculator.

For a badge that only displays supplied values, it should do much less. A view is enough. A disclosure can keep its own visual state. The instructions should prevent unnecessary architecture as deliberately as they prevent mixed responsibilities.

I use a skill as the workflow around those decisions. It tells the agent which reference to read, how to approach implementation or extraction, and what evidence to return. The principles explain why. The skill should not repeat the entire reference document.

The exact location and loading mechanism depend on the agent environment. What matters is that the instruction is discoverable at the point of work. An important document with no reliable route to it is an optional read in practice.

Make validation part of the working procedure

I do not want the workflow to be “generate the feature, then ask someone to validate it.” Before implementing a slice, the agent should identify the requirement, the existing checks, and any missing evidence. If an important check does not exist, building it can be part of the delegated task.

For the workout example, that means calculation checks for units and zone targets, an interaction check that changing duration or zone updates the displayed kJ, and save checks that retain the draft after failure. Removing the minutes-to-seconds conversion should fail the 540 kJ reference case. For an architecture restriction, an ESLint or dependency rule needs both valid and violating fixtures. The checks should reject a concrete mistake, not merely record the current implementation.

During implementation, the agent runs the fast checks relevant to its change, reads the failures, and corrects the cause. A failure in an assertion is different from a broken test environment. If it proposes changing the check or the requirement, I want that decision explained rather than hidden in a green result.

Focused mutation testing can challenge the important behavioral assertions. Relevant E2E journeys exercise the assembled feature before handoff, followed by the project’s full required quality gate. I would choose the cadence by risk and runtime: a full mutation campaign or browser suite after every small edit would make the feedback unnecessarily slow.

The handoff names the checks run, the behavior they exercised, the defects they rejected, and the boundaries they replaced. A skipped check is an explicit gap, not a passing result. This is how the workflow makes validation repeatable without pretending that all green checks mean all behavior is correct.

Choose a reference carefully

“Follow nearby code” is useful until nearby code contains the drift I am trying to prevent. I prefer one small, reviewed reference feature whose responsibilities and tests are easy to inspect.

It should be real enough to exercise a domain calculation, local input, a mutation, and an error path. Our workout editor receives the rider’s loaded FTP from its host; it does not need to fetch it again merely to demonstrate a query. The reference should stay small enough that an agent can understand it without touring the application.

The reference is not a template that every feature must fill. It shows where responsibilities go when they exist. Copying the same files into a read-only section would miss that distinction.

Code stays in the app’s feature folders. A shared service provider can already be a test seam. I do not need package extraction to make a dependency replaceable, and I do not want the skill to turn a specific deployment arrangement into a universal rule.

Let checks reject what they can actually see

Instructions steer decisions. A dependency check can reject a view importing a controller, core importing a query library, or production code importing a development adapter. Type checking can make contradictory workflow states harder to represent. Calculation tests can reject incorrect kJ, and interaction tests can reject a duration change that leaves the displayed estimate unchanged.

Those are different mechanisms, and I want to be explicit about their coverage. A clean import graph does not establish good state ownership. A controller can import only permitted modules and still coordinate several unrelated features.

Describe the work
A requirement, ownership rules and a reviewed example.
Build the checks
The agent helps build missing rules and behavioral checks.
Implement and validate
Change one slice, run focused checks and correct failures.
Challenge the evidence
Use relevant defects, mutation runs and end-to-end journeys.
Review the result
Run required gates and name unverified integrations.
Validation runs during implementation. A failed check sends the slice back for correction, not a weaker assertion. Passing checks support review; they do not replace it.

The checker also needs a concrete way to classify files. A hook name is not enough: a query hook and a controller hook can both start with “use.” The adopting project should choose locations or metadata that distinguish core, use cases, controllers, views, contracts, and adapters.

I care about resolved dependencies, including aliases and re-exports. Restricting one import spelling can leave a helper or barrel as a route around the same boundary. Transitive checks can require more setup than simple lint patterns, so I would introduce them according to actual risk and report the remaining coverage honestly.

These are acceptance cases for a checker, not a claim that this series delivers one. An LLM can help implement the rule and its fixtures, but I would review the classifications and run real violations against the configured tool. Checking that a configuration contains a glob does not establish that the rule catches the offending file. Neither does accepting fixtures whose expected outcomes were inferred from the checker’s own output.

Keep useful exceptions explicit

A view can own focus behavior and viewport subscriptions. A controller can compose child units. A view can import a plain type from core without importing the controller’s runtime state. A browser adapter can navigate the document because that is the capability it implements.

The rules need to describe those cases. Otherwise, an agent following them literally will invent wrappers, duplicate types, or move behavior into a less appropriate owner to satisfy a ban.

For a genuine exception, I want a concrete path, a reason, and compensating evidence. A broad suppression across a whole feature makes the boundary difficult to trust. A growing exception list is also a reason to question the policy, not just the code.

Refactoring must preserve the behavior around the code

An extraction can look mechanical while changing when requests run, which account owns a cache entry, or whether a refetch overwrites an unsaved draft.

Before delegating that extraction, I want the existing behavior characterized. Query keys and identity scoping stay stable. Route prefetching and prerequisite gates remain in place. Polling, retries, form validation, initialization, and reset behavior keep their existing contracts. Save and navigation ordering remain observable.

Moving a subscription to the component that reads it is a useful ownership improvement only if I preserve the loading behavior around it. Accidentally introducing a request waterfall is a behavior change, even when every file now has the right name.

If the agent discovers a bug during extraction, it should name it separately. Combining an architectural move with an unrequested behavior correction makes both harder to review.

Adopt it on one feature first

I would start with the single-zone workout editor, not a repository-wide reorganization or an interval-training engine. Establish its responsibilities, build the missing checks with the agent, and use their feedback while implementing it. Render it with the real calculation and strict fake save service, challenge the unit conversion with a mutation, and verify that saving and reloading preserves the workout’s inputs and estimate. Add the checks that can protect those boundaries in the project’s ordinary quality command.

Then try a different kind of task: a read-only badge, an existing form section, or a timer-based recovery action. These reveal whether the guidance handles variation or merely teaches the agent to reproduce one example.

A development host with controlled response states can become worthwhile when repeated flow or visual checks need it. I would not make building that infrastructure a prerequisite for the first small feature.

For existing code, I prefer explicit incremental coverage. Protect the migrated slices and grow the policy as features move. Claiming that a few lint rules enforce an architecture across an unclassified application would give me confidence I have not earned.

What I still need to measure

I have not run a controlled evaluation showing that this skill improves agent compliance or development speed. The document structure and example interactions are a proposal for making that evaluation possible.

I would compare similar tasks with and without the guidance, holding the model and settings steady. I would look at accepted boundary violations, behavior preserved, meaningful defects caught, human interventions, and the total effort spent implementing and reviewing. I would also track the maintenance cost of the harness and rules. Fewer generated lines or a faster first response would not settle the question.

Some of these judgments remain qualitative. Did I need to reconstruct the whole screen to understand the change? Could I explain why a test failed? Did the agent report the integration it had not exercised? Those observations matter alongside elapsed time.

What I like about this direction is that it gives delegation a concrete contract. I can describe who owns a decision, how an operation enters the feature, and what evidence should come back. What I dislike is the extra navigation and infrastructure it can introduce when applied without restraint.

That is the balance I want to keep evaluating: enough structure to make delegated work inspectable, and enough restraint that the structure continues to serve the feature.