Skip to content

Practices

Ways of working that mostly existed long before AI. Only one was shaped for agentic development, and even that one adapts an older engineering idea; the rest were invented for other reasons entirely. That is the interesting part: every one means something different when the author is an agent biased toward agreeing with you.

A practice is not a product. It is a way of working — a procedure, a pattern, a technique — that covers a discipline and survives whatever tool you use to apply it.

MemoryMemoryContextContextStandardsStandardsCapabilityCapabilityMethodMethodControlControlSpec-driven development01SDDTest-driven development02TDDReceipt-driven development03RDDArchitecture decision records04ADRDomain-driven design05DDDHexagonal architecture06Hexagonalarchitecture
CoversAlso helps with
01

Spec-driven development

SDD

  • Covers
  • Method
  • Standards
  • Control

What is the work verified against?

Write the contract — what has to happen, and how it will be checked — before asking for the code, then verify against that contract rather than against your memory of what you wanted.

Where it comes from

It began as large-team formality: put the requirement in writing before implementing it, so two people could not read the same sentence two different ways.

What changes when the author is an agent

With an agent the spec stops being paperwork and becomes the primary artefact carrying the intent of that change from one session to the next — records and stored decisions carry the rest. The prompt goes out with the context window. The spec stays, and it is what you can argue against later.

At the moment you ask an agent for something, you know what you meant. The problem arrives two weeks later, when you look at the code and cannot separate "the agent did something else" from "I asked for that". With nothing written beforehand there is no way to tell: your memory of the request has been contaminated by the result.

A spec fixes that by being prior and independent. It does not describe the implementation — that is the design — but the observable behaviour: what has to happen, with which inputs, and how it is checked. Written that way, anyone can verify the result without having been in the conversation. Including you, in two weeks.

There is a side effect worth more than the original one: if you cannot write down how you will check that it is right, you do not yet know what you are asking for. Half the tasks an agent "got wrong" were badly formed tasks, and specifying them makes that fail before a single token is spent.

The phased cycle — explore, propose, specify, design, tasks, apply, verify, archive — exists for a mechanical reason, not a ceremonial one: each phase needs different context and has a different definition of done. Collapsing them into one request is asking the same person to design, build and inspect at once. They will approve their own work.

Watch the other extreme, though. A three-page spec for a two-line change is not rigour, it is theatre. The ceremony has a fixed cost and it should only be paid when the change earns it.

The idea that outlives the tools

If you cannot write down how you will check that it is right, you do not yet know what you are asking for.

02

Test-driven development

TDD

  • Covers
  • Control
  • Method

Can the test fail?

Write the test before the code, watch it fail, and only then implement until it passes.

Where it comes from

It spread as a design tool: writing the test first forces you to use your own API before it exists, so bad interfaces hurt immediately instead of in six months.

What changes when the author is an agent

Here is an inversion almost nobody says out loud. In a person's hands, TDD is a design tool. With an agent it is a control mechanism: it is the only thing stopping the test from being written to fit the code that already exists.

The reason is mechanical and has nothing to do with moral discipline. Ask for the tests after the code is written and the agent writes tests that pass. That is literally what you asked for, and it will do it well. The result is a green suite that proved nothing, because no test in it ever had the opportunity to fail.

Which is why the step people skip — seeing the test red — is not a formality. For behaviour that does not exist yet it is the entire mechanism: red is the proof that the test can detect the absence of the thing it tests. Green on the first run tells you the test runs, which is a different claim and a less useful one. The rule is narrower than the slogan, though. A characterisation test fencing behaviour that already ships is supposed to pass immediately — it is not proving a new behaviour, it is pinning down an old one.

With an agent there is also a failure mode of its own: it mocks the thing under test. If the test for the billing function mocks the billing function, it passes forever and covers nothing. That sounds like a joke until you see it in a pull request. The defence is reading what the test mocks, not counting how many tests there are.

