RSS Amplifier

Deriv<ed> · Aug 18, 2026

Building an automated software development lifecycle with AI agents

0
Sign in to vote or save

Raunak Kathuria · Deriv<ed>

The pipeline is green, and the product is wrong. Here’s a failure worth more attention than it usually gets.

Imagine a requirement that says catalogue search matches on SKU or name, case-insensitive. Four scenarios, written out. Suppose that the code matches on name only, and it’s case-sensitive. There’s a test for it, and the test passes, because whoever wrote the test read the implementation rather than the requirement.

So the machine reports four things. Has a test: pass. Coverage: complete. Pipeline: green. Behaviour: wrong.

Every gate did the job it was given. The coverage check confirmed that every requirement is named by a test, which is the only thing a coverage check can confirm. Naming isn’t asserting. A test derived from the implementation agrees with the implementation, passes forever, and tells you nothing about the product. A green pipeline only proves the code agrees with the tests it was handed.

That sentence is why the rest of this architecture exists.

The ADLC (automated development life cycle) is a development loop built like a production line. One product spec lives in Git, and every change is a diff to that spec. Agents carry the work between stations. Humans stand at exactly two points and make the two decisions that carry accountability: approving the intent, and merging the pull request. Between those points, guardrails either pass the work on or send it back, and every step is checked by something that didn’t do the work.

There’s a working reference implementation at github.com/raunakkathuria/adlc. It’s Node 22, no dependencies, no lockfile, no Docker, and it ships with a finished reference run committed in artifacts/, so you can read a real end-to-end run even if you never install an agent CLI.

Every Monday in product review, something doesn’t match. The site says one thing, the app says another, and the rule that actually governs behaviour lives in a Slack thread from March. Our website is in Webflow, our designs are in Figma, and the spec is in people’s heads. We’ve been closing that gap with process for years without closing it.

Meanwhile, an engineer with an agent builds a feature in an afternoon, and then it queues. It waits for a design review, a compliance read, a QA slot, and for someone to remember the exact EU risk-warning wording. Typing stopped being the bottleneck a while ago; the wait between stations is where the weeks go.

Manufacturing settled this a century ago. Standardise the line, automate each station, put a guardrail between every pair of them, and keep people on ideas and quality control rather than nuts and bolts. People aren’t on our line either. Everything between the two gates belongs to the agent, including the review, which is precisely why the review has to come from somewhere else.

The routing question at station 01 decides how much process a change carries. A behaviour change takes the long way round, through a human gate before any code exists. A bug goes straight to a failing test.

The amber arrows are the part that matters. A finding doesn’t go into a report someone reads later; it goes back to a station. Note where a Verifier failure lands: back to the Planner, never to the Executor. If the spec was silent or wrong, more code won’t fix it.

Two gates, and only two:

Gate 1, approve the intent. A human reads and merges the spec delta. An agent never approves a spec. Merging the delta is the approval, so the record of what was agreed is the same file the build then reads.

Gate 2, ship it. A human merges the pull request on green gates. The loop opens pull requests. It never merges one.

Two-band flow diagram. Top band, before any code exists: issue, classify, then either spec delta, spec review and human Gate 1, or straight to reproduce as a failing test. Bottom band, from code to shipped: build, verify, review, verify against spec, then human Gate 2 ship. Amber arrows route findings back to build or to the planner.
One question at station 01 decides how much process a change carries. Follow the amber arrows: a Verifier failure routes back to the Planner, because a silent spec doesn't get fixed by more code.

Work arrives wherever people are: a chat message, a support ticket, a customer email, someone’s idea in a meeting, a metric that dropped. The line accepts it exactly one way, as a tracked issue copied into the repo as a file, and classification is the first station rather than a person’s job.

Five unstructured inputs on the left (chat message, support ticket, customer email, an idea in a meeting, a metric that dropped) converging on a single tracked issue committed as one file, which feeds the classify station and then stations 02 onward.
Five ways work turns up, one way in. Everything after intake reads the same file, so a run is reproducible from the commit alone.

The narrow point is deliberate. Every later station reads the same file, so a run is reproducible from the commit alone and nobody has to remember what the original request said.

Every check produces findings in the same shape, so the line routes them without a person reading a report. Four kinds of findings, four destinations, and the further down the list you go, the wider the thing being repaired.

