How we codified development, testing, reviews and deployments, and used each correction to improve the way the next change was built.
We built the AppHelix website with coding agents working through Claude Code and Codex, directed by one human. The agents wrote the custom application code, tests, development tools and release automation. They also wrote much of the machinery that reviews their work.
The human set the requirements, chose the design direction, challenged results and made operational decisions. As the work progressed, those decisions became repository instructions, skills, hooks and executable checks. A correction could improve the current page and change what a future agent would be expected to do.
That feedback loop became part of the engineering process. We encountered incomplete instructions, inadequate tests, misleading validation output and review procedures that needed better scope. We used the agents to investigate those weaknesses and improve the process itself.
The website gave this work real consequences. It has an editorial workspace, recruitment and inquiry forms, private documents, external integrations and separate release environments. Security, performance, accessibility and consistent design had to survive changes across pages and sessions. We required explicit constraints, reusable implementation, independent challenge, controlled releases and evidence of the result.
In Software Design Done Right: The Power of Implementation Blueprints, we described putting engineering intent into a form coding agents can use. This account follows how we developed that approach on our own website, including the times the process failed to give us the evidence we needed.

Codifying development
Claude Code and Codex provide the coding harnesses: the environment through which a model reads the repository, changes files, runs commands and uses other tools. A session can investigate an existing implementation, develop a change and inspect its result. It can also delegate a bounded question to another agent.
The human's first job is to make the assignment specific enough to challenge. A request to improve a page still leaves decisions about layout, shared components, accessibility, mobile behaviour and the scope of testing. We made more of those decisions explicit as the application grew.
Give the agent an existing system to work within
Our development instructions require agents to build a reusable component first whenever the work calls for one, then continue the page task. That changes where development begins. Before adding page-specific markup, the agent must inspect the existing components and decide whether the behaviour belongs in a shared source.
Banners, forms, cards, article layouts and navigation recur across the site. An agent can make one page look right by introducing a local variation. Later work then has to discover which versions are intentional. We put the reuse decision before implementation and made consistency part of review.
The same approach applies to design. Shared tokens describe the palette, type scale, spacing and breakpoints. Components own recurring structure. Repository instructions tell the agent where those decisions live; checks look for selected violations. The agent still has room to design for a page's particular content, while working within the site's established rules.
We used different mechanisms for different kinds of knowledge. AGENTS.md and CLAUDE.md carry conventions and constraints that apply across tasks. A skill describes a recurring operation: how to start the local stack, create an article, review a change or prepare a deployment. Hooks invoke selected checks at events the harness supports. Tests and scripts establish specific behaviour by executing it.
A skill can contain the sequence, inputs, evidence and recovery steps for an operation. The local startup skill, for example, directs the agent to discover the existing database and preserve its data, build the selected checkout, verify the running image and report the result. A healthy older website does not establish that the latest source was built successfully.
The lasting knowledge lives in the repository and its configured tools. A later session can read the same decisions and run the same checks without relying on the conversation in which they were first made.
Check what the harness actually receives
We discovered that even this setup needed verification.
An audit of the two coding harnesses found that the Claude and Codex instruction files matched byte for byte. But the file was 37,781 bytes long, beyond Codex's then-default 32,768-byte limit. The supplied instructions stopped partway through the Lighthouse guidance. Maintaining identical files had left the agents with different effective context.
We raised the configured limit and checked the actual prompt diagnostic for the final sections. A setup checker now detects oversized instructions and drift between the mirrored files and skill directories.
The audit also found a globally installed startup skill that required local OAuth and referenced a retired editor URL. It conflicted with the repository's current procedure. We disabled that particular obsolete installation and verified that it no longer appeared in fresh skill discovery. The evidence established conflicting guidance; it did not establish that an agent had followed every obsolete step.
Automatic checks differed too. Claude had edit and commit hooks; Codex lacked the corresponding configuration. We connected Codex to the shared checks, then independently reviewed the adapter. That review found that the normalized command payload omitted the command's working directory. A guard could inspect one checkout while the command operated in another. We moved the guard into the command's execution context and added regression cases.
Hook discovery, activation and correct execution needed separate checks. The audit recorded that the new Codex definitions were discovered but still awaiting user trust. A configuration file in Git was not evidence that every local or cloud session enforced it.
For our use of multiple harnesses, the practical work included checking the instructions delivered to the agent, the skills it could discover and the hooks active in that particular environment.
Codifying testing
We used the agents to write tests as they developed the application. We also had to examine whether those tests could establish the property we cared about.
During the CSS migration, validation, 609 unit tests and 55 UI tests passed. Computed-style comparisons nevertheless differed in 555 of 755 route, width and theme combinations. Those were changed computed styles, not a count of visibly broken pages. They showed that passing the existing suites did not establish that the migration had preserved the rendering.
A smaller comparison helped us investigate. Keeping the relevant rules in one layer preserved the selected cases apart from an intended screen-reader correction. Splitting them into ordered sublayers changed 26 of the same 27 comparisons. The new structure had changed which CSS declarations won.
We corrected the layer model and retained tests and guidance for it. The agent's assignment also needed an observable rendering requirement: a structural rewrite should preserve the intended appearance at the affected widths and themes. Testing selectors or component output alone could not settle that requirement.
This led to more explicit acceptance evidence. For a shared form, the agent must consider validation, error states, keyboard operation and what happens to the submitted data. For a visual change, it must inspect the rendered page. For a performance-sensitive dependency change, it needs measurements of the resulting build. The relevant failure determines the test.
Set a zero-warning baseline
Our validation command, npm run validate, runs seven checks: ESLint, strict TypeScript checking, CSS linting and formatting, design-token checks, search metadata checks and the release contract. ESLint and Stylelint run with --max-warnings 0. A warning is enough to fail validation.
ESLint uses type-aware rules and checks that switches cover the possible values of the types being handled. Its inline configuration is disabled, so an eslint-disable comment cannot switch off a rule for an agent's local change. The repository instructions also prohibit weakening rules or adding suppressions to get a passing result. That instruction governs changes to the checks themselves; it is separate from what the linter enforces.
The CSS rules encode decisions about how the site is built. Selector specificity is capped at 0,4,2, cascade layers must come from the declared set, and !important is restricted to the accessibility layer and print rules. Literal colours belong in tokens or documented exceptions, including brand artwork. These checks give an agent concrete failures to resolve before asking a reviewer to assess the design. The exceptions stay in the shared configuration, where they can be inspected and reviewed.
Read the result of the command
A simpler mistake involved validation itself. Validation had been failing because a filtered log hid a Prettier warning. The output someone read was incomplete evidence of the command's result.
We fixed the formatting issue and made the exit status part of the definition of done. The commit gate runs validation and rejects recognized commits when it fails. The same batch added hooks and changed test scope at the human operator's direction; the record does not establish that the hidden warning alone caused that whole system.
Test the checks the agents write
When an agent implements a new guard, the guard becomes another piece of code to review.
Our rendered-page checks have passing and failing fixtures. A typography check must reject an element with the wrong computed font. An overlap check needs a page where text is obscured. A forced-colour check needs a mark that disappears under that rendering mode. The tests help establish that a rule detects its intended failure, rather than accepting only the examples used to write it.
The same principle applies to harness hooks. Their tests include changed working directories, multiple edited files, failed validation and supported commit forms. We check the mechanism through which a future agent will be guided or stopped.
Some properties still require judgement. We keep that work visible in the review procedure instead of treating a larger test count as completion.
Codifying reviews across several dimensions
The review process grew through explicit decisions and findings.
We first required a UX review before committing changes visitors would see. We codified an automated pass and a separate judgement pass. We then expanded the requirement to adversarial review of every substantive change, including server code, tooling and operations. The custom-review skill incorporated the UX review when relevant, so the same reviewer could examine both the code and the rendered result.
This was more involved than asking an agent to check its own work. The implementation session prepares the change, its purpose, constraints and evidence. A fresh reviewer receives that material without the working conversation. It reads the source and challenges the claims independently.
The review examines several dimensions:
| Concern | What the agent must investigate | Evidence used in our workflow |
|---|---|---|
| Functional correctness | Does the change work on success, failure, retry and relevant edge cases? | Focused unit, integration and browser tests, plus review of callers and data flow |
| Accessibility | Can people operate and understand the affected interface across supported states? | axe, target sizes, heading structure, forced colours, and keyboard/focus inspection where relevant |
| Performance | What does the selected build cost the pages and devices affected? | Scoped, repeated Lighthouse runs, budgets, metrics and investigation of regressions |
| Security and privacy | Who can act, what input is trusted, and where can private information travel? | Source review, authorization and negative tests, dependency/artifact checks, credential and logging review |
| Design consistency | Does the result follow the site's visual decisions across widths and themes? | Token and rendered-style checks, screenshots and independent visual judgement |
| Reuse and maintainability | Does the change belong in an existing shared component, rule or procedure? | Review of ownership and consumers, shared-source fixes and representative route sweeps |
| Operational behaviour | Can we identify what was built and deployed, preserve data and report partial failure? | Build/release identities, workflow tests, health checks and retained release evidence |
| Content and discovery | Is the copy supported, linked correctly and reflected in the relevant discovery files? | Editorial/source review, link checks and the article/page maintenance procedures |
The agent chooses the evidence appropriate to the change and explains the scope. A text correction and a shared authentication change need different work. A screenshot cannot establish authorization; a unit test cannot decide whether a diagram communicates clearly.
Turn a review finding into a repeatable check
Reviewers initially caught several visual defects by looking at the pages. We expanded the automated review to catch classes of those defects in subsequent work.
The added checks inspect computed typography, heading structure, text crossed by positioned elements, duplicate IDs, missing anchor targets and type changes across breakpoints. They also examine marks that may disappear in forced-colour rendering. A decorative connector can use an approved colour yet become indistinguishable from the canvas in that mode.
The agent implemented these checks in the shared rendered-checks module and updated the UX skill and reviewer brief. Later sessions invoking that workflow received the additional checks without needing the original review conversation.
We kept judgement items separate. A heading ending with a single word, a long line or an isolated card may warrant a design change, but the context matters. The tooling records such items for the reviewer instead of mechanically failing every instance.
The same pattern continued. Restoring the section bands on About also produced shared guidance and rendered checks for band alternation. Section-spacing checks subsequently verified registered padding against shared tokens and looked for competing wrapper spacing. A correction to one page became a way to detect related drift elsewhere.
Reuse belongs in this review too. When a defect comes from a shared component or convention, the instructions require fixing that source and checking the other affected uses. The sweep samples page templates and accepts additional content variants. An article with a special diagram can need inspection even when another article already represents the same template.
Give Lighthouse a precise job
Lighthouse became part of this process as a measurement tool with a defined scope, environment and completion condition.
The CSS work exposed a sequencing mistake. We delayed Lighthouse until final verification, after a framework upgrade and several other phases. Mobile performance measured 91–94 against the earlier baseline's 94–98, even though the pages shipped less CSS. By then, five subsequent phases made the cause harder to isolate.
Controlled experiments attributed the main cost to the framework upgrade. The human chose to retain the upgrade and address the performance work separately. The report records the lesson: measure after a consequential framework change, while its effect is easier to distinguish. That lesson required a decision about when to measure; we did not acquire an automatic check that schedules every useful benchmark.
We also expanded what a benchmark covered. The Lighthouse runner gained a separate axe pass across the selected routes, in mobile and desktop viewports and both themes. That included rules omitted from Lighthouse's accessibility score. Violations fail the budget, and an axe check that cannot complete leaves the benchmark incomplete.
Our current procedure retains three Lighthouse repetitions and reports median scores and underlying metrics. Mobile and desktop use separate performance budgets. The report identifies the source revision, runtime image, origin, routes, tool versions and settings. A later agent has enough context to decide whether two runs are comparable.
Measurements run sequentially on a machine because competing audits can distort scores. Independent lint, test and review work can run concurrently. This is a specific constraint on performance measurement, not a reason to serialize the whole development process.
An automated accessibility pass covers the rules and states exercised. It does not settle every question of usability or accessibility. Likewise, a performance score is evidence about the measured build and conditions. The review keeps those limits attached to the result.
Ask the reviewer to challenge the evidence
The fresh reviewer can also examine whether a check tells the truth.
When we added automatic content publication, a reviewer found that two commits with identical article inputs could leave the application reporting an old source revision. The rendered article looked correct, but a check waiting for the expected commit could keep waiting. We corrected the metadata handling and retained the publication check in the article workflow.
The reviewer inspected the mechanism claiming completion, including a case outside the obvious successful edit. The feature's working appearance did not answer that question. We retained a procedure that requires both the applied revision and inspection of the published page.
Security review requires the same specificity. During work on release tooling, fresh reviewers found an expiring registry credential cached indefinitely and short credential values omitted from redaction. Agents corrected the implementation and added regression fixtures. The review examined what the code could expose and how it behaved as credentials changed, alongside whether the release worked.
Review findings have a disposition: fix before completion, fix or explain why it waits, or retain as a note. The implementing agent verifies a finding before changing code. A reviewer can be mistaken, and a review trailer records an outcome without proving that the underlying work was done.
Keep the review proportionate
We also changed the process when it demanded too much work for the change at hand.
The human explicitly required agents to choose routes based on what a change touched. The UX tool reports the potential scope, but the agent names the routes, states and widths it will examine. The tool refuses to run an ordinary review without that selection. Full-site measurement is a separate decision.
A request for lighter review of surgical changes led to the custom-review-lite skill. It retains a fresh adversarial reviewer with a narrower brief and short report. Shared behaviour, security, deployment and scripts that enforce rules remain outside its scope.
Codifying deployments
The release skills distinguish local startup, beta delivery and production delivery. The current ordinary application workflow builds and tests locally, then uses beta for acceptance. Production requires an explicit human release decision. A successful local startup or a request to prepare a deployment does not by itself authorize every later operation.
The agent first prepares something concrete to decide on: the selected source, included changes, target environment, validation and review results, and any configuration changes. It must preserve existing data and unrelated work. It then carries out the authorized release through the established tooling.
We codified the mechanical steps too. The workflow selects and verifies a specific image digest, checks its source and target, records the deployment and backup state, and verifies the running result. The agent uses these tested commands through the release skill instead of reconstructing the operation from remembered shell commands.
Source identity matters throughout. The code controlling a release, the code inside its image and the current editorial content can have different revisions. The procedure tells the agent which identity each observation establishes. A successful push alone cannot show that the intended application is running.
Failure reporting also needs more detail than a single green status. One release successfully replaced the application while image housekeeping failed. The record kept those outcomes separate; subsequent work corrected the cleanup code. Completion reports must preserve such distinctions so the next session has an accurate starting point.
Operational permission remains with the human. Skills specify the authorized path and the points that require a decision. Credential scope and runtime permissions constrain what the software can do. Harness hooks add checks for supported actions, with documented activation and coverage limits.
For a new session, the skill now carries the release sequence, evidence requirements and recovery considerations. The agent can execute a substantial operation while the human decides its scope and evaluates unresolved risk.
Improving the system that does the work
The setup improves when feedback becomes a reviewed change to its instructions and tools.

