Skip to content

Staying the engineer who understands the system

In this lesson we look at what happens to your own understanding of a system when an agent writes most of the code. The earlier lessons in this course gave the agent a plan to follow, a spec to work from, and small increments to land. Each of those keeps the agent’s output checkable. This lesson is about the other side: the engineer who does the checking has to understand the system, and that understanding is easy to lose when someone else types every line. We name where it leaks away, and the habits that keep it. The page has no code to run. The examples refer to the to-do fixture from Working from a spec in small increments, and the exercise uses that fixture after its increments are merged.

The claim behind the lesson is plain. You can only review a change to a system you understand, and every agent change gets reviewed by you. An agent that produces more code than you can hold in your head has moved the review from you to nobody. Brilliant’s skills map for coding with AI lists keeping your understanding and the coherence of the system as a skill of its own within incremental development, separate from getting the increments to land [1].

Reading code and writing code build understanding in different ways, and an agent removes the second one entirely. Suppose you had written the overdue command yourself instead of briefing the agent for it. You would have decided where today’s date comes from, seen a first try fail the test with the two TODO_TODAY dates, and fixed it. The decision would stay with you because you made it. When the agent merges the same increment, the code arrives finished. The tests pass. The diff is small and the report is confident. Every reason to slow down and read it is gone, and so is the moment where the decision would have become yours.

The leak is slow. After one increment you still know the program, because you wrote the spec. After ten, you know the spec and the agent knows the code. After a hundred, a colleague asks in a design review why the date is stored as a string and you open the transcript to find out. That’s the point where the objective of this lesson has been missed: you can no longer explain how the parts fit or why they were built that way, and the agent’s next change goes into a system nobody on the team can vouch for.

Checkpoint · choice

An engineer merged twenty increments with an agent over a month, each one tested and merged after a glance at the diff. Asked in a design review why the queue is in-process, the engineer has to look it up. What did the small, green diffs cost?

The first habit is to read agent-written code with the attention you give a colleague’s pull request. That’s a lower bar than it sounds, because you already read colleagues’ code for a living. It is also a higher bar than most engineers hold agent output to. A colleague’s PR doesn’t arrive with its tests already green and a paragraph saying it is done.

Reading means the whole diff, at the speed it takes to follow it. You stop at anything you can’t explain, such as a regular expression you can’t parse or a helper whose name doesn’t say what it does. At each stop, you have two moves. Ask the agent to explain the line in plain language, and ask it for a test that documents the behavior you couldn’t see. The test stays in the suite after the explanation is forgotten, and it turns a line you took on faith into one the suite checks.

Prompt (illustrative, not a recorded transcript)

In todo.py, the due command validates the date with datetime.date.fromisoformat(text). Explain in plain language which inputs that accepts and which it refuses, and add a test that documents one accepted and two refused inputs.

Response

fromisoformat accepts a date written as four digits, a dash, two digits, a dash and two digits, such as 2026-10-01, and raises ValueError for tomorrow and for 2026-10-1, where the day has one digit. Which other forms it accepts depends on the Python version. On 3.9 and 3.10 the dashed form is the only one. From 3.11 it also accepts other ISO 8601 forms, such as 20261001 without dashes and the week form 2026-W40-4. The spec’s bad date criterion names tomorrow, and the due command catches the error and prints bad date: <input> for it on every version. I added test_due_date_formats in test_due.py with 2026-10-01 accepted and tomorrow and 2026-10-1 refused, which holds on 3.9 and on 3.11. If you want 20261001 refused too, the check needs to be stricter than fromisoformat alone, and that is a spec decision.

This exchange is illustrative and shows the form of the question. The version difference is the kind of fact you only learn by asking. Had you skimmed past the line, the program would accept 20261001 on a colleague’s newer Python and refuse it on your own older one, and nobody would know why. The answer also surfaced a spec question, which forms count as a bad date, and that question goes back to the spec before anyone writes more code.

The habit costs minutes per increment, and small increments are what make it possible. A diff you can read in one sitting is a diff you can understand. The brief that asks for small increments is the same brief that keeps your reading possible.

Checkpoint · scenario

The agent’s increment for date validation includes a regular expression you can’t parse. The suite is green. What do you do?

Reading builds understanding, and the check that it worked is whether you can explain the system without looking at it. After an increment is merged, close the editor and say how the parts fit and why they were built that way. For the due-dates feature that’s a few sentences: the date is a field on the item that some items have and some don’t, render.py shows it when it is present, store.py didn’t change because the JSON file takes whatever keys an item has, and overdue reads today from TODO_TODAY so a test can pick the day. Each of those sentences has a “because” in it, and the “because” is the part you lose first.