Four-row routing diagram. A code review finding goes back to build in the same cycle and repairs the change. A Verifier finding or spec gap goes to the Planner, then Gate 1 if the spec moves, and repairs the spec. A production issue re-enters intake and repairs the product. A recurring finding goes to the prompts and the gate, and repairs the line. Axis runs from tighter loop to wider blast radius.
Four findings, four destinations. The second row is the one teams skip, and it's the row that keeps the spec honest.

Row two is the one teams skip. When a reviewer says the spec doesn't state which of two rules wins, that's the most valuable thing the run produced, and it belongs in the spec before the next person guesses.

The boundary is the whole design. Planner and Executor share business context, so the build knows why it's building. They never share a session, so a plan can't leak its assumptions into the code. The Verifier sits outside both, and reports drift in two directions, which most reviews don't: missing is a requirement the product doesn't honour, extra is behaviour that traces back to no requirement at all. Extra findings go back to the spec, because code can't abstain. Where the spec stayed silent, an implementation detail decided, and nobody chose it.

A factory keeps its quality inspector off the line supervisor’s org chart for the same reason. An agent that just spent twenty minutes convincing itself a change was right is the worst available reviewer of that change.

Planner and Executor sit inside a shared business-context boundary, iterating; the Planner writes the spec change and tasks and no code, the Executor writes code and never renegotiates the spec. Outside that boundary the Verifier shares neither context nor session, re-derives from the spec first, reports missing and extra behaviour, and never writes code. Footnote reads: separation of duties, not self-review.
Planner and Executor share business context and never a session. The Verifier shares neither, and re-derives the feature from the spec before it reads a line of code.

Here’s what the separation buys, measured. One bug, two candidate fixes:

  • Fix A moves the write below every guard.

  • Fix B adds the stock back afterwards.

Two candidate fixes for one bug both reach the deterministic verify station and return identical passing results. Both then reach an independent review running on fresh context that wrote neither fix, which approves Fix A and requests changes on Fix B. Labels read: same bug, same tests, same green; the gate cannot tell them apart, the review can.
Fix A moves the write below every guard. Fix B adds the stock back afterwards. Identical verdict from the deterministic gate; the independent reviewer approved one and asked for changes on the other.

Both fixes pass every test, with identical verdicts from the deterministic gate. Fix B makes the test pass while leaving the mechanism that produced the bug in place. The independent reviewer, running on fresh context and having written neither fix, approved A and requested changes on B, while noting honestly that there was no reproducible defect today and the objection was to the shape of the patch.

The gate is one command with no model in it. It runs in about a tenth of a second, and it’s the only thing in the loop that gets a vote on whether the work is done. That cheapness is why it can sit between every station.

It’s also not enough on its own, and the repo proves that against itself. Back to REQ-CAT-3:

Comparison panel. Left: the spec requires SKU or name, case-insensitive, with four written scenarios. Right: the code does name only, case-sensitive, and the test was written from the code. Below, four status chips: has a test, pass; coverage, complete; pipeline, green; behaviour, wrong.
The spec asks for SKU or name, case-insensitive, across four written scenarios. The code matches name only, case-sensitive, and the test was written from the code. Every indicator reads green.

The gate can only tell you that a test exists and runs, which is why one station has to read the spec as the authority and nothing else. Without it, every green tick in the run is confirming a claim the code made about itself.

What the product should do, what it does, how each step runs, and the standards all three answer to.

  • spec/ — what it should do. Requirement IDs, with changes/ holding deltas awaiting a human at Gate 1.

  • app/ and test/ — what it does. Every test names its requirement, and that string is what the gate reads.

  • prompts/ — how each step runs. One file per station, plain markdown, no tool lock-in.

  • AGENTS.md — the only instruction file, holding six rules the team actually argues about. CLAUDE.md, GEMINI.md, .cursor/rules and copilot-instructions are three-line pointers to it, so there’s nothing to keep in sync.

Three boxes (spec, app and test, prompts) all pointing down to AGENTS.md, described as the only instruction file holding six rules the team argues about. Below it, four pointer files: CLAUDE.md, GEMINI.md, .cursor/rules and copilot-instructions, labelled three lines each, pointers not copies.
Three directories answering to one instruction file. The pointer files are three lines each, so there's nothing to keep in sync.

Nothing in prompts/ knows anything about the repo it isn’t reading at run time. No paths are baked into the reasoning. That’s why the same eight files work on a codebase they were never written for, with whichever CLI happens to be installed.