And there is a second-order benefit that matters more in a team than the first: a test written beforehand is an executable specification. It cannot drift from the code — the day the two disagree, the build says so. It can still drift from what you actually wanted, which is why the spec and the record exist and the test does not replace them.

The idea that outlives the tools

For new behaviour, a test you have never watched fail is not a test: it is an opinion written in green.

03

Receipt-driven development

RDD

  • Covers
  • Control
  • Method
  • Standards

How do you prove this was already reviewed?

Have review produce a receipt bound to the exact content reviewed, and have every exit point — commit, push, pull request, release — validate that receipt instead of reviewing again.

Where it comes from

It comes from the same idea as artefact provenance in the software supply chain: a verifiable claim bound to exact content. If the content changes, the claim stops holding. gentle-ai brings that to the review cycle of a single change.

What changes when the author is an agent

With an agent, asking for a review is nearly free and trusting one is expensive. Without a receipt only two endings remain, and both are bad: you review again at every exit point — unbounded cost — or nobody reviews — unbounded risk. The receipt is what turns review into a dated fact rather than a feeling.

Start with the real problem, which is not the quality of the review but its repetition. You review a change. Then comes the commit, the push, the pull request, the release. At each of those points somebody — or some agent — asks again: "has this been reviewed?" With no verifiable answer, the only honest move is to review it again. And reviewing again with an agent costs money and time, every time.

The receipt cuts that. Review happens once, against an immutable target: the exact tree, the exact paths, the exact modes. What remains is a receipt bound to that content. The later points do not review: they validate. And if the content changed by so much as a byte, the receipt does not apply — which is precisely what you want to happen.

It also settles the problem of review never ending. An agent asked to "review this" keeps producing one more thing to say for as long as you keep asking; with no declared limit, review stops when you get tired, which is not a criterion. Here the correction budget is fixed when review opens, scaled to the size of the change, and is not renegotiated afterwards. What shows up later is new work, not an extension.

The other half is proportionality. A documentation change does not deserve the same scrutiny as one touching permissions or payments. The risk of the change decides how much analysis runs: none for the trivial, one focused lens for the ordinary, the full sweep for the dangerous. Choosing that by hand, change after change, is exactly the kind of decision people stop making by week three.

One warning, because this pattern degrades fast: a receipt that cannot be invalidated is a rubber stamp. All of its value lies in being fragile to a change of content. If your process keeps it valid "because it is basically the same", you no longer have control — you have paperwork.

The idea that outlives the tools

A review without a receipt has to be repeated; a receipt that cannot be invalidated is not a review.

04

Architecture decision records

ADR

  • Covers
  • Memory
  • Standards

Why is it built this way, and who decided that?

Write down the decisions the project has to live with — the ones that cost an argument, and the ones nobody argued about because they did not look like a decision at the time — in a short file with the context, the options, the one you took and what it costs you, versioned with the code.

Where it comes from

Michael Nygard proposed it in 2011: one short, numbered file per decision, kept in the repository rather than in a wiki. The point was that the why should age alongside the code it explains.

What changes when the author is an agent

An agent that cannot read why you chose X will re-litigate it every session, or will quietly write the alternative you already rejected. From the code, a decision and an accident look identical: the only thing that separates them is a piece of text somebody had to write.

Code tells you what was decided. It does not tell you what else was on the table, why that was dropped, or what you agreed to pay in exchange. That part was never in the repository: it was in a conversation, in a Slack thread, or in the head of somebody who now works somewhere else.

With an agent the problem changes scale. A human colleague who does not understand a decision asks. The agent does not ask: it completes. It sees a service that does not use the project's ORM and "fixes" it; it sees two modules not sharing a helper and unifies them. Every one of those corrections is reasonable if you do not know what the record knew, and none of them gets flagged in review, because the diff looks fine.