Then open the code and check your explanation against it. Where the code does something your explanation didn’t predict, you have found a gap in your model, and the increment isn’t done until you close it. Either the code is right and you ask the agent why, or the code is wrong and it comes back to the spec. Either way, the review did its job.

This is also the point to notice when the answer to “why” is a guess. “The date is a string because that’s what JSON has” is an explanation. “The date is a string, I think because the agent chose it” is a decision nobody made. A decision nobody made is a decision the next session can contradict, and that’s the subject of the last section.

Checkpoint · multi-choice

An engineer explains the due-dates feature from memory. Which of these sentences show the understanding this lesson asks for?

Select exactly 2.

Keep the reasons where the agent reads them

Section titled “Keep the reasons where the agent reads them”

The third habit is about the team, and about the next session. An architecture decision that lives in your head is safe until the next person, or the next agent session, makes a different one. A fresh agent session starts from the files in the repository and, for some tools, a private memory the agent keeps for itself. Claude Code, for example, loads CLAUDE.md and its auto memory at the start of every conversation [2]. The chat transcript of the last session is in neither. A decision the session doesn’t find in what it loads is one it doesn’t know about, and one it will reverse when the decision gets in the way of the task in front of it.

So the reasons go in the repository, in two places that point at each other. A decisions folder, often docs/decisions/, holds one short file per decision: what was decided, why, and what was considered and rejected. The project instructions point the agent at it, the way Writing project instructions the agent reads every session showed. The to-do fixture has an instructions file, and its lines say which commands must keep working and that SPEC.md is the source of truth while a change is in progress.

A decision file for the fixture is short.

# Due dates are stored as ISO strings
Date: 2026-10-01
## Decision
An item's `due` field is a `YYYY-MM-DD` string in `todos.json`, parsed
when it is compared and never at load time.
## Why
The JSON file has no date type. Parsing at load would make an item with a
bad date impossible to load, and the spec says an item without a `due` field
stays valid. Parsing at comparison keeps `list` working on any file that
loads today.
## Considered
A Unix timestamp: harder to read in the file, and the spec shows the date
in `list` as written. A separate dates file: two files to keep in step.

And one line in the instructions:

- Architecture decisions are in `docs/decisions/`. Read the ones that
touch the files you change, and add one when you make a new decision.

The instructions line does two jobs. It tells the agent where the reasons are, so the next session that touches dates reads why they’re strings before proposing timestamps. And it tells the agent to write a decision down when it makes one, which is how the folder stays current when the agent merges most of the increments. You still read every new decision file as part of the diff, because a decision the agent wrote and you didn’t read is back in nobody’s head.

Checkpoint · sort

Exercise

Take a copy of the to-do fixture from Working from a spec in small increments with its first two increments merged, as that lesson and its exercise leave it. Close your editor and write down, from memory, how the due date flows from the due command through the modules to list and overdue, and why the field is optional. Then open the code and mark every sentence right or wrong. For each wrong one, ask the agent to explain the line you misread. Finish by adding docs/decisions/ with one file recording why dates are stored as strings and parsed late, and a line in the fixture’s AGENTS.md that points the agent at the folder. Plan on ten minutes. This is the check you run after any increment you didn’t type yourself.

A good result: your explanation names the field, the three modules and which of them changed, and says why an old item without a date still loads. At most one sentence needed correcting after you read the code. The decision file says what was decided, why, and what was rejected, and the AGENTS.md line names the folder. Then answer one question: which sentence of your explanation would you have got wrong a week from now, and is the reason for it written down anywhere the agent reads?

Stretch: Do the same after the third increment, date validation. Then compare your two decision files: does the second one contradict anything in the first, and if so, which of the two changes?

Recap

  1. Understanding leaks when the agent writes and you only run the tests. Passing tests check the change and say nothing about whether you can still explain the system [1].
  2. Read agent code with the attention you give a colleague’s pull request. Stop at every line you can’t explain, and ask for a plain-language explanation and a test that documents it.
  3. After an increment is merged, explain from memory how the parts fit and why, then check the explanation against the code. A gap is a review finding.
  4. Architecture decisions and their reasons go in a decisions folder in the repository, and the project instructions point the agent at it, so the next session reads the reason before it proposes to reverse the decision.

You can now

  • Keeps their own understanding of the code as the agent produces more of it

  1. Brilliant. Developing incrementally. Brilliant, Coding with AI skills map. Reference. Brilliant INC
  2. Anthropic. How Claude remembers your project. Claude Code documentation. Reference. Claude Code memory