AI Engineering
AI wrote the code. Do you still understand it?
Aditya Shah · Oct 13, 2026 · 8 min read
I use Claude Code for most of my work now. The code ships, the tests pass, and the PRs get merged. What I noticed is the part nobody warns you about: you end up understanding less of your own system than you think.
I gave a talk on this recently. This post is the written version, with every prompt I use and the CLAUDE.md that runs the whole loop at the end.
Understanding used to be free
When you wrote the code yourself, understanding was a side effect. You could not ship something you had not understood, because you had to build it line by line.
Before: understand, design, code, test, review. Weeks of building.
Now: prompt, 10 to 50 files changed, tests pass, merge. Hours, and nothing in that loop makes you understand what changed.
So the question I keep asking myself is simple. AI wrote 80% of it. Do I understand 100% of what it does?
This is not a "use AI less" post
I want to use AI as aggressively as possible, while still understanding how the result works. Addy Osmani put it well in his essay on comprehension debt:
Making code cheap to generate doesn't make understanding cheap to skip.
Understanding no longer comes for free, so I build it back in on purpose. My answer is a loop of six prompts between "generate" and "merge".
The loop
- Plan. Read the plan before any code exists.
- Implement. The smallest change, inside the scope I set.
- Trace and map. Walk the flow and list every change and why.
- Challenge. Make it argue against its own code.
- Quiz (optional). Let it test me before I merge.
- Own. Four questions I answer myself.
Then the next ticket starts the loop again. None of these steps asks you to write code by hand. Every step is a prompt.
1. Plan
Read the code and understand how it works.
Don't write a single line of code.
Give me a detailed plan.
Nothing gets written until I have read the plan. The plan is something I can read, argue with and correct before a single file changes.
This step has already paid off for me. One plan showed the agent reading data from a cache that updates late. As a diff, that bug is invisible: the code works, it just reads stale data sometimes. In the plan it took a two-line conversation to fix.
2. Implement
The plan is approved.
Make the smallest change necessary.
Scope the work to <the module you agreed on> only.
A diff I can't read is a diff I can't own. I keep the change small, I don't let it refactor code outside the plan, and if it needs a file the plan didn't list, it has to stop and tell me why.
3. Trace and map
Summarize every change and why it was necessary.
Trace one request end to end. Don't skip layers.
Separate what the code confirms from what you assumed.
Reading the trace is faster than reading the diff. The part I read first is the assumptions list, because that is where the bugs hide. Anything it assumed, I check before merging.
4. Challenge
Act as a hostile senior reviewer.
Convince me NOT to merge this PR.
Race conditions, security, wrong assumptions, failure paths.
Be critical rather than agreeable.
Claude will defend its own code unless you tell it not to. Ask "is this ready to merge?" and you usually get a yes. Ask it to argue against the change and it finds things.
In one review it found a settings screen that showed memory as raw Markdown, while the chat view rendered the same text properly. Same data, two renderers, and every test passed.
5. Quiz (optional)
Quiz me on this change before I merge it.
Five questions, one at a time. Wait for my answer.
Don't give me the answer. Tell me where to look.
Generate, then ask. In Anthropic's study on AI assistance and coding skills, developers who asked questions after generating code kept their understanding, while those who only delegated lost it. When I get a quiz answer wrong, that is the file I reread before merging.
6. Own
Before I hit merge, I answer four questions myself, without the chat open:
- What does this do, and why?
- What happens when a dependency fails?
- Do the tests check behavior, or do they just pass?
- Could I debug this at 3 AM without the chat history?
I also attach the plan to the PR and call out what the reviewer must look at: the assumptions, the risky paths, and any file the agent touched beyond the ask.
The CLAUDE.md that runs the loop
You don't need to remember all of this. Paste the block below into CLAUDE.md in your repo, or into ~/.claude/CLAUDE.md to use it in every project. Then start a message with a trigger word: plan, implement, trace, challenge, quiz or own.
# AI code ownership loop
Six steps between "generate" and "merge". You write the code. I still have to understand it.
A step starts when my message begins with its trigger word, with or without a leading slash. `plan-feature` also counts for step 1.
## Always
- A feature, or any change that touches more than one file, starts with an approved plan. If I ask for one without a plan, say so and offer to plan first. One-line fixes skip the loop.
- Make the smallest change that works. Do not refactor unrelated code.
- Separate what the code confirms from what you assumed. Say which is which.
- When I ask whether something is ready to merge, answer as a hostile reviewer, not as the author.
- If the code contradicts the plan, or you need a file outside the plan, stop and ask before continuing.
## 1. Plan `plan <feature>`
Do not write or edit any code in this step. Not a single line.
- Restate the feature in two or three sentences with one concrete example. If the idea is too vague to restate, ask at most three questions and stop.
- Trace one real request through the code path this feature will change, end to end: entry point, calls, decisions, external services, data store, error handling, response. Cite file paths. Do not skip layers.
- Look for code, settings, or patterns that already do part of this. Say whether to extend them instead of adding something new.
- Answer the design questions from the code, with file:line evidence: scope (who it applies to), storage, where it plugs into the existing flow, what it must never override, whether a change takes effect immediately or hits a cache, and what it costs.
- Split findings into Known (backed by code) and Assumed (with what breaks if wrong). List the questions only I can answer.
- Plan the smallest v1: files per repo (at most five, justify more), data or API changes, the flow before and after, three tests (one that must work, one that must be rejected, one that checks freshness), and risks.
- Review your own plan as a hostile senior reviewer. Name its weakest part and revise.
- Stop. Wait for my approval before writing code.
## 2. Implement `implement <constraints>`
Treat the plan as approved. My constraints override it. Where the plan left a question open, use its own recommendation.
- Touch only the files in the plan. Match the patterns already in each file. No new abstractions unless the plan asked for them.
- Build from the bottom up: data and backend, then API, then UI. Skip layers the plan does not touch.
- Write and run the tests from the plan.
- Finish with two lists: every file changed and why each change was necessary, and every decision you made on your own.
## 3. Trace and Map `trace`
No code changes. Read and explain.
- Summarize everything changed this session and why each change was necessary. Flag anything outside the plan.
- Trace one real request through the new behavior, from entry point to what the user sees rendered. Cite the file and function at every step. Mark the steps this session changed.
- Split what the code confirms from what you assumed. For each assumption, say what breaks if it is wrong.
- End with the one thing a reviewer should check first.
## 4. Challenge `challenge`
Act as a hostile senior reviewer. Convince me NOT to merge this. Be critical rather than agreeable.
- Check race conditions, security, wrong assumptions, failure paths, and every screen or consumer that reads the data this change touches.
- Report blockers first, then risks, then nits. Give each a file:line and a way to confirm it.
- Do not fix anything unless I ask. Say you found nothing only after checking every area above.
## 5. Quiz `quiz` (optional)
- Ask me five questions about this change, one at a time. Wait for my answer before the next.
- Cover the flow, the failure paths, and why each file changed.
- Do not give me the answer. Tell me where to look.
- After the fifth, list what I got wrong and the file to reread before merging.
## 6. Own `own`
- Draft the PR description: what changed and why, a link to the plan, and a section the reviewer cannot miss listing assumptions, risky paths, and files touched beyond the original ask.
- Then ask me these, and do not answer them for me: What does this do and why? What happens when a dependency fails? Do the tests check behavior or just pass? Could I debug this at 3 AM without the chat history?
## Setup
Paste this file into `CLAUDE.md` (the project root for one repo, or `~/.claude/CLAUDE.md` for every project). Or save it as `ownership-loop.md` next to `CLAUDE.md` and add the line `@ownership-loop.md`.
Start with plan on your next real ticket. That one step catches the most.
The short version
You can write less code and still understand more of the system. AI generates the implementation. You still own the consequences.