Sometimes the feedback comes from the human: a page lacks consistency, a review runs too broadly, or a deployment request is ambiguous. Sometimes an independent agent finds a defect. Sometimes a test or benchmark supplies evidence that contradicts the implementation session's expectation.
The agents can then make two changes. They correct the application or immediate task, and they update the appropriate instruction, skill, hook or check when the lesson is reusable. That second change receives review and, where executable, tests of its own.
A later agent running the UX workflow gets the forced-colour check built from an earlier finding. The human does not have to remember to request that particular inspection for each page. Its passing and failing fixtures also give the next agent a way to check changes to the guard itself.
A lesson does not always warrant another hook or another paragraph in the root instructions. Some need human judgement; others belong in a task-specific skill. Our instruction-limit problem was itself a consequence of accumulating guidance. We have to maintain the operating method as carefully as the application code.
The Shield build account describes another use of bounded assignments and independent review. On this website, we applied that discipline across ongoing development, content, design and operations with one human directing the agents.
To apply this approach in your own project, start with one bounded change. Adapt the following brief to your codebase, tools and release process:
Outcome
Describe the intended outcome and the existing behaviour to preserve.
Development
Inspect the relevant implementation and repository guidance.
Identify the shared component or rule that should own the change.
Name assumptions that need a human decision before implementation.
Evidence
Choose checks for correctness, accessibility, performance, security,
consistency and reuse according to what this change affects.
Name the affected interfaces, states and failure cases they will cover.
Review
Give a fresh reviewer the requirement, diff and evidence.
Verify findings, fix them or record the decision that remains open.
Delivery and learning
Follow the authorized release procedure and identify what is running.
If a finding exposes a reusable gap, propose and review the change
to the relevant skill, instruction, hook or test.
Use that brief on an actual feature. When a review finds a repeatable failure, add a failing example to the relevant check, correct the implementation, and confirm that the check distinguishes the two. The next session should be able to run it without recovering today's conversation.



