Read straight through, or jump to the part you need.
Part 1
Where we left off
A 60-second recap of the keynote.
→
Part 2
The double loop
The system, taken apart piece by piece.
→
Part 3
Your turn
Clone it and run the loop yourself.
→
Part 4
Looking ahead
What airborne means — and the one ask.
Appendix · jump ahead
Why it works→
The theory under the loop — five ideas.
Extending this model→
From solo to org — the four moves.
Making it run→
The actual files, and how to run it.
Every claim here is runnable — the repo builds a real app, unattended.
github.com/rishidean/pedal · Self-paced4
A quick caveat
This is one way. Not the way.
There are many ways to build agentic loops. This is a simplified version of what I do. The tools are moving fast, and some of this may even be outdated by the time you finish reading this deck!
Take the principles, not the syntax. The shape of the loop matters more than which file does what.
github.com/rishidean/pedal · Self-paced5
HOW TO READ THE DEMOMINIMAL REPRODUCIBLE CASE
The demo is a repro, not a product.
The app is deliberately trivial, so that the loop is the only variable.
What’s under test
The loop — spec, build, verify, document, state in files. Not the app it happens to produce.
Why it’s small
You strip a system to the smallest thing that still shows the behaviour. Standard practice. Nobody answers a repro with “too small, so the bug isn’t real.”
What scale adds
More context to route, more invariants to protect, more ways to be wrong. That changes the anchors (the deterministic checks; Part 2 names them) — not the shape of the loop.
What it can’t prove
That your worst-case bug is as cheap as mine. That one is real. It gets its own slide in Part 4.
Judge the mechanism first. Then argue about blast radius — I’ll make that argument for you.
github.com/rishidean/pedal · Self-paced6
Part one
Where we left off
A sixty-second recap of the keynote — the continuum, ground vs. air, and how you operate. Then we fly.
What this answers: what the keynote established, and where today picks up.
github.com/rishidean/pedal · Self-paced7
THE AI ADOPTION CONTINUUMRECAP · FROM THE KEYNOTE
Think of AI adoption as modes of transport.
{{ s.markerText }}
{{ s.icon }}
{{ s.num }}
{{ s.name }}
{{ s.desc }}
github.com/rishidean/pedal · Self-paced8
THE AI ADOPTION CONTINUUMRECAP · FROM THE KEYNOTE
Six ways to move. Only some leave the ground.
95% of teams live here
THE 10X LIVE HERE
GROUND AIR
{{ s.markerText }}
{{ s.icon }}
{{ s.num }}
{{ s.name }}
{{ s.desc }}
Ground — same work, fasterAirborne — a different process
github.com/rishidean/pedal · Self-paced9
How you operateRECAP · FROM THE KEYNOTE
The shift from player, to coach, to conductor.
Autocomplete
Player
Linear. You in every step.
Agentic
Coach
Cyclical. You manage the loop.
Orchestration
Conductor
Systemic. You conduct the fleet.
github.com/rishidean/pedal · Self-paced10
The jump we make today
From using agents to code, to building agents that code.
That's the ground-to-air jump — a different process, not a faster tool. The keynote drew the map. Today we fly the first leg.
github.com/rishidean/pedal · Self-paced11
What you'll walk away with
Get airborne.
By the end of this deck you'll understand a multi-sprint, self-verifying, autonomous development loop...and the means to run it yourself.
That system is the harness in the session title: the structure around the model that turns “an AI that can code” into a system that builds software.
github.com/rishidean/pedal · Self-paced12
Part two
The double loop
Some files and a bash script. We'll take it apart piece by piece, and then watch it build an app, unattended.
What this answers: what the system is, and how it runs unattended.
github.com/rishidean/pedal · Self-paced13
THE OPEN SECRET
Agentic Orchestration is a fancy term, for some files + a loop.
github.com/rishidean/pedal · Self-paced14
WHERE THE INTELLIGENCE LIVES
We're shifting the burden from the model to specification & scaffolding.
Model
The engine
Raw capability. Necessary, but the part everyone talks about.
+
Files
The judgment
Standards, specs, and memory. Where your engineering lives.
+
Loop
The discipline
Build, verify, document (repeat until done).
Take any one away and it stops working. And most of what makes it good isn't the model. It's the files (and what we'll cover in the rest of this deck.)
github.com/rishidean/pedal · Self-paced15
WHAT WE MEAN BY AGENTIC
We're going to orchestrate the model to run in a loop.
Many are still thinking about "autocomplete", but they're very different.
↻It is — a loop
●Sets its own intermediate steps
●Calls tools to act, not just answer
●Checks its own work
●Loops until the goal is met
→It isn't — a turn
○Autocomplete on steroids
○A chatbot you babysit turn by turn
○“AI that writes code for you,” one prompt at a time
github.com/rishidean/pedal · Self-paced16
TWO THINGS MODELS DO
It can generate, or it can call.
Only one of these can hallucinate. Knowing which is what makes the loop trustworthy.
Generatecan hallucinate
Text from weights
The model writes the most plausible next tokens from what it learned. Brilliant for synthesis and code — and the only place a guess can sneak in.
prompt→model→plausible text
Callreturns a fact
A tool runs, for real
The model emits a structured request; a deterministic system runs it — code, a search, a test — and hands back ground truth the model then reads.
request→tool runs→fact→model reads
In a loop, most of the work is tool calls returning ground truth not the model free-associating. run-qa’s Playwright test actually ran; the model didn’t decide it passed.A call is an anchor — a result that can’t be argued with.
github.com/rishidean/pedal · Self-paced17
THE PRIMITIVES
A few words to help speak the language.
New to Claude Code? Everything that follows is just some form of these terms.
Session
One run of Claude Code. Fresh memory every time. Nothing carries over.
Context window
The working memory a session holds at once. Finite. Fill it and quality drops.
CLAUDE.md
A context file Claude reads automatically at the start of every session.
Task tool
How a session hands a job to a subagent — and gets the result back. It's how run-qa calls its three agents.
Skill
A reusable procedure Claude can invoke by name — like run-qa.
Command
A saved prompt you trigger with a slash — like /review.
Subagent
A scoped helper for one narrow job. Often a cheaper, faster model.
github.com/rishidean/pedal · Self-paced18
THE SYSTEM
Three parts that mirror what we do IRL.
Overview · the three stages
This map recurs — the next three slides zoom into one stage each.
{{ c.tag }}
{{ c.title }}
●{{ it }}
github.com/rishidean/pedal · Self-paced19
THE TOPOLOGY
One loop inside another.
The outer loop marches through sprints with a fresh brain each time. The inner loop is one session: build → verify → document.
↺ RED → fix → re-run [skill] run-qa (max 3 attempts, then stop)
github.com/rishidean/pedal · Self-paced21
THE LOOP OBJECTIONWHERE THE LOOP LIVES
“I’m skeptical of loops.” You’re already running one.
There are only three places a loop can live. Declining to build one doesn’t delete it — it leaves it in the most expensive place.
03 · Driving · most teams
In your head
04 · Helicopter · you are here
In files
06 · Spaceship · the sequel
In the system
Who runs it
You, in real time
run.sh, from files
The system, from compiled rules
When you stop
It stops
It keeps going
It never needed you
Scales with
Your attention
Your specs
Your corrections
Where the gate goes
Nowhere — you are the gate
On the diff, every sprint
On the equivalence check
“Offloading a full task to an agent” is a loop too — someone else’s, with the control surface hidden.The one you can see is the one you can put a gate in.
github.com/rishidean/pedal · Self-paced22
THE SYSTEM
The setup stage is for our specifications and agreements
Stage 1 / 3 · Setup
Why first: the system can't act until it knows the rules.
Setup
What it knows
●Tech Lead
●PM
●Design
●QA Lead
Actors
Who does the work
●The Builder
●QA Team (x3)
●QA Manager
Orchestrator
What keeps it moving
●Eng Manager
●PM
github.com/rishidean/pedal · Self-paced23
BROAD CONTEXT (CLAUDE.MD · PROMPT.MD)
How we work.
Everything true for every sprint: architecture, conventions, and the definition of done. One constraint forces quality —
"Not done until run-qa returns GREEN."
This is the scaffolding that earns the trust.
CLAUDE.md
# Project architecture & conventions
# Marching orders, every session
## Definition of done
Not done until run-qa is GREEN.
prompt.md
Read the manifest. Pick the next sprint.
Build it. Run QA. Update state.
# same instructions, every time
github.com/rishidean/pedal · Self-paced24
THE MANIFEST (DOCS/ROADMAP.MD)
What needs to get done, where we're at.
One glyph per sprint — that's your state machine. The glyph flips after each sprint. Stuck work marks ⛔ and stops.
This file is your project status.
🔲 not started✅ done⛔ blocked — stops for a human
docs/Roadmap.md
## Sprints — Booking
✅ S1 — App Setup and Shell
🔲 S2 — Ride Request
🔲 S3 — Ride Lifecycle
S2 starts only after S1 passes.
github.com/rishidean/pedal · Self-paced25
How to decompose · docs/Roadmap.md
Slice it vertically, not horizontally.
Weak · horizontal layers✕
# Roadmap
- [ ] Build all data models
- [ ] Build all API endpoints
- [ ] Build all UI screens
- [ ] Wire it together
- [ ] Test everything
Nothing runs until the very end. No verifiable step — nothing for QA to gate.
Good · vertical slices✓
# Booking · vertical slices
✅ S1 The shell runs a real app boots
🔲 S2 A rider gets matched on top of S1
🔲 S3 A full ride completes needs S2
Each slice ships a working app, ordered by dependency. 🔲 ✅ ⛔ legible at a glance.
github.com/rishidean/pedal · Self-paced26
SPECIFIC CONTEXT (SPECS/BOOKING/S*.MD)
What to build this turn.
One spec per sprint: acceptance criteria, technical approach, edge cases. This is where your engineering judgment lives.
At Driving you write code. At Helicopter you write specs.
# S2: Ride Request
Let riders request a pedicab
and get matched to a driver.
No criteria. No edge cases. The build is a guess; QA has nothing to assert.
Fat · explicit✓
# Booking S2: Ride Request
## Acceptance Criteria
- estimate (4 min · $18) shows before request
- matching is its own visible state
- assignment: Maya Chen · PEDAL 14 · ETA 3 min
- state survives refresh (pedal.ride.v1)
## Watch out for
- exactly ONE matching timer may assign (BR-007)
- a storage failure must fail closed (BR-016)
Explicit criteria + the trap to avoid. The build is trivial; QA is decisive.
github.com/rishidean/pedal · Self-paced28
THE SYSTEM
Now, it's time to build.
Stage 2 / 3 · Actors
Why next: someone has to do the work — and check it.
Setup
What it knows
●Tech Lead
●PM
●Design
●QA Lead
Actors
Who does the work
●The Builder
●QA Team (x3)
●QA Manager
Orchestrator
What keeps it moving
●Eng Manager
●PM
github.com/rishidean/pedal · Self-paced29
THE BUILDER
builder · sprint session
$ claude -p "$(cat prompt.md)"
reading context…
building feature…
writing index.html
Executes the spec for a single feature / sprint. Then done.
The Builder is just a Claude Code session — no special framework, no persistent agent. Spun up fresh for one sprint, then thrown away. Its power is that nothing carries over.
Stateless
Clean brain every turn — no context rot from the last sprint.
Self-checking
It calls run-qa on its own work before it ever declares done.
Hands off
Writes its memory to PROGRESS.md so the next session can pick up.
github.com/rishidean/pedal · Self-paced30
THE QA MANAGER
When code is complete, the
manager delegates the QA tasks
One call — run-qa — runs all three QA agents and returns a single verdict: GREEN or RED. RED three times and it stops for a human.
run-qa
→
Lint
→
Review
→
Test
→
GREEN
↺ RED → read failures → fix → re-run max 3 attempts, then mark blocked & stop
.claude/skills/run-qa/SKILL.md
---
name: run-qa
description: Full QA pass — lint, review,
e2e. Returns one GREEN/RED verdict.
---
# run-qa
Run these in order, each as a subagent:
1. Delegate to linter.
2. Delegate to code-reviewer.
3. Delegate to playwright-tester.
Verdict: any lint error, CRITICAL
finding, or failed spec → RED.
Otherwise → GREEN.
If RED: fix, re-run from step 1.
Stop after 3 attempts; report to human.
github.com/rishidean/pedal · Self-paced31
THE QUALITY TEAM
Each team member has a very specific job.
.claude/agents/They check, they don't build — cheaper, faster models.
This is the scaffolding that earns the trust — the answer to the doubt loop from Part 1.
Every verdict is a contract — GREEN / RED · CRITICAL / WARN / NIT — a shape the next step consumes, never prose.
Judgment · latentvsVerification · anchoredTwo anchors and one opinion — lint and tests are deterministic; the reviewer is a fresh-context judgment, and the anchors outrank it.
{{ q.mark }}
{{ q.name }}
{{ q.model }}
{{ q.job }}
{{ q.snippet }}
{{ q.file }}
github.com/rishidean/pedal · Self-paced32
THE INNER LOOP
RED doesn't stop the loop — it routes back to the Builder.
On RED, the verdict carries the actual failures — the Builder reads them, patches, and re-runs. Three attempts, then it stops. RED isn't an opinion — it's a failed assertion; the fix targets a fact, not a feeling.
RED → read failures · fix · re-run
The Builder
Write & fix
Builds the feature. On a RED return, reads the failures and patches the code.
→
run-qa
Verify
Lint · review · test. Returns one verdict — and the failures with it.
→
REDloops back ↑
GREENexits → Document
Three attempts, then it stops. Still RED after the third try → mark the sprint [!] blocked and hand back to a human. Autonomous, never infinite.
github.com/rishidean/pedal · Self-paced33
THE SYSTEM
Close the sprint, and move to the next.
Stage 3 / 3 · Orchestrator
Why last: something has to keep the sprints moving, hands-free.
Setup
What it knows
●Tech Lead
●PM
●Design
●QA Lead
Actors
Who does the work
●The Builder
●QA Team (x3)
●QA Manager
Orchestrator
What keeps it moving
●Eng Manager
●PM
github.com/rishidean/pedal · Self-paced34
KNOWLEDGE HANDOFF
On GREEN, the session writes itself down.
QA GREEN→three writes — roadmap = state · PROGRESS = memory · CLAUDE = learning
## Sprint 3
scaled hire cost.
spend bug → fixed
(guard the spend)
03CLAUDE.md
Promote durable learnings to permanent context.
Learning
## Gotchas
+ score must never go
+ negative — guard spend
A deliberate simplification. In production this handoff is a context-management system writing to several stores — here it’s one file per job, so you can read the whole mechanism in one sitting.
github.com/rishidean/pedal · Self-paced35
THE ORCHESTRATORrun.sh
Ten lines. Dead simple by design.
#!/usr/bin/env bash
set -euo pipefail
MAX=4; n=0
while grep -q '🔲' docs/Roadmap.md && (( n < MAX )); do
$ DEMO_MODE=planted ./run.sh # guaranteed S2 RED → GREEN (planted matching bug)
A fresh session spins up for each sprint — it builds the feature, runs the QA gate, ticks the roadmap, and hands off. Then the next sprint starts with a clean brain. You write specs; the loop writes code.
Stuck or dirty repo?
$ git reset --hard harness # start over from the harness tag
README.md# prereqs, auth, the contract
github.com/rishidean/pedal · Self-paced39
WHILE IT RUNS · THREE SPRINTS
Now go hydrate.
A full run builds three real sprints — installs, tests, a real browser. Watch the console scroll by if you like, or step away, stretch, refill your water, and let the loop cook. It doesn't need you for this part.
// back in a few
github.com/rishidean/pedal · Self-paced40
STEP 3 · WATCHSTEP 3 / 4
What one full run produces — no human at the keyboard.
PLACEHOLDER — record the PEDAL proving run (GIF / MP4 frame): Booking S2 planted bug, RED → GREEN
github.com/rishidean/pedal · Self-paced41
STEP 4 · PLAYSTEP 4 / 4
You didn't write a line of it.
$ npm run dev # then open localhost:5173 — add ?demo=1 for the ride controls
PLACEHOLDER — PEDAL screenshot from the proving run: driver card (Maya Chen · PEDAL 14) on the static city map
Pick the Ferry Building. Request. Watch matching resolve to a driver. Ride, then pay the driver directly. Three sprints, zero keystrokes from you.
github.com/rishidean/pedal · Self-paced42
DEBRIEF
What just happened.
01
Stateless sessions, real progress.Continuity came from the files, not memory.
02
The gate caught a real bug.S2's matching timer assigned twice; the tester caught it, the Builder fixed it. The loop found it - not a model, nor a human.
03
Three sprints, zero keystrokes.You wrote specs; it wrote, tested, fixed, and documented.
The keynote’s thesis, running: specs made intent executable; the gate kept execution governed.
github.com/rishidean/pedal · Self-paced43
LOW FLOOR · HIGH CEILINGEXTENDING THE LOOP
This is the seed. Extend it forever.
Every extension is the same shape — one small file in .claude/. Four moves take you from solo to enterprise; the depth is in the appendix.
the four moves in full →“Extending this model” (appendix)
github.com/rishidean/pedal · Self-paced44
Part four
Looking ahead
What being airborne means for you, the team, and the org — and the single ask that starts it.
What this answers — what airborne means next, and the one ask.
github.com/rishidean/pedal · Self-paced45
WHAT'S NEXT
How it spreads from here.
{{ p.who }}
{{ p.stage }}
{{ p.text }}
github.com/rishidean/pedal · Self-paced46
THE CAPABILITY LADDERHELICOPTER → JET → SPACESHIP
Same craft. Three altitudes.
04 · This repo · You are here
Helicopter
05 · A team
Jet
06 · An org · The sequel
Spaceship
Context
One CLAUDE.md + one PROGRESS.md
Layered & indexed, shared by the fleet
Compiles and maintains itself
Execution
Sequential — one sprint at a time
Parallel — fan out, reduce, verify, synthesize
Self-routing — rule, nudge, or cold model
Verification
One QA gate per sprint
A fresh-context verifier on every edge
Equivalence checks graduate rules
Memory
State lives in files, per repo
Shared state + indexes across builders
Stable patterns compile out as rules
Cost
Full price, every run
Tiered — cheap nodes, strong judgment
Compiled paths run free
Control flow
You write the loop
You + the model draw the graph
The system draws its own
Sequential is a choice, not a ceiling. Everything in this talk is column one — learn the loop before you fleet it. Column three is the next talk.
github.com/rishidean/pedal · Self-paced47
WHERE THIS FLIESKNOW YOUR BLAST RADIUS
Autonomy is priced by what a missed mistake costs.
Not by your seniority, and not by how complex the system is. By what happens when the loop is wrong and nobody notices.
Cheap to missrun unattended
Something below you holds the line
Types, the framework, the database, the platform enforce your invariants for you. The worst realistic bug is transient — restart, resync, gone.
mistake→caught by the floor→restart
Expensive to missgate the diff
You are the invariant
Schema migrations, money movement, concurrency — anything that writes durable state. A missed mistake is silent and permanent, and no restart repairs it.
mistake→durable→no undo
I work high in the stack, where the floor catches me — that is the fair version of the “toy” critique, and it was never that the example was small. The loop still runs down there. The gate just moves: a human on the diff, not on the keystrokes.
github.com/rishidean/pedal · Self-paced48
WHAT AIRBORNE LOOKS LIKE
The secret is that there is no secret. It's just putting in the work.
{{ s.markerText }}
{{ s.icon }}
{{ s.num }}
{{ s.name }}
{{ s.desc }}
Driving — the old way
{{ row }}
Helicopter — what the loop does
{{ row }}
github.com/rishidean/pedal · Self-paced49
THE ACCELERATION
Each shift arrives faster than the last.
Walking
~ years
Biking
~ a year
Driving
months
Helicopter
now
Jet
The advantage compounds. The gap between Driving and Helicopter isn't closing — it's widening.In public: the Bun runtime port — ≈535K lines of Zig → 1M+ lines of Rust in 11 days, ≈$165K of usage against roughly a year of engineering. (The review-burden critique is real — and earned.)
github.com/rishidean/pedal · Self-paced50
THE COST OBJECTIONTOKENS VS HEADCOUNT
You’re not buying tokens. You’re buying the headcount you didn’t add.
“An expensive way to spend tokens” prices the loop against zero. Nothing is priced against zero — price it against the person you’d have to hire.
The real baselineloaded cost
A day of senior attention: $1,500–2,500
Salary, benefits, overhead — before a single meeting eats it. The QA pass and the PM writing the ticket are the same currency.
task→headcount→$$$$
My actual billmeasured, not modelled
A month of heavy use: $500–1,000
Hundreds of hours in Claude Code across a month of real work. Less than one engineer-day — at every corner of both ranges.
spec→loop→verified sprint→$
Cap first: one repo, twenty items → read the usage report → earn the scale, then double.
The honest limit: cost rides usage — at this altitude you pay full price on every run. That isn’t a rebuttal, it’s why Part 2 exists: compiling the stable paths until they run free.
github.com/rishidean/pedal · Self-paced51
THE BUDGET OBJECTIONSEAT VS CAPACITY
$2.5M is only shocking if you booked it as software.
A thousand engineers at $2,500 a month is a real number. The question was never whether it’s big — it’s which line it belongs on.
Booked as a seatindefensible
$2,500 per user, per month
No tool is worth that, and it shouldn’t be. Sat next to Jira and a laptop it loses every time — and that is the comparison being made.
spend→software line→rejected
Booked as capacitythe right line
5–8% on top of a loaded engineer
Against $31K–52K a month of loaded cost, the bar is arithmetic: does it return more than 8%? And $2,500 is already 2.5× my actual spend.
spend→capacity line→8% to clear
And the honest half: if the hours aren’t producing gains, it really is waste.Which is an argument for measuring it — not for skipping it.
github.com/rishidean/pedal · Self-paced52
MY REQUEST OF YOU
90
days.
Every service gets a CLAUDE.md and a run-qa skill.
Pick the most mundane, repetitive task you do every week. That's your first candidate to automate.
Five ideas under the loop — optional reading. Every one resolves to a file you already ran.
github.com/rishidean/pedal · Self-paced55
Why it works01 / 05
A skill stores a process, not content.
A skill file holds a procedure, not facts — how to do a recurring job: run the three checks, return one verdict. The method becomes reusable and versioned, kept separate from any single task it runs on.
that’s the skill→SKILL.md / run-qa
github.com/rishidean/pedal · Self-paced56
Why it works02 / 05
Subagents keep context clean.
Each subagent gets its own context window and exactly one narrow job. The reviewer never sees the builder’s scratch work; the tester starts fresh. Narrow scope means a cheaper model and no cross-contamination.
that’s the QA crew→linter · reviewer · tester
github.com/rishidean/pedal · Self-paced57
Why it works03 / 05
Fresh sessions beat a full context.
A model’s context is finite and degrades as it fills. So every sprint launches a new session with an empty window — the roadmap and PROGRESS files carry state forward, not the model’s fading memory.
that’s the clean brain per sprint→docs/Roadmap.md + PROGRESS.md
github.com/rishidean/pedal · Self-paced58
Why it works04 / 05
The loop improves itself.
When a session learns something durable — a gotcha, a convention — it writes it back into the broad context. The next session starts smarter. The system quietly edits its own instructions.
that’s the Document step→promotes → CLAUDE.md
github.com/rishidean/pedal · Self-paced59
Why it works05 / 05
Generate is latent. Verify is deterministic.
Generation is fuzzy by nature — synthesis, design, judgment. Verification isn’t: the assertion passes or it doesn’t. You never trust the model’s opinion of its own work; you run a tool that returns a fact. The gate is anchored: lint and tests are deterministic; the reviewer adds a fresh-context opinion — and anchors outrank opinions.
that’s why QA is a test→a test, not a vibe check
github.com/rishidean/pedal · Self-paced60
APPENDIX B · GOING FURTHER
Extending this model
The four moves in full — same shape every time, one small file in .claude/.
Appendix · Going furtherEncode judgment · in depth
Add a PLAN phase.
Plan before you build — and, going further, before you spec.
pre-spec runs once
intent
→
PLANauthor
→
docs/Roadmap.md + specs/booking/
→
◇approve
post-spec per sprint
spec
→
PLANbuild
→
plan.md
→
◇approve
→
build
→
QA
→
document
The artifact · concrete
# specs/booking/S2.plan.md
files to touch — RideRequest.tsx, matching timer
order — request state → matching → assignment
approach — one scheduled assignment, cleared on fire
risks — duplicate timer assigning twice (BR-007)
Four files, four jobs
roadmap = state
plan = intent
PROGRESS = memory
CLAUDE = learning
A plan is intent — its own slot, not jammed into memory.
Judgment moves up a rung — you approve plans instead of writing specs. That's the Jet step.
github.com/rishidean/pedal · Self-paced63
Appendix · The principles
The principles, not the syntax.
Commands and flags change. What makes the output good doesn’t.
01
Plan before build.Decide the slice and the spec before a line of code.
02
Verify before done.“Done” means the gate is GREEN — never a feeling.
03
One job per subagent.Narrow scope, cheap model, clean context.
04
Fix, don’t ask.On RED, read the failure and patch — stop only when truly stuck.
05
Promote learnings.Write durable lessons back into the files so the next run is smarter.
This is my way — the syntax will change, but these don’t.
github.com/rishidean/pedal · Self-paced64
APPENDIX C · THE FILES
Making it run
The key file types for this model, and to run the exercises
github.com/rishidean/pedal · Self-paced65
APPENDIX · THE FILESFile 01 / 13
run.sh
The orchestrator — the outer loop (core trimmed for the slide; real file adds logging)
#!/usr/bin/env bash
# PEDAL outer loop. Dumb on purpose: all the
# intelligence is in the files it reads.
set -euo pipefail
MAX_TURNS="${MAX_TURNS:-4}"
# DEMO_MODE=planted swaps the S2 matching fixture first
for turn in $(seq 1 "$MAX_TURNS"); do
if grep -q '⛔' docs/Roadmap.md; then
echo "blocked (⛔). A human steps in. See PROGRESS.md."
exit 1
fi
remaining=$(sed -n '/## Sprints/,/## Current Status/p' \
docs/Roadmap.md | grep -c '🔲' || true)
if [ "$remaining" -eq 0 ]; then
echo "every sprint is done. Take the ride."; exit 0
fi
echo "── Turn $turn: $remaining sprint(s) left. Fresh session."
claude -p "$(cat prompt.md)"
done
github.com/rishidean/pedal · Self-paced66
Appendix · The FILESFile 02 / 13
CLAUDE.md
Broad context — true for every sprint
# PEDAL — Broad Context
## Product
Rider-only pedicab hailing app. Destination → estimate
(4 min · $18) → request → matching → driver assigned →
ride → pay the driver directly. Local, deterministic.
## Read order
README → Vision → FunctionalBrief → Flows →
BusinessRules → Roadmap → the active sprint spec.
BusinessRules governs behavior; Flows governs sequence.
## Technical boundary
Vite + React + TypeScript strict. Tailwind. Typed
reducer. localStorage pedal.ride.v1. Demo controls
only under ?demo=1. No backend, auth, APIs, payment.
## Operating rules
Implement only the states the artifacts define. Never
widen scope. Deterministic fixtures — never random.
## Definition of Done
Not done until run-qa returns GREEN.
Then: results record, roadmap glyph, PROGRESS handoff,
recovery commit with the spec's exact message.
github.com/rishidean/pedal · Self-paced67
Appendix · The FILESFile 03 / 13
prompt.md
Marching orders — read at every session start
# Sprint Session — Marching Orders
You are the Builder for exactly one sprint. Fresh
session, no memory; everything you need is on disk.
1. Orient — CLAUDE.md, PROGRESS.md, docs/Roadmap.md.
Find the first 🔲 sprint. Any ⛔ → stop.
2. Read the contract — the spec, plus Flows.md and
BusinessRules.md for anything it references.
3. Build — only what the spec defines. A missing
product decision? Mark ⛔, name it, stop.
4. Verify — run-qa until GREEN (max 3 attempts).
Still RED → mark ⛔ with the failing check, stop.
5. Document — Test Results Log, docs/results/,
roadmap glyph, PROGRESS handoff, promote learnings.
6. Commit — the spec's exact message.
One sprint per session. The loop handles the next.
github.com/rishidean/pedal · Self-paced68
Appendix · The FILESFile 04 / 13
docs/Roadmap.md
The manifest — one glyph per sprint
# PEDAL Roadmap · ## Sprints — Booking
🔲 S1 — App Setup and Shell — specs/booking/S1-App-Setup-and-Shell.md
🔲 S2 — Ride Request — specs/booking/S2-Ride-Request.md
🔲 S3 — Ride Lifecycle — specs/booking/S3-Ride-Lifecycle.md
S2 starts only after S1 passes. A failed sprint stays
active; the harness may not skip ahead.
github.com/rishidean/pedal · Self-paced69
Appendix · THE FILESFile 04 / 13 · at scale
docs/Roadmap.md
One file, nested — named epics, ordinal sprints
# PEDAL Roadmap
## Catalog «1»
✅ Groundwork artifacts complete, tagged defined
🔲 Booking one full rider journey · active
— Realism DIRECTIONAL — needs Discovery
## Sprints — Booking «2»
✅ S1 App Setup and Shell specs/booking/S1-…
🔲 S2 Ride Request specs/booking/S2-…
🔲 S3 Ride Lifecycle specs/booking/S3-…
gate: S2 starts only after S1 passes «3»
## Current Status «4»
Active Booking S2 — Ride Request
Shipped Booking S1 — shell up, checks green
Next S3 Ride Lifecycle → Realism Sprint 0
1
Named epics.Booking, Realism — real words, never numbers. Session 1's convention, running.
2
Same glyphs, nested.Epics → sprints, ordinals only inside the epic. Each sprint points at one spec.
3
A gate can be human.Not just code — the loop stops and waits for a checkpoint.
4
The living handoff.Current Status is rewritten at the end of every session.
github.com/rishidean/pedal · Self-paced70
Appendix · The FILESFile 05 / 13
PROGRESS.md
The memory — the Builder writes it, sprint by sprint
# Progress Log
// starts empty — one handoff entry appended per sprint:
// what was built · key decisions · gotchas · next-up
github.com/rishidean/pedal · Self-paced71
APPENDIX · THE FILESFile 06 / 13
specs/booking/S1-App-Setup-and-Shell.md
App Setup and Shell
# Booking S1: App Setup and Shell
## What to build
The PEDAL foundation: Vite + React + TS strict,
Tailwind visual system, mobile rider frame, static
city map, typed reducer, deterministic fixtures.
## Acceptance Criteria
- App boots to destination entry — nothing more
- State survives refresh via pedal.ride.v1
- Invalid stored state clears; never crashes
- typecheck · test:run · build · test:e2e all pass
## Technical Notes
- Demo Controls foundation behind ?demo=1
- No ride-request behavior beyond the shell contract
github.com/rishidean/pedal · Self-paced72
APPENDIX · THE FILESFile 07 / 13
specs/booking/S2-Ride-Request.md
Ride Request — the planted bug lives here
# Booking S2: Ride Request
## What to build
Destination → review → request → matching →
driver assigned. Landmark selection; canonical
estimate; deterministic 1,200 ms assignment.
## Acceptance Criteria
- Estimate shows 4 min · $18 before request
- Matching is its own visible state
- Assignment: Maya Chen · PEDAL 14 · ETA 3 min
- Every state survives refresh
## Technical Notes
- Playwright evidence through driver_assigned
- Exactly ONE matching timer may assign (BR-007) —
the planted demo bug violates exactly this
github.com/rishidean/pedal · Self-paced73
APPENDIX · THE FILESFile 08 / 13
specs/booking/S3-Ride-Lifecycle.md
Ride Lifecycle — the epic completes
# Booking S3: Ride Lifecycle
## What to build
Driver arrived → ride in progress → ride complete →
"Pay the driver directly" → reset to a fresh ride.
## Acceptance Criteria
- Demo-mode transitions drive each lifecycle state
- $18 fare + the payment instruction at complete
- Every state restores after refresh; reset is clean
- Full end-to-end verification path passes
## Technical Notes
- Demo controls only under ?demo=1 — honest mocks
- Lifecycle transitions valid only in order (BR-008)
github.com/rishidean/pedal · Self-paced74
APPENDIX · THE FILESFile 09 / 13
docs/results/booking-s1.md
The result record — shape fixed by the spec; the run fills it in
# Booking S1 — Result Record
Outcome Shell boots to destination entry;
state survives refresh
Files created + modified paths, listed
Verification typecheck ✅ test:run ✅ build ✅ e2e ✅
network boundary: local-origin only ✅
Deviations any spec departure, and why it
preserves the contract
Unresolved None — or a named blocker, never
a hidden TODO
Recovery feat(booking-s1): app setup and shell
the commit to return to
github.com/rishidean/pedal · Self-paced75
APPENDIX · THE FILESFile 10 / 13
.claude/skills/run-qa/SKILL.md
run-qa — the quality gate
---
name: run-qa
description: The PEDAL quality gate. Anchors first,
opinion second. One GREEN/RED verdict.
---
# run-qa — the gate
1. Anchors (deterministic):
npm run typecheck · test:run · build · test:e2e
2. The crew (subagents):
linter → code-reviewer → playwright-tester
Verdict:
- Any anchor FAIL or any CRITICAL finding → RED,
every failure listed so the Builder can fix blind.
- WARN and NIT never block. Anchors outrank opinions.
Never weaken a check to reach GREEN. A test that
cannot run is a FAIL, not an N/A.
Three attempts, then ⛔ — a human steps in.
github.com/rishidean/pedal · Self-paced76
APPENDIX · THE FILESFile 11 / 13
.claude/agents/linter.md
Subagent 1 — structure & syntax
---
name: linter
description: Deterministic well-formedness anchor.
tools: Bash, Read, Edit, Glob, Grep model: haiku
---
You check; you do not build.
1. npm run typecheck — record pass/fail with the
first errors verbatim
2. npm run lint, if the script exists
3. Auto-fix only trivial formatting; anything
needing judgment gets reported, never fixed
Report format, nothing else:
LINTER: GREEN | RED
FIXED: <files auto-fixed, or none>
ISSUES: <file:line — verbatim compiler output>
RED only for real failures: type errors, parse
errors, lint errors at error severity.
github.com/rishidean/pedal · Self-paced77
APPENDIX · THE FILESFile 12 / 13
.claude/agents/code-reviewer.md
Subagent 2 — bugs & logic
---
name: code-reviewer
description: Read-only review against the invariants.
tools: Read, Glob, Grep model: sonnet
---
Review the sprint's diff against BusinessRules.md,
Flows.md, and the spec. Never modify files.
Hunt in priority order:
- Boundary violations — network, auth, payment,
random values. Always CRITICAL (BR-013/014).
- Invariant violations — one matching timer (BR-007),
lifecycle order (BR-008), fail-closed storage (BR-016)
- Persistence contract — pedal.ride.v1
- Logic bugs & unmet acceptance criteria
Return findings as CRITICAL / WARN / NIT, file:line
each. RED only when a CRITICAL exists. If the diff
is clean: GREEN, zero findings, stop.
github.com/rishidean/pedal · Self-paced78
APPENDIX · THE FILESFile 13 / 13
.claude/agents/playwright-tester.md
Subagent 3 — behavior & acceptance
---
name: playwright-tester
description: Behavioral anchor — acceptance criteria
in a real browser.
tools: Bash, Read, Write, Edit, Glob, Grep model: sonnet
---
Author tests for any acceptance criterion not yet
covered, then run npm run test:e2e. Deterministic
fixtures, deterministic tests — no arbitrary sleeps.
Key scenarios for Booking S2:
- Estimate (4 min · $18) shows before request
- Matching state observed BEFORE assignment
- Exactly one assignment fires (BR-007)
- Driver card: Maya Chen · PEDAL 14 · ETA 3 min
- Every state persists across refresh
- Network boundary: local-origin requests only
Return "GREEN" if all pass, else "RED" plus, per
failure: test name, failed assertion, actual result.
github.com/rishidean/pedal · Self-paced79
APPENDIX D · OBJECTIONS
Fair questions
The pushback this deck hears most — with straight answers. Take them into your own Q&A.
github.com/rishidean/pedal · Self-paced80
Appendix · ObjectionsFair questions · 1 of 2
The gate answers most of them.
“It’ll game its own metric”
The gate is an anchor, not the loop’s metric
·tests ran — or they didn’t
·specs set the bar, not the model
·[!] escalates to a human
“Models can’t grade their own work”
Correct — so they never do
·worker & verifier never share context
·lint + tests anchor the verdict
·the harness is built from distrust
“What if a step fails silently?”
A 3-character state machine can’t
·[ ] → [x] → [!] — nothing else
·max 3 attempts, then stop
·[!] blocked → a human steps in
“Isn’t context the hard part?”
Yes — deliberately out of scope
·this talk assumes context exists
·layered context → the sequel
·one boundary, drawn on purpose
If you don’t trust the model — good.Neither does the harness. Your distrust is the architecture: it’s called the QA gate.
github.com/rishidean/pedal · Self-paced81
YOU MAY HAVE HEARDLOOPS VS GRAPHS
“Loops are dead. Graphs won.” — look again.
The loop you just met, relabeled in graph vocabulary. It was a graph the whole time.
Nodes
Build · Verify · Document — one bounded job each.
Conditional edges
The GREEN / RED verdict routes the flow. RED cycles back — bounded at 3.
Checkpointed state
docs/Roadmap.md · PROGRESS.md · CLAUDE.md— the run survives any session.
Traversal engine
run.sh — every graph framework runs a loop underneath.
An edge is real only if data moves across it — and every arrow here carries data. By the graph crowd’s own rule, “a loop is fine.” Loops buy depth; graphs buy breadth — Jet is this, fanned wide.
github.com/rishidean/pedal · Self-paced82
APPENDIX · OBJECTIONSFAIR QUESTIONS · 2 OF 2
“Fine for toys — our system is much more complicated.”
PEDAL is a pendulum, not a bridge. Nobody says gravity only applies to pendulums.
What scales unchanged
The invariants
Thick specs make building trivial. Anchored gates catch what generation hallucinates. State survives in files. None of this cares how big your system is.
What your complexity becomes
The specs and the gates
Edge cases, tribal scar tissue, the rules an optimizer would bend — that content comes from senior engineers and nowhere else. The complexity objection is the job description.
Receipts, if pressed: the Bun port — a year of work in eleven days, in public · the fan-out-and-verify diamond running in production inside Claude’s research feature · three communities converging on file-based state and deterministic gates without ever meeting.