What makes a record useful is not the decision you took — that one is in the code — but the list of the ones you did not. A record with no rejected alternatives is a long comment. With them it is the only thing that can close an argument without having it again, and the only format you can hand an agent so it does not reopen it.

The cost is low, and that is worth saying: fifteen lines written the day the argument ends. The trap is not the effort, it is writing it while you still know why. A week later you have already rewritten the memory around how it turned out.

And there is a convention that holds the whole practice up, and that people break immediately: an accepted record is not rewritten. While it is still proposed it can change; once accepted, you write a new one that supersedes it and the old one is marked superseded rather than removed. Edit it to say what is true today and you lose exactly what you came for — the thread between what was decided and what shipped.

The idea that outlives the tools

A decision nobody wrote down is not a decision: it is a coincidence somebody will undo.

05

Domain-driven design

DDD

  • Covers
  • Context
  • Standards

Is it building what you asked for, or the thing next to it?

Use the business's own words in the code, one meaning per word, and put an explicit border where that meaning changes.

Where it comes from

Eric Evans wrote it in 2003 against a translation problem: the domain expert said "booking", the code said Booking, BookingDTO and ReservationEntity, and nobody could claim those were the same thing.

What changes when the author is an agent

The agent uses your vocabulary with total confidence and no understanding. If "customer" means two things in your company depending on the module, it picks one — the internet's — and builds, very well, the wrong thing next door. Language stopped being documentation hygiene: it is the input that decides whether the output is any use.

The failure mode here is not code that does not work. It is code that works and was not what was needed. It compiles, the tests pass, review approves it, and three weeks later somebody from the business looks at the screen and says that is not a discount. Nobody caught it earlier because nothing was wrong: something was different.

Of everything in domain-driven design, two pieces carry almost all the weight once you are working with agents. The first is one rule: one word, one meaning, and the same word in the conversation, in the spec, in the code and in the tests. That sounds small until you see what happens without it. At every point where you have to translate, somebody translates; and when the translator is a model, it takes the translation from the average of the internet rather than from your business.

The second is accepting that the same word means different things in different places, and that this is fine. A "shipment" in billing is a line with a price; in logistics it is a box with a weight. The answer is not to pick one: it is to mark the border where the meaning changes and make it explicit. For an agent that border is also a reading limit — it says how far it has to understand in order to be right, which is the same question hexagonal asks from the other side.

Now the honest part, because domain-driven design has a reputation for being expensive and earned it. What I just described — the vocabulary and the borders — is cheap and pays from day one. The tactical patterns — aggregates, value objects, repositories, domain events — are expensive and most codebases do not need them. They are two different things that arrived in the same book.

And be careful asking an agent for them, because it knows them and applies them with enthusiasm. A pattern with a proper name is exactly what a model reproduces best: ask for domain-driven design over a six-column table and you get an aggregate, a repository and a factory to store a name and an email address. That is not a modelled domain, it is domain vocabulary painted onto a CRUD.

The idea that outlives the tools

The agent does not build what you meant: it builds what your words say.

06

Hexagonal architecture

Ports and adapters

  • Covers
  • Context
  • Standards
  • Capability

How much does the agent have to read to avoid breaking something?

Put the business rule at the centre, isolated, and leave outside everything that can change: the database, the framework, the interface — and the model.

Where it comes from

Alistair Cockburn proposed it so business logic would not depend on the technology around it. Domain inside, adapters outside, and an explicit boundary between them.

What changes when the author is an agent

Architecture stopped being a matter of taste. It is the variable that decides how much context an agent needs in order to be correct — and context is paid for twice: in tokens and in mistakes.

An agent is correct in proportion to what it can see at once. If changing a business rule means understanding the ORM, the router and three shared helpers, the agent has to load all of it, and the moment it does not fit, it starts inventing. An isolated domain hands it a small, bounded surface. This is not elegance: it is a reduction in the amount of context required to not be wrong.

