From Prompt Engineering to Loop EngineeringValerii Iatsko
From Prompt Engineering to Loop Engineering
Stop prompting. Start designing loops.
From Prompt Engineering to Loop EngineeringValerii Iatsko
Valerii Iatsko
Software engineer at Google
With GitNation since 2016
Work on AI data pipelines and AI developer workflows
From Prompt Engineering to Loop EngineeringValerii Iatsko
You were the loop
"I don't prompt Claude anymore. I have loops running that prompt Claude and figure out what to do. My job is to write loops." โ Boris Cherny, Claude Code (Anthropic)
Prompt โ inspect โ re-prompt โ repeat.
The agent was fast. The steering was manual.
Then models got capable enough to run faster, longer, and in parallel.
Your attention carried state, chose next work, and decided when to stop.
That is how you became the bottleneck.
Scan QR for source note
From Prompt Engineering to Loop EngineeringValerii Iatsko
Move decisions out of your head
Start by asking: what steering decisions am I still making by hand?
what to do next
how to split work
what context to load
which command proves it
when to retry, stop, or ask for review
Loop engineering gives those decisions a place to live:
read state โ choose work โ run agent
โ check result โ record state โ repeat
The human keeps goals, boundaries, and gates.
The loop takes repetitive steering.
From Prompt Engineering to Loop EngineeringValerii Iatsko
What can loops build?
Not just chores.
Loops can build:
repo maintenance and triage
migrations and ports
small product features
full apps from a spec
even languages, if the repo carries enough state
The question is not "can the model do it once?"
It is "can the loop make progress you can inspect?"
From Prompt Engineering to Loop EngineeringValerii Iatsko
Three months of while true
while :; do cat PROMPT.md | claude-code; done
The same PROMPT.md went in every time. An excerpt:
Follow @fix_plan.md and choose the most important thing.
Before making changes, search the codebase โ don't assume
something isn't implemented. When the tests pass, update
@fix_plan.md, then git add -A, git commit, git push.
9999999999. ALWAYS KEEP @fix_plan.md up to date.
99999999999. When you learn how to build, update @AGENT.md.
The prompt never says what to build. specs/ define the target. fix_plan.md is the live backlog. AGENT.md is local operating knowledge.
CURSED code consists of the following token categories:
- `KEYWORD` - Reserved language keywords
- `bool_lit` - Boolean literals (`based`, `cringe`)
- `nil_lit` - Nil literal (`nah`)
- `เถ` - Among Us symbol for pointer types
- Line comments start with `fr fr` and continue to end of line
- Block comments start with `no cap` and end with `on god`
Fifteen files like this: grammar, memory management, concurrency, FFI, the LLVM target. The loop reads these, not your mind.
He didn't type them by hand either. They came out of a planning conversation with the agent, one file per topic, and his job was reviewing them. A duplicated keyword in this very file cost him a month of confused loops.
lexical proof
From Prompt Engineering to Loop EngineeringValerii Iatsko
Rules that survive fresh starts
How to build, test, and run the project. Every fresh iteration reads it first, and the prompt makes the loop maintain it, verbatim:
When you learn something new about how to run the
compiler or examples make sure you update @AGENT.md
using a subagent but keep it brief. For example if
you run commands multiple times before learning the
correct command then that file should be updated.
Huntley calls it the heart of the loop. Run a command wrong three times, write down the right one, and the mistake only happens once.
From Prompt Engineering to Loop EngineeringValerii Iatsko
What came out
slay main_character() {
sus i normie = 1
bestie i <= 100 {
ready i % 15 == 0 {
vibez.spill("FizzBuzz")
} otherwise ready i % 3 == 0 {
vibez.spill("Fizz")
} otherwise {
vibez.spill(i)
}
i = i + 1
}
}
FizzBuzz, verbatim. slay is a function, sus a variable, bestie a for-loop. It compiles: LLVM backend, three platforms, a standard library. Nobody was hand-prompting after kickoff.
From Prompt Engineering to Loop EngineeringValerii Iatsko
Takeaway: repo state drives the loop
Clean starts are useful only when the repo remembers.
From Prompt Engineering to Loop EngineeringValerii Iatsko
"We put a coding agent in a while loop and it shipped 6 repos overnight"
A real HN headline. The whole setup, from their writeup:
while :; do cat prompt.md | claude -p; done
Your job is to port browser-use monorepo (Python) to
better-use (Typescript) and maintain the repository.
Make a commit and push your changes after every file edit.
Six projects overnight: React to Vue, Python to TypeScript, TypeScript to Python, plus specs-to-code experiments from docs. About 1,100 commits, just under $800.
Nothing stopped the loops. Humans looked in the morning.
From Prompt Engineering to Loop EngineeringValerii Iatsko
Big diffs die waiting
The same team pointed a loop at their own frontend. The actual prompt, committed in the PR (condensed):
0a. Read REACT_CODING_STANDARDS.md โ the ideal architecture
1. Read REACT_REFACTOR_PLAN.md and implement the SINGLE
highest-priority change, with tests
2. Run the checks and tests, fix until all are passing
3. Update the plan, commit, push
Six hours of that produced +19,392 / โ1,367 across 131 files and zero formal reviews. A diff that size never even reached review. While it sat, main kept moving; the conflicts outgrew the refactor. PR #513: closed, not merged.
"Waking up to one small refactor every morning is better than waking up to none โ and better than waking up to 50."
Their fix: once per night, a diff sized to review over coffee and merge the same morning. The bottleneck was never the agent. It's how fast humans absorb change.
From Prompt Engineering to Loop EngineeringValerii Iatsko
Takeaway: speed moves the bottleneck
Parallel loops turn calendar time into attempts.
They do not remove human accountability.
When code gets cheap, the scarce thing becomes:
deciding what to accept
merging it safely
keeping the system coherent
owning the outcome
From Prompt Engineering to Loop EngineeringValerii Iatsko
Hand off repetition. Keep judgment.
the loop can do
you still own
repeat prompts
the objective
work the checklist
the spec
chase green tests
test authority
propose next tasks
approval
merge routine branches
review bandwidth
Before it runs unattended, be able to answer: What goal is it serving? What is it allowed to change? What makes it stop?
From Prompt Engineering to Loop EngineeringValerii Iatsko
What should you automate?
Put loops where work is:
Recurring โ the same prompt every day or every red build
Checkable โ tests, logs, diffs, screenshots, or a reviewer can say pass/fail
Bounded โ small blast radius, clear files, easy rollback
Good first loops: CI triage, flaky-test diagnosis, dependency bumps, doc drift, small bug queues.
Bad first loops: broad refactors, architecture rewrites, "make it better."
From Prompt Engineering to Loop EngineeringValerii Iatsko
Step 1 of 5
The starter loop is five artifacts
SPEC.md โ what "done" means
PLAN.md โ the queue, as checkboxes
AGENTS.md โ local rules and commands
PROGRESS.md โ memory between fresh agents
loop.sh โ repeats until the plan is empty
Each one is reviewable. That is the point.
The loop can move work forward, but these files keep the work legible.
From Prompt Engineering to Loop EngineeringValerii Iatsko
Step 1 of 5 ยท file 1
SPEC.md: own the target
# SPEC.md
Goal: a tiny expression language.
...
Done means:
- every checklist item is ticked
- node --test is green
Non-goals:
- no package manager
- no syntax not described in this spec
This is not a prompt. This is the contract the loop keeps rereading.
From Prompt Engineering to Loop EngineeringValerii Iatsko
Step 1 of 5 ยท file 2
PLAN.md: make work claimable
# PLAN.md
- [ ] 1: lexer tests for numbers and operators
done when: the new test fails for missing lexer
- [ ] 2: implement the lexer
done when: node --test is green
- [ ] 3: parser tests for expressions
done when: the new parser test fails
One checkbox = one iteration. Small enough to review.
From Prompt Engineering to Loop EngineeringValerii Iatsko
Step 1 of 5 ยท file 3
AGENTS.md: put rules where agents look
# AGENTS.md
- Run tests with `node --test`
- Work only on the first unchecked PLAN.md item
- During implementation, do not edit `test/`
- Append one PROGRESS.md line before exit
The prompt can stay short because the repo carries the rules.
From Prompt Engineering to Loop EngineeringValerii Iatsko
Step 1 of 5 ยท file 4
PROGRESS.md: give the next agent memory
# PROGRESS.md
- 09:12 wrote lexer tests; next implement token shape
- 09:18 lexer green; next write parser expression tests
- 09:25 parser test expects BinaryExpression.operator
A fresh agent starts from files, not from yesterday's chat context.
From Prompt Engineering to Loop EngineeringValerii Iatsko
Step 1 of 5 ยท file 5
loop.sh: repeat the handoff
while grep -q "\[ \]" PLAN.md; do
codex exec "Read SPEC.md, PLAN.md, AGENTS.md, PROGRESS.md.
Build the first unchecked item. Test it.
Tick it only if green. Append progress."
done
That's the first handoff: the loop works the plan now. The spec is still yours.
From Prompt Engineering to Loop EngineeringValerii Iatsko
Step 2 of 5
Protect the tests from the loop
Still one agent, one loop, but now it runs unattended. A loop was told "make the tests pass":
iteration 4: 3 tests failing
iteration 5: 0 tests failing โ it deleted the tests
Not a naughty model. A badly specified objective: you asked for green, you got green.
So who writes the tests? The loop can โ writing a test is its own iteration. The rule protects the other iterations: when the job is "make the tests pass," the test files are off-limits, enforced by the tools, not by a polite sentence in the prompt.
From Prompt Engineering to Loop EngineeringValerii Iatsko
Step 3 of 5
Hire a skeptic
The first time we add a second agent. It's nothing new: the same claude -p, a different prompt, no shared memory with the writer.
git diff | claude -p "Try to prove this change is wrong.
Run the tests.
Verdict: pass or fail, and why."
Ask it to prove the work wrong, not to approve it. Models reviewing their own output don't get better, they get agreeable (Huang et al., ICLR 2024).
On fail, the loop stops and a human looks.
From Prompt Engineering to Loop EngineeringValerii Iatsko
Step 4 of 5
Let it refill its own backlog, carefully
When the plan runs dry, one extra run gets a different prompt: read the goal, propose at most two tasks, build nothing.
Proposals follow the same rules as human tasks, are labeled as machine-written, and wait for a person to approve them.
This handoff: the loop proposes work now. The goal stays with you.
From Prompt Engineering to Loop EngineeringValerii Iatsko
Step 5 of 5
Scale by adding loops, not chaos
Start with one loop on main: no branches, no merging, one task at a time. That's not a limitation, it's the baseline.
When review capacity grows, scale in this order:
Schedule it. A nightly cron, a diff sized to review over coffee.
Add worker loops in worktrees. Same PLAN.md, one git worktree per worker, finishing work as PRs. Give the plan a tiny state language: [ ] open, [~] claimed, [c] ready.
Automate the merge last, once it's boring: one more agent that merges a branch, re-tests main, and stops the moment anything is off.
From Prompt Engineering to Loop EngineeringValerii Iatsko
Should you use loops?
Yes, when the work is:
repeated
checkable
bounded
blocked mostly by your steering
No, when "done" is unclear or nobody owns the gate.
Loops are not a way to avoid judgment.
They are a way to spend judgment where it matters.
From Prompt Engineering to Loop EngineeringValerii Iatsko
Start with loops today
Ask where you are still doing routine steering
work you re-prompt every week
decisions that follow the same rule
checks that can say pass or fail
"done" or "good" you can write down
Keep real-time judgment with the human
Give the loop the routine path
Start with one tiny loop, one state file, and one review gate
From Prompt Engineering to Loop EngineeringValerii Iatsko