Real here. The spec as source of truth. The deterministic gate. One prompt per station with fresh context. Both human gates. Committed evidence of runs that actually happened: terminal output, diffs, and failure messages, none of it written by hand.

Left out. A browser test layer, a database, a design system the generated UI is forced onto, business rules held outside the model’s reach, and the CI wiring to run all of this unattended. Left out so the whole thing stays readable in an afternoon.

The honest limit. None of this makes an agent reliable. It makes an unreliable agent’s output checkable, and it puts the two decisions that carry accountability in front of a person who can be held to them.

The claim isn’t that a machine works the night shift. It’s that the loop runs without anyone steering it, on the same prompt files, in any repo, at any time, and that when it’s wrong, the wrongness lands somewhere a person can see: a test that fails, a review that objects, a gate that stays red, or a run that stops and says what it tried.

Join Deriv

Two parts. In the first, you watch one feature go the whole way round. In the second, you run the short path yourself. Budget about 35 minutes, and you can do all of it without an agent CLI.

Read this before you start. Every step has a finished reference run committed in artifacts/. If your CLI won’t authenticate, is rate-limited, or you never installed one, you lose nothing. The reading and judging is the part that teaches; the live run is the part that convinces.

Node 22 or newer is the only requirement. Nothing to install: no dependencies, no lockfile, no Docker.

00 · Get it and check ityou run

git clone https://github.com/raunakkathuria/adlc
cd adlc
./check.sh

Three green ticks: Node, the gate, and whichever CLI you have. If the CLI line says none found, that’s fine; carry on.

# optional, see the product itself at localhost:3000
npm start

Product wants shoppers to be able to narrow the catalogue by price. It arrives as issue #4: three paragraphs, no ticket template, the way real requests turn up. The first station takes it in, copied into the repo as issues/003-filter-catalog-by-price.md, so every station after this reads the same bytes and none of it needs a token.

01 · Classify itwatch

One question decides how much process this change carries: would a rebuild from the spec alone lose it?

./run.sh prompts/triage.md \
    issues/003-filter-catalog-by-price.md
  • The one station whose output is data, not prose. To pipe it: ./run.sh --print … | claude -p | jq

  • It comes back feat, a behaviour change, so the spec moves before any code does. It writes down its reason, so a human can disagree in one line.

  • That second argument is the target: which issue, delta or spec this run is about. Every station takes one. Leave it off and each prompt falls back to its own stated default.

02 · Change the spec, not the coderead the committed one

# already in the repo as evidence, open it, don't re-run it
spec/changes/filter-catalog-by-price/tasks.md
  • delta.md won’t overwrite committed work; it writes a fresh slug and says why. Correct behaviour, but two delta directories mid-demo is noise.

  • Open the file. It worked out that the coverage gate only reads the top level of spec/, spotted the other defect in this repo, and wrote: “Do not fix search inside this change.”

03 · Two reviewers read it, before a human doeswatch

./run.sh prompts/spec-review.md \
    spec/changes/filter-catalog-by-price/

A product lens and an architect lens, neither of which wrote the delta. Advisory only.

04 · Gate 1, your turnyou decide

A second delta arrived the same morning, artifacts/gate-1/delta-b/, which lets a customer cancel an order. It reads reasonably. Would you merge it? Four minutes. There’s no code yet, so you aren’t reviewing an implementation; you’re deciding whether the intent is agreed and testable.

Two questions carry most of the weight. Does every requirement say what the product does, or does one say how to build it? And is every path covered, including the ones where the answer is no?

Then open delta-b/review.md and compare it to your own list. Judge the review too: anything it missed is its own finding.

05 · Build italready done

Delta A gets merged. Merging is the approval, so the build reads the same file you just signed off.

# already done, don't run this in the room
./run.sh prompts/build.md spec/changes/filter-catalog-by-price/
  • This is the main development work of Part 1, and the real run took about 50 minutes, the longest step in the loop by a wide margin. Keep the session clock in mind: show the result, never the spinner.

  • Switch to the finished branch instead:

git checkout feat/filter-by-price
git diff main
  • That branch is pull request #1. Read the run report: it stayed inside the change, found a hole in the gate it was measured by, argued with the delta it was given, and named four behaviours it made true by accident.

# only if you did run the build, it deletes the delta directory, which is correct
git checkout -- app/ test/ spec/

06 · The Verifier signs it offwatch

