You’ve been told this changes everything. It hasn’t worked yet.
Either
you haven’t really started. Opened it, typed something, got a shrug, closed it.
Or
you did start, and it produced something confident and wrong that took longer
to clean up than to have written yourself.
Both are the correct reaction. The method is missing — nobody hands you the
method, they hand you a text box.
This starts where the 101 stops
Assumed: you have run a task in plan mode and read the diff.
By the end you can:
Explain why quality depends on context and specification, not model choice
Locate yourself on the map and name your next step
Judge what comes back instead of trusting how polished it looks
Capture one thing that worked into a file your team can reuse
Fluency takes weeks of doing this on real work. A talk doesn’t buy it.
Most of this room is at 2 — which is the normal place to be
1 No AI
2 Individual ad-hoc use
3 Team-integrated workflows
4 Semi-autonomous + guardrails
5 Fully AI-native
Level 1 is behind you. Three passes over one task make Level 2
deliberate; the rest of the hour is 3, 4 and 5. A map is not a
scorecard — it just tells you which direction is forward.
The thing that changed isn’t quality. It’s the size of task it can finish.
~5 hours
of human work, on tasks a frontier model finishes half the time (interval: 2.8–12.1 hours)
Measured across 228 tasks.
That horizon doubled roughly every 7 months since 2019 —
and every 3 months since 2024.
METR, Time Horizon 1.1, January 2026
The task: add retry with backoff
Our API client hammers a flaky upstream service. Add retry with backoff.
Deliberately boring. Every one of you has done a version of it.
Hold in your head what a good answer looks like.
Pass 0: it’s good. Better than most of us write by hand.
// Methods safe to replay: the upstream ends in the same state whether
// the request lands once or twice. POST is absent on purpose.
export const IDEMPOTENT_METHODS = new Set(['GET','HEAD','OPTIONS','PUT','DELETE']);
// Full jitter (random(0, backoff) rather than backoff itself) keeps
// concurrent callers from re-converging on the same retry instant.
export function backoffDelay(attempt, { baseDelay, maxDelay }, random = Math.random) {
const ceiling = Math.min(maxDelay, baseDelay * 2 ** attempt);
return Math.round(random() * ceiling);
}
// Retry-After is either delta-seconds or an HTTP date. Returns ms, or null.
export function retryAfterMs(response, now = Date.now()) { /* ... */ }
real output, one sentence of prompt — plus 18 passing tests it wrote unasked
So what decision did it make for you?
// The timeout is per attempt, so each retry gets a full budget.
You passed timeout: 10_000. Three attempts plus backoff is
~30 seconds. There is no total budget anywhere.
It didn’t get this wrong. It decided it,
wrote a comment justifying it, and moved on.
Nobody flags that line in review. The comment makes it look considered.
Instructions are intentions — every gap you leave, it fills
It’s probabilistic. When you write a rule, you are shifting
a probability — not setting a flag.
Not a defect you can prompt your way out of. It’s the shape of the thing.
The loop, the window, and why it has never seen your code — all in the 101.
Pass 1 changes one thing: write the intent down first
Same task. Same model. Same tool.
Before I open a session, I write down what I actually want — in a file.
Not a formal document. Eight lines.
Eight lines, four minutes — every one a decision it made for me last time
# Retry with backoff — intent
- Retry only idempotent requests: GET, HEAD, PUT, DELETE. Never POST.
- Retry only on 429, 502, 503, 504, and connection/timeout errors. Never 4xx.
- Exponential backoff with full jitter. Base 100ms, cap 5s.
- Respect an overall deadline passed by the caller; never exceed it.
- Max 4 attempts total, including the first.
- Log every retry with attempt number and reason.
Same model, same tool, different output
const RETRYABLE_STATUS = new Set([429, 502, 503, 504]);
const IDEMPOTENT = new Set(['GET', 'HEAD', 'PUT', 'DELETE']);
function backoffWithJitter(attempt) {
const ceiling = Math.min(MAX_DELAY_MS, BASE_DELAY_MS * 2 ** attempt);
return Math.random() * ceiling; // full jitter
}
if (!IDEMPOTENT.has(method)) {
return fetch(url, { method, ...options }); // never retry non-idempotent
}
excerpt — full source in the repo
What’s still missing from my spec?
What happens when retries are exhausted — throw, or degrade?
Does the deadline include the backoff sleeps?
Does any of this apply to streaming responses?
The specification is the bottleneck, not the model
The file outlives the session — and context degrades before it fills
Across 18 frontier models, accuracy grows increasingly
unreliable as input length grows.
And models do worse when the long context is logically coherent
than when it’s shuffled.
More context is not free.
So you don’t hold state in a conversation.
You write it to disk and hand it over.
The file is the handoff.
Chroma Research, “Context Rot,” 2025
Pass 2: a second session that never watched the first one work
When the work is done, open a fresh session
and ask it to review the result.
With the spec. Without the conversation that produced the code.
Not the same session. The reviewer must not have watched the author work.
Both serious findings were in the one requirement I’d put in bold
Eight findings. Six were minor — a missing log line, an
unreachable constant, a case-sensitivity nit.
Both of the serious ones were in the deadline
logic.
HIGH 1 — the deadline check reserves no room for the
next attempt, and destroys the last usable response. One of four attempts burns
on a 12ms window that could never succeed.
HIGH 2 — only undefined is guarded.
deadlineMs: null fails every request with zero fetch calls;
NaN slips through and silently disables the deadline entirely.
attempt 1/4 failed (HTTP 503); retrying in 100ms
THREW Error: deadline of 130ms exceeded after attempt 2 (timeout after 12ms)
It works because it has your spec — not because two agents are smarter than one
Revising its own reasoning with nothing external to check
against doesn’t reliably improve — sometimes it gets worse.
Copies of a model debating each other produce
consistency, not correctness.
Pass 2 works because the second session has
something external to check against — your spec.
And it ran probes —
every finding reproduced by executing code, not read off the page.
Huang et al., “LLMs Cannot Self-Correct Reasoning Yet,” ICLR 2024
You cannot tell how well this is going. Neither can I.
Polish suppresses scrutiny.
Across 9,830 conversations, the ones involving code were where people
least questioned the reasoning (−3.1pp) or noticed missing context
(−5.2pp). Anthropic AI Fluency Index, Feb 2026
The harness moves the number as much
as the model. Swap the scaffold around a fixed model and benchmark scores move
like a model generation — 21.8 points on one benchmark.
Gorinova et al., June 2026
And this one happened to me.
I asked an agent to check a 2026 result. It reported +18% — twice.
The paper reports −18%, a CI crossing zero, and
“very weak evidence.”
METR, Feb 2026
The check has to be structural, not a feeling
Level 1 → 2 — done
You just did the whole thing by hand
1 No AI
2 Individual ad-hoc use
3 Team-integrated workflows
4 Semi-autonomous + guardrails
5 Fully AI-native
Write the intent to a file before you start. Hand the file to a fresh
session. Open a second session to check the result against the file.
That is Level 2, and it is genuinely most of the
value. If you stop here you have not failed.
Level 2 → 3
Your practice lives in your head. That doesn’t scale to a team.
1 No AI
2 Individual ad-hoc use
3 Team-integrated workflows
4 Semi-autonomous + guardrails
5 Fully AI-native
You know to say “never retry a POST.” The next person doesn’t.
Every session on your repo starts from zero.
The highest-leverage file in the repo is the one the agent reads first
# AGENTS.md
## Things an agent would otherwise get wrong
- Never retry non-idempotent requests. POST is not safe to replay here;
the orders endpoint is not keyed for deduplication.
- `pricing.internal` is behind a 200ms p99. Anything in the request path
needs a deadline, not just a per-attempt timeout.
- Run `npm test` before claiming done. There is no CI on this repo yet.
Not documentation. The set of things that get got wrong.
Ours is one line long
@AGENTS.md
That is the entire CLAUDE.md. The tool-specific file is a pointer;
the content lives in a tool-agnostic one.
In May, ours was a “comprehensive project reference.” We learned.
Most of these files make things worse
A February 2026 study ran four agents across 300 SWE-bench Lite tasks and a
138-task agent benchmark, with and without context files.
Auto-generated context files — the raw output of an init
command — did not improve success rates at all,
while raising cost by over 20%.
And when they stripped the README and docs out of the repo, context files
started helping consistently — which tells you most of what people put
in them was already discoverable.
ETH Zurich, February 2026
You have an instruction budget, and it is smaller than you think
Instruction-following degrades as instruction count rises — benchmarks put
the turning point somewhere around the low hundreds, and your file
is not the first claim on that budget. The harness ships its own.
And adherence decays through a session: strong in the first couple of
exchanges, measurably weaker by the tenth.
You’re not writing laws. You’re writing suggestions.
Every line you add is a line that competes with the work
Bloated
“This is a Node.js project using ES modules. We value clean code and
readability. Please write good tests. Follow SOLID principles…”
True, generic, and it displaces context that isn’t.
Sharp
“There is no CI on this repo. Run npm test before claiming
done.”
Unguessable, specific, changes behaviour.
Test for every line: could a competent stranger have guessed it?
Context arrives in layers, and you are budgeting, not tidying
Global — how you work, everywhere
Project — how this repo works (AGENTS.md)
Skills — loaded only when relevant
Tools / MCP — systems it can reach
Conversation — right now
The mistake is stuffing everything into the top layer.
A skill is context that loads itself only when it’s needed
---
name: incident-response
description: Use when triaging a production alert, paging, or writing a
postmortem. Covers severity levels, comms templates, and escalation.
---
# Incident response
(...900 lines the agent only reads when the description matches...)
The description is the whole game. It is the only part always loaded.
Precision in, precision out
Before
After
Session cost
$3.60
$2.64
Wall time
17m 10s
9m 12s
New tokens
~361k
~169k
Lines the agent changed
1,159
119
Same task, same repo. The only change was tightening skill descriptions and deferring
bodies behind them. No rules were deleted.
Three ways to give it capability, and they are not interchangeable
Command / SOP
A repeated process
“run our design phase”
Skill
Domain knowledge
“how we handle incidents”
MCP tool
An action in another system
“query the dashboard”
Most teams reach for the third when they needed the first.
MCP is the expensive one, and it charges you up front
MCP tool definitions load eagerly — every tool, every
session, whether you use it or not. One internal server measured at
~27k tokens, about 13.5% of the window, before any work started.
A skill costs you a name and one line until it fires.
So: MCP for what you need in most tasks. Skills for what you need
sometimes.
Which one would you reach for?
“Every new service needs the same six setup steps”
“The agent should be able to read our on-call schedule”
“Nobody remembers our deprecation policy”
Command. MCP tool. Skill.
Level 2 → 3 — done
The team’s knowledge stops being something people carry
What you were doing by hand: re-supplying the conventions,
every session, forever.
What replaced you:AGENTS.md for the corrections
that repeat, skills for knowledge that loads on demand, MCP only where the agent
must reach another system.
Do this week: at the end of your next session, ask what
you had to correct, and put those lines in AGENTS.md.
Level 3 → 4
You are still the first person who reads everything
1 No AI
2 Individual ad-hoc use
3 Team-integrated workflows
4 Semi-autonomous + guardrails
5 Fully AI-native
The work got faster. Your queue didn’t. Everything still routes through
one pair of eyes — yours.
Things you ask for, and things you actually enforce
Asked for
“Always run the tests before you say you’re done.”
A probability shift. Usually works. Not always.
Enforced
A hook that runs the tests on every edit, and blocks on failure.
A door that is locked.
Autonomy is only as safe as the things you enforce
Someone measured this properly: five approaches, 600 runs each
Pass rate
Input tokens
No instructions
15.7%
1,870
Simple instructions
82.5%
2,329
Full procedure in the prompt
99.8%
9,879
Graph / workflow orchestration
80.8%
3,116
Enforced by hooks
100.0%
3,346
Same tools, one task. Enforcement matched the best prompt at a third of the
tokens — a hook fires at the decision, not ten turns earlier.
Clare Liguori, Strands Agents, March 2026 — one chatbot task, vendor-published
So put the reviewers before your eyes, not after
Gate 1 — evaluate. Correctness, tests, security, style.
Several reviewers, different jobs, in parallel.
Gate 2 — challenge. An adversary tries to
refute gate 1’s findings. Are these real, or noise?
Gate 3 — safety. What did everyone else miss? Edge cases,
error paths, concurrency.
By the time it reaches you, the question is “is this the right approach?”
— not “is there a null check missing on line 47?”
The reviewers are told to forget that you meant well
Reviewers run cold — the instruction to respect the
author’s intent is suspended. They judge the code, not the plan.
Then a separate pass puts intent back and sorts every finding into
real bug, over-flagged, or
not a bug.
Two passes, because doing both jobs at once produces a
reviewer that talks itself out of real findings.
Every loop needs a way to stop that isn’t you noticing
A round cap. Three passes, then it stops
and escalates rather than grinding.
A circuit breaker. If the same finding
survives two attempted fixes, stop trying and hand it back.
A diminishing-returns breaker. If a round
is producing less than the one before it, that is the signal to stop.
Without these, a loop either runs forever or quietly ships something it
couldn’t fix.
The bill for getting this wrong arrives quietly
Publicly reported: a runaway agent loop that burned tens of thousands of
dollars in five hours. Another that ran eleven days before
anyone noticed.
The mechanism is simple. Every retry re-reads the whole context. Iteration one
costs a little. Iteration ten costs a lot. You pay for each failure again and again.
Agents don’t fail loudly. They retry, reformulate, and look busy the whole time.
If you can’t grep why it stopped, you haven’t automated it — you’ve hidden it
Every decision the pipeline makes leaves a line. Including the decisions to
not do something.
You can only let it run unattended if the worst case is cheap
git worktree add ../task-3 -b task-3
cd ../task-3
# agent works here. If it destroys everything:
git worktree remove ../task-3 --force
Blast radius: exactly one task. Every mistake becomes a two-way door.
Isolated and unambiguous tasks can run at the same time
step-1 ──┬──> step-3 ──> step-4
step-2 ──┘
The plan is a graph, validated by topological sort so nothing can depend on
something that never runs. Code computes which tasks are ready, dispatches those,
and recomputes when one finishes.
Note the order: specify, then isolate, then parallelise. Skip either of the first
two and you get N confidently different answers.
Which of these could you safely stop watching tomorrow?
“It always runs the tests”
“It never touches files outside the task”
“It writes good commit messages”
“It never force-pushes to main”
The ones you can enforce. Three of these are a hook or a worktree. One is a hope.
Level 3 → 4 — done
You stop being the first reader
What you were doing by hand: being the only quality gate, on
everything, serially.
What replaced you: layered gates that run before you look,
bounded so they stop, logged so you can audit, inside isolation so the worst case
is recoverable.
Do this week: add one hook that enforces something you
currently ask for.
Level 4 → 5
And here is where I stop being able to sell you anything
1 No AI
2 Individual ad-hoc use
3 Team-integrated workflows
4 Semi-autonomous + guardrails
5 Fully AI-native
Level 5 means agents owning operational loops end to end. We are not there, and
I’d be lying if I implied otherwise.
What actually defines each level is who verifies the work
Levels 1 to 3 all rely on a human saying “this is
good.”
Levels 4 and 5 delegate verification itself to the system.
The prerequisite for more autonomy isn’t a smarter model. It’s better proof.
The instruction that says “rate this minor” does not hold
We wrote a reviewer that was supposed to emit a specific severity. Across
repeated runs on fixed inputs, it emitted whatever it wanted.
The fix was not a better sentence. It was moving the rule out of the prompt and
into a deterministic check.
Prose is a hint. Code is a guarantee.
We built guardrails so good they made everything worse
Review depth was scaled by how dangerous a change looked. Sensible — until
you notice that editing a prompt file counted as touching the pipeline, so the
cheapest, most reversible changes got the heaviest review.
A one-line prose edit, fully undone by git revert, went through the
full production gauntlet.
It ran like that for weeks before anyone noticed. Nothing
failed. It just quietly made every small change feel like shipping to production.
And our “autonomous” mode is less autonomous than it sounds
Interactive
Auto
Who invokes it
you type the command
you type the command
Task sequencing
one file at a time
one file at a time
Context reset
you clear it
you clear it
Quality gates
you confirm
it decides and logs why
Every row is identical except one. What we automated was
judgment at the gates — not the sequencing, and not the human.
What none of this does
It does not decide what to build.
It does not know which of these two designs you will regret in a year.
It does not know that this service is the one that pages you at 3am.
It does not know when the honest answer is “we shouldn’t.”
Every parallel task is executing your design. Good execution amplifies a bad one.
How this got built
None of it was designed up front
You have just seen four levels in twenty-five minutes, in a tidy order.
That is not how it happened, and if you copy the tidy order you will build the
wrong things first.
Three months, twenty-seven projects, and it ends with a deletion
Started by adopting an open-source
workflow. Not building one.
Then the parts that broke: the handoff
contract between phases, because context was getting lost.
Then gates, because output was landing
that shouldn’t have.
Then isolation and parallelism, because
by then it was safe to run more than one.
Then measurement — what are these
gates costing versus what are they catching?
Then deletion. The most recent project
removed machinery, and the system got better.
One file’s life, in lines
324 lines in May → 1,022 at its peak in July
→ 777 the following week.
The cut removed no rules. It removed machinery.
We adopted the core. We didn’t invent it.
Prompt-Driven Development — an open-source family of agent
SOPs. strands-agents/agent-sop, Apache 2.0, published out of
AWS’s open-source org, built by James Hood and a community of practitioners.
Summarise the codebase → hone the idea into a design → break the design
into tasks → implement each task. The contracts between the phases are
the valuable part — someone already worked out what a design document
must contain for the next phase to consume it.
Our plugin wraps that with the gates and the graph. The
wrapper is ours. The core isn’t, and you shouldn’t reinvent either.
Yours starts as one markdown file
Next time you finish a session where you got something genuinely useful done, open a
fresh session and say: “Look at what I asked for in the previous session.
Capture what worked into a reusable instruction set. Save it as
workflow.md.”
Every layer you have seen today started exactly there and got refined each time it
was reused.
Three rules that survived every level
1. Clear context is your best friend.
2. Deterministic work belongs to code,
not agents.
3. Plan for humans, not agents —
every phase leaves a file you can read, and a door back in.