The other half is what things are called. A folder structure that screams what the business does — billing, bookings, shipping — gives the agent free context before it opens a single file. One that screams the framework makes it read ten files to infer the same thing. Names are the cheapest context there is, and the only kind that is not consumed.

Now the part almost nobody applies: the same architectural idea can be applied to your AI workflow. The model is an adapter. The harness — Claude Code, Cursor, whatever you use — is an adapter. Your domain is the specs, the memory, the standards and the tests. If your knowledge lives inside a tool, you do not have an architecture: you have a dependency.

That is exactly the test this site uses to mark each tool portable or not. Portability is not an abstract virtue: it is the port/adapter boundary applied to your own working environment. What sits inside survives a change of tool. What sits outside does not.

And the downside, because there is one: hexagonal applied badly — a port for everything, interfaces with a single implementation, four layers to read one record — hands the agent more surface, not less. An abstraction that separates nothing real is precisely the kind of pattern a model reproduces enthusiastically.

The idea that outlives the tools

If changing a business rule means touching the framework, the agent will touch the framework.

Principles

Under the practices sit smaller rules that are not procedures: there is nothing to run, only something to decide by. They hold whatever your stack is.

  1. 01Control

    Marginal cost of verification

    Optimise the expensive half, and writing is no longer the expensive half.

    Generating code got an order of magnitude cheaper. Reviewing it costs exactly what it always did. Every bottleneck in an AI-assisted team sits on that side, and almost every decision people make points at the other one.

  2. 02Control

    Falsifiability

    A review that cannot fail is not a review.

    If the criterion admits no negative outcome, you are not verifying: you are requesting approval. It holds for a test, for a checklist, and for an agent you ask to judge another agent's work.

  3. 03Standards

    Contracts before implementations

    Write the type before the function.

    Types are the cheapest verification there is and the only one an agent cannot argue with. Strict mode is not a style preference: it is a control mechanism that runs on every save, for free.

  4. 04Control

    Small diff

    The change has to fit in the reviewer's head.

    Review capacity is the scarce resource, not generation capacity. A two-thousand-line pull request does not get reviewed, it gets approved. And an agent can produce those two thousand lines in ten minutes, so the limit has to be explicit.

  5. 05Context

    Locality

    What is not nearby does not exist, as far as the agent is concerned.

    The model reasons with what is in the window. A rule living three hops away does not constrain it, however important it is. Putting information near where it is used is not tidiness: it is what makes it apply.

  6. 06Context

    The docs are the prompt

    When the documentation lies, the agent is not confused: it complies.

    The README and the instruction file stopped being documentation for humans: they are the first thing the agent reads, in every session, without anyone asking. A stale line there does not confuse someone for a while — it steers the new code.

  7. 07Method

    Reversibility

    Prefer what is cheap to undo.

    With an agent you will be wrong more often and faster. The answer is not to be right more often: it is to make being wrong cheap. Branches, worktrees, contained changes, staged rollouts.

  8. 08Method

    Scope budget

    Declare the limit before starting, not when you get tired.

    The agent is trained to be helpful, and helpful means doing extra. With no limit stated up front — how many files, how many corrections, how much spend — the work does not finish: it gets abandoned.

  9. 09Capability

    Least authority

    Let it run only what you would not mind it running.

    The model cannot tell deleting a temp file from deleting your branch. The environment draws that line. Anything irreversible goes through an explicit confirmation, declared once rather than decided in every prompt.

  10. 10Standards

    AHA before DRY

    Wait for the third repetition before abstracting.

    Patterns are exactly what a model is good at, so it abstracts early and too much. A wrong abstraction costs more than the duplication it avoided, and you find out three months later.

  11. 11Memory

    Traceability

    It must be possible to reconstruct which decision produced this code.

    When something breaks, the useful question is not which line is wrong but what was asked for and why. With no thread joining the commit to the decision, every investigation starts from zero.