A third role that wrote none of it and shares no session with the two that did. It re-derives the feature from the spec before reading any code.

./run.sh prompts/verify.md spec/catalog.md
  • It reports drift both ways: missing (required, not done) and extra (done, no requirement asks for it). On pass the work goes to Gate 2; on fail it goes back to the Planner, not the Executor.

  • Expect it to flag the search defect this build deliberately left alone. That’s the point: per-diff review passed it, and the independent check didn’t.

07 · Gate 2, still a humana person ships it

The pull request is open, the gates are green, and nothing merges it but a person. The loop opens pull requests. It never merges one.

Now the short path. Same loop, much less process, because this is a bug rather than a behaviour change.

08 · The pipeline is green, and the product is wrongyou run

npm run verify

Every test passes. Every requirement has a test. Nothing is red.

Now do the Verifier’s job by hand. Open spec/catalog.md beside app/server.mjs, read REQ-CAT-3 scenario by scenario, and ask of each one: does the code actually do this? Then check the same scenarios against test/catalog.test.js.

# three minutes of reading, then hand it to the real thing,
# the same station you watched in step 06
./run.sh prompts/verify.md spec/catalog.md

The lesson: the coverage check confirms every requirement is named by a test. Naming isn’t asserting.

09 · Judge a test before you write oneyou decide

Read the report first, written the way support actually writes them: issues/001-rejected-order-eats-stock.md. Then open artifacts/expected/02-reproduce.diff and answer one question.

On today’s build, does this test fail?

It matters more than it looks. A reproduction asserts the behaviour that should happen, so it fails now and passes once the bug is fixed. Get the polarity backwards, and you have a test that passes today, hides the bug, and reports success.

Then count how many tests it wrote, and work out why it wrote more than one.

10 · Run the loopyou run

./run.sh prompts/reproduce.md issues/001-rejected-order-eats-stock.md
# ^ writes a failing test
npm test                    # watch it fail, read the failure
./run.sh prompts/fix.md
npm run verify              # green

Your agent won’t produce the reference diff, and that’s fine. The criterion is verify going from red to green, not a particular patch.

11 · Look at what it actually didyou run

git diff app/server.mjs
  • Did it stop the bug happening, or clean up after it? Both kinds of fix pass every test.

  • Then read artifacts/expected/04-review.md and 05-review-of-the-naive-fix.md: two reviews of two different fixes for the same bug. One approves. One asks for changes. The deterministic gate couldn’t separate them.

Start again from clean

git checkout main && git checkout -- app/ test/ spec/ && npm run verify

Green, with both defects live. That’s the shipping state. spec/ is in that list on purpose: the build deletes a delta directory, and restoring only app/ and test/ leaves Part 1 unrunnable.

Your CLI isn’t covered, or isn’t working

The prompts are plain markdown. Print one and paste it into whatever you use.

./run.sh --print prompts/fix.md

Nothing in the loop depends on a particular vendor. The parts that matter are the spec, the gate, and the independence.

Is the ADLC the same as spec-driven development? Spec-driven development usually means writing a specification before code. The ADLC adds three things to that: the spec is a single versioned artefact in git that every station reads, changes to it are diffs approved by a human before code exists, and one station re-derives the feature from the spec without reading the code.

Why does a failed verification go back to the planner instead of the developer? Because a verification failure usually means the spec was silent or wrong. Sending it to whoever wrote the code produces a patch that satisfies the check without changing what the product promises.

Doesn’t test coverage catch this already? Coverage confirms a requirement is named by a test. If the test was written from the implementation, it agrees with the implementation and passes permanently. The independent check compares against the spec instead.

Can an agent approve a spec change or merge a pull request? No. Those are the two human gates. The loop opens pull requests and never merges one.

Does this need a specific model or CLI? No. Prompts are plain markdown with three-line pointer files for Claude, Gemini, Cursor, and Copilot. If your CLI won’t run, print the prompt and paste it.

What does it cost to try? Node 22 and about 35 minutes. No dependencies, no lockfile, no Docker, and a full reference run is committed in the repo if you’d rather read than run.

This is Part 2 of a series on AI-native product engineering. Part 1 looks at why the living product specification becomes the centre of the development system. This article goes under the hood of the automated development lifecycle that turns approved intent into verified software.

No posts

Read the original on derivai.substack.com

Comments

Nothing yet. Say the first thing.

    Sign in to join the conversation.