Shipping Reliable Products

Engineering playbook · workshop companion

Shipping Reliable Products

Agents made the typing cheap. They did not make the thinking cheap. This workshop is about the engineering basics that let you, and the agent working beside you, get through the problems that still show up.

Everyone is a product engineer. The agent is your colleague, and it is your job to make its life easier.

Scope individual level only Format talk + live demos + estimation exercise Pillars Product engineer · Mythical Man-Month · No Silver Bullet
Two inks run through the page: you what stays with the human agent what the agent needs from you

Run of show · Wed 28 Oct · 19:30–22:00 IST · online

Two and a half hours, two agent runs, one ticket

The talk sections are in the order below, which is not the page order: the listing opens with how coding agents work, so the harness loop goes first and the pillars follow it. Everything hands-on happens inside the two runs.

What the check-in says (n = 12, as of 27 Oct)

Nine L3/L4s who use a terminal daily and three L1/L2s who barely have; seven of twelve want "parallel agents, automation, custom tooling"; five of twelve debug by pasting the error back or starting over. Six engineers, two growth, two founders, one PM, one data. Only three work in a large production codebase.

What they wrote in the free-text box, and where it lands

  • Want to know more about the stack you use06 Greenhouse · speaker's desk
  • What's the optimised and effective way to use Claude Code? FOMO browsing X… how to keep up as an applied AI engineer?03 No Silver Bullet · new beat below
  • Shift away from the Codex UI to the command line… automate repetitive tasks, agents for them05 tool choice · trust ladder · webhook agent
  • As a solo builder, need to check anomalies before AI, prompt, code better04 review for understanding · testing skill
  • Agentic SDLC process and one project setup07 workflow · 06 repo layout
  • Move beyond chat and apps to building something real from scratchtrust ladder rung 1 · first-rung aside
talk 55 minagent runs 50 minharness deep-dive 20 minquestions 20 minbreak 10 minclose 5 min
  1. 19:3010
    How coding agents workThe loop in eight lines, context assembly, who decides what the model sees and remembers, and what a turn costs: the prefix cache, what breaks it, what compaction throws away. Live: tail a pi session log while it runs one tool call, then /usage in Claude Code to show the hit ratio.
  2. 19:4015
    Prompting vs engineering, and the ten tenetsFraming, personal-level scope, everyone is a product engineer. Tenet 6 gets the extra minute: how well do you interview your users. One sentence on parallel agents: explore in parallel, commit serially, and why.
  3. 19:5515
    Brooks, twiceAntoine's menu, the 1/3–1/6–1/4–1/4 rule, the surgical team remapped, then essence vs accident, ending on the "keeping up without FOMO" beat. Two-minute chat poll: estimate the ticket with the fractions.
  4. 20:1030
    Run 1 · pi · from fresh clone to a passing expect test hands-onOpens with a two-minute tour of the speaker's desk (cmux: pi, Claude Code, logs and a browser pane side by side). Attendees clone Greenhouse alongside. just up with nobody at the keyboard. Then the ticket is planned inside Greenhouse itself: just plan GH-12 opens a plan room, two exploration threads try the two ways to model a resolved thread, and the decision comes back as an interactive report in the plan, not a three-option prompt. Pick one, then the domain half: just new command ResolveThread, event, projection, expect snapshot reviewed as prose.
  5. 20:408
    Questions, round oneTaken while the e2e replay runs in the background, so the wait is not dead air.
  6. 20:4810
    BreakLeave the Stagehand flow running on screen; people come back to a browser driving itself.
  7. 20:5825
    Run 2 · Claude Code · from UI to a merge-ready PR hands-onThe ticket's UI half under impeccable and the animation skills: the resolve action on a comment thread and the decision appearing in the log, linked to its block. One Stagehand flow, then just review with a different model: correct code that is wrong, caught. PR opened with the agent's walkthrough attached, and the plan room shows the decision that led to it.
  8. 21:237
    Questions, round twoUsually about tools. The pi / Claude Code / Codex / Amp table answers most of them.
  9. 21:3020
    Durable and multiplayer: the harness in the cloudThe two-kinds-of-durability table first (Claude Code resumes a conversation; pi-durable resumes a run). Then kill -9 mid tool call, same requestId, resume; second client on viewState; the Durable Object + container version. Webhook-triggered review agent as the finale.
  10. 21:507
    Released, and then changed under real usersThe workflow in one slide, the release checklist, then the four live-product questions at one minute each: versioning events, flags vs versions, rollouts, bugs the agent can reproduce. Depth is on this page; the talk only names them.
  11. 21:573
    Last questions, takeaways, repo linkStarter repo, this playbook, the checklist. You are the gardener.

Buffer: Run 2 and the harness segment are the two places most likely to overrun. If 21:30 arrives and Run 2 is not done, skip the multiplayer live demo and show the recorded one; the release segment is a promise on the listing and should not be cut.

The day before: one full dry run

Run the whole show once, end to end, with a timer. Fix the skills where they misfire rather than noting it. Then:

  • Greenhouse is in prod on Cloudflare, with GH-12 behind a flag that is off. The release segment flips it live.
  • Rollback rehearsed: the flag-off command and the Workers version rollback command are in docs/RELEASE.md, with the current version id filled in.
  • Multiplayer harness recorded as the fallback: kill, resume, second device, cloud sandbox, webhook review. Five minutes, no narration needed.
  • Planted bug still plants. Confirm the first-pass author actually produces ThreadClosed, or seed it in the branch so the inverted review has something to catch.
  • Fresh-clone timing measured on a clean machine: if just up is over three minutes, attendees watch Run 1 and follow along only in Run 2.
  • Skills pinned by commit so a third-party update the morning of does not change behaviour on stage.
  • Model inversion configured: just review uses a different provider than whichever tool authored, and the API keys are in the sandbox.
  • cmux workspace saved with the four panes and the sidebar in the order of the show.
GH-12 · the real ticket · worked through in both runs

Resolve a comment thread into a decision

In a plan room, someone leaves a comment thread on a block ("should retries live in the client or the wrapper?"). People and the agent reply. Today the thread just ends. It should end in a decision: who decided, when, what was chosen, and the block it changed, and that decision should stay attached to the block as the plan keeps changing. This is Chopin's "decision ownership" problem, as one ticket.

  • Domain (Run 1): ResolveThread command, ThreadResolved and DecisionRecorded events, decision-log projection updated. Invariant: a decision references exactly one thread and one block, and a resolved thread cannot be resolved twice. Expect test: command in, events out, read as a story.
  • UI (Run 2): a resolve action on the thread, a one-line "what was decided" field, the decision appearing in the log and as a marker on the block. One Stagehand flow: open a plan, comment, resolve, see the decision in the log.
  • Review: a different model reviews the branch against GLOSSARY.md. Planted bug: the first pass names the event ThreadClosed, which passes every test and breaks the vocabulary.
  • Done means: expect and e2e green, one Stagehand flow green, glossary updated, PR opened with the agent's walkthrough, release checklist attached. And the plan for GH-12 itself, in Greenhouse, shows the decision that chose the modelling.

00 · Framing

Prompting vs engineering

There is no right way to do AI coding. There are many things you can use, and every path leads to tech debt, because any code committed is tech debt. An arrow shot cannot be taken back. What changed is who shoots and how fast.

In the rush, we quietly dropped a lot of the engineering practices that got us here. The pitch of this workshop is simple: those practices were never about typing speed. They are about keeping a system legible to whoever works on it next, and the agent is now whoever works on it next.

Agents are a new primitive. Machine empathy, the thing that made you a good engineer for the computer, now extends to agent empathy. A good agent experience still needs great developer experience underneath it, and it needs updating as models change.

Personal level · in scope

A very good bump in what one person can do. This is where the basics pay off fastest, because one person can change their own habits tomorrow.

Team level · out of scope today

Huge variance in how teams do this. Deliberately left for another session; nothing here depends on a process change.

A working definition for the day: an agent will cook. Whether what comes out is edible depends on your intent, and intent is an engineering artefact.

Pillar 01

Everyone is a product engineer

Features are not asks. Any code that makes money is good code. Your job is the outcome, and the agent only knows the outcome you managed to write down.

Features ≠ asks
An ask is what someone typed in a ticket. A feature is the change in the user's day. The agent will faithfully build the ask; translating it into the feature is yours.
Outcome over output
"Any code that makes money is good code" is only half a joke. If the measure is the outcome, then verifying the outcome, not the diff, is the work.
Intent is the input
Prompts, plans, tests, types and docs are all the same thing: ways of writing intent down so a second brain can act on it without you in the room.

The ten tenets of a product engineer

The core ideology. None of these are about tools; every one of them changes what the agent gets handed.

  1. 01
    Understand the problem spaceThe agent only knows the problem you managed to describe. Time spent here is the planning third of Brooks's schedule.
  2. 02
    User, machine and fellow-dev empathyAdd a fourth: agent empathy. The next reader of your code is as likely to be a model as a colleague.
  3. 03
    Think in outcomes, not outputOutput is now nearly free. If you measure yourself by it, the agent will happily bury you in it.
  4. 04
    Be comfortable with ambiguityAgents are not. Resolving ambiguity before you hand work over is the highest-leverage thing you do all day.
  5. 05
    Ship fast, think and act slowlySlow is smooth, smooth is fast. The agent supplies the fast; you supply the slow.
  6. 06
    Talk to users who use your productOr to your ideal customers. How well do you interview your users? No agent can do this for you, and everything downstream depends on it.
  7. 07
    Always use your productDogfood. The agent can run the tests; it cannot feel the friction. That is the review only you can give.
  8. 08
    Connect the dotsAcross the codebase, the user's day and the business. Agents see one context window; you see the whole board.
  9. 09
    Use LLMs to augment your learningAsk the agent to explain why it did the thing. The point is that you understand more at the end of the session, not less.
  10. 10
    Develop taste in code, design and UXTaste is what you review with. Without it, every agent suggestion looks equally fine.

Pillar 02 · Frederick P. Brooks Jr., 1975

The Mythical Man-Month, read by one person

The book is about teams. Almost every chapter still applies when the "team" is you and a few agent sessions.

Good cooking takes time. If you are made to wait, it is to serve you better, and to please you. Menu of Antoine's, New Orleans · the book's opening epigraph

Agents collapsed the wait. The cooking still takes the time it takes, it just moved from the keyboard into planning, testing and reading. If you spend none of it, you get the coin toss.

Estimation and optimism

Brooks's claim in chapter two: the two things that sink software are optimism and bad estimation, and they are the same thing. Software engineering is optimistic by nature. We rarely thought through the outcome before; agents give us even less reason to pause.

Brooks's rule of thumb for a schedule

Coding was already the smallest slice in 1975. Agents shrink it further. The other five sixths are still yours, and if you treat the coding slice as the whole job, your estimate is off by a factor of six before you start.

The surgical team, remapped

Chapter three describes Harlan Mills's proposal: one surgeon who owns the design, surrounded by specialists who keep the surgeon's hands free. It is the first description of a person working with a staff of helpers who do not share authorship. Note what the team is not: it is not ten surgeons operating at once. Here is the roster with today's cast.

Role in Mills's teamFilled byWhat it means at your desk
SurgeonyouOwns the problem, the design and the final call. Conceptual integrity lives in one head.
CopilotagentKnows the design, argues with it, writes a lot of the code. Does not own it.
AdministratoryouEnvironment, tooling, access. Make things easy to run anywhere, for yourself and for the agent.
EditoragentDocs, comments, changelogs, the "why" behind a change, written and kept current.
Program clerkagentReview passes, skill and prompt writing, bookkeeping of what was tried.
Toolsmith, tester, language lawyersharedAgents do the volume; you decide what counts as a passing test and which idioms are allowed.
Brooks's law
Adding people to a late project makes it later. Adding agent sessions to a confused task makes it more confused, because every session routes its questions through the same person: you are the communication overhead now.
On parallel agents
A position: parallel exploration, serial commitment. Threads that each implement a different option before you decide are cheap and worth it; that is Appleton's "making contact with reality", and it needs no git branches or worktrees when each thread is its own implementation you open in a portal and compare. What Brooks rules out is the other thing: several agents building the committed version of one ticket at once. Coding was one sixth of the job; a fan-out there speeds up the sixth and multiplies the five sixths you still owe, each agent holds partial context, and the merge is where correct code becomes wrong. So: many threads to explore, one thread to build, one inverted reviewer after.
One day at a time
"How does a project get to be a year late? One day at a time." Agents hide slippage well, because something always got produced. Keep milestones small and visibly true or false.
The second system
The gold-plated version was always tempting; now it is also cheap to generate. The discipline of leaving things out is a human one.
Plan to throw one away
Finally affordable. Let the agent build the first version to learn the problem, then throw it away on purpose rather than by accident.

Pillar 03 · Brooks, 1986

No Silver Bullet

Brooks split the difficulty of software into essence and accident, and predicted no single technique would give a tenfold gain. Coding agents are the strongest attack on accident we have seen. The essence did not move.

Accidental difficulty

agent takes most of this

  • Syntax, boilerplate, glue code
  • Looking things up, remembering APIs
  • Mechanical refactors, test scaffolding
  • Translating between languages and formats

Essential difficulty

you still hold all four

  • Complexity: the shape of the data and its invariants
  • Conformity: the messy world the software must match
  • Changeability: what users will ask for next
  • Invisibility: nobody can see the whole system, including the agent

Agent complexity is hill climbing. Given a hard target the agent takes shortcuts, and it cannot reliably do well on things it cannot see. So the practical reading of No Silver Bullet is not pessimism. It is a to-do list: everything that shrinks the essence for a human also shrinks it for the agent.

Brooks's "promising attacks", thirty years on

Buy, don't build
Boring, opinionated frameworks are slower to start and better to live in. Rails-style "one way to do the right thing" is exactly the constraint an agent needs. Read the docs for the platforms you deploy to; people get burned by serverless and cloud pricing when they let the agent configure it blind.
Rapid prototyping
Align visually. Show me, don't tell me, and no walls of text. A rendered screen is a far better requirements document than a paragraph, for both of you.
Grow, don't build
Loops with forward and backward pressure: plan, build, verify, feed what you learned back in. Let the work compound across sessions instead of starting from zero every time.
Great designers
Brooks's last hope was cultivating great designers. That is now the only role you cannot delegate. You are the gardener.

Keeping up without the FOMO

One check-in said it plainly: watching the timeline, it feels like everyone else is doing unbelievable things, and the question is what it takes to catch up. No Silver Bullet is the answer, and it is a kind one. Every tool on the timeline is an attack on accidental difficulty, and a good one, but the gain any single tool can give you is bounded by how much accident is left in your work. The essence (knowing what to build, the shape of the data, what correct means) is where the compounding happens, and none of it expires when the next tool ships.

What to keep up with

Your own loop: how fast you get from intent to a verified change. Measure it on your repo, not on a demo. One new tool a month, tried on a real ticket, kept only if the loop got faster.

What to let go of

Leaderboards, model launches, other people's thirty-second clips. A harness is six lines of plumbing; the unbelievable thing in the clip was usually the basics you already know, applied by someone who did not skip them.

04 · Playbook

The basics that carry you and your agent

Ten practices, none of them new. Each one is written twice: what it does for you, and what it does for the agent you hand your codebase to.

1. Make it run anywhere

DX is agent DX
you

A repo that runs locally with one command is the difference between a two-week onboarding and a two-hour one. One team spent two to three weeks on a single problem: getting a repo to run on a laptop.

agent

If the agent cannot run the thing in its own environment, you become the test harness. Every check routes through you.

  • Postgres locally, config in env files, no shared staging dependency for everyday work
  • Object storage behind a local stand-in (MinIO for S3), fixtures that seed a believable state
  • Twelve-factor for web services is still the cheapest checklist for this

2. Types as the design language

Make illegal states unrepresentable
you

Picking the right shape of data is most of the design. Types are where you write the invariants you would otherwise carry in your head.

agent

A whole class of mistakes cannot be generated: null dereferences, out-of-bounds access, data races, states that make no sense. The compiler is feedback in milliseconds with no prompt.

  • Application-specific invariants get their own types, not a comment
  • Anti-slop rules for your language live in the type config and lint config, not in a prompt the agent may skim

3. Tests the agent can learn from

Agents thrive on feedback
you

Software is brittle. Committed examples prove intent in a way prose cannot, and they survive you forgetting why.

agent

Feedback in milliseconds beats feedback in a code review. The faster and more deterministic the loop, the better the agent climbs.

  • No unit tests for their own sake. Three layers instead: expect tests at the library level, event-replay end-to-end through the domain, and Stagehand for the few browser flows where the browser is the point
  • Expect tests (point at something, snapshot the result) are the legible kind: a human can read the output and say "yes, that". Deterministic, with simulated clocks and networks for anything distributed
  • Example-based over clever: the committed example is the documentation

4. Keep it simple, three times

Simple code · simple components · simple tech choices
you

Simplicity is what makes the bus factor survivable, and the bus is now also "the model changed".

agent

Agents do well on well-trodden paths. Every unusual choice is a place where the agent will confidently guess.

5. Review for understanding, not for approval

Your understanding ↔ the agent's understanding
you

Review is where you check that the code matches the product, and that you could still explain it. Walk through it. Break features into stacked PRs. Ask questions interactively.

agent

Ask the agent to tell you why it did the thing. Markdown works; a short recorded walkthrough works too. If it cannot explain the change, treat that as a finding.

  • Correct code can be wrong. A diff that passes every test can still contradict how the codebase is supposed to work. Review against context, not just the diff.
  • Review agents fail in predictable ways: missed bugs, missing context, expensive runs, nitpicky comments, and more runs producing more "bugs". Tell them to skip the nitpicks; real bugs are rare and that is the point of the review.
  • Model inversion: author with one model, review with a different one. The two have different blind spots.

6. One vocabulary, three speakers

Domain-driven design
you

DDD's ubiquitous language is the oldest trick for this: the words in the code are the words in the conversation with the user. No translation layer where meaning leaks.

agent

The agent learns the domain from your identifiers. If Order, Booking and Reservation all mean the same thing, it will invent a fourth. Name the concept once and the agent speaks it back to your user.

  • Bounded contexts tell the agent where a word stops meaning what it meant
  • Put the glossary in the repo, next to the code, where both of you read it
  • When a user's phrase does not map to a type, that is a design finding, not a naming chore

7. Event sourcing: end-to-end without the browser

Make the data visible
you

Spreadsheets won because the data and its flow are visible. Event sourcing gives a service the same property: the log of what happened is the system of record, and you can read it.

agent

Browser-based e2e tests are slow, flaky and expensive for an agent to iterate on. With an event log, an end-to-end test is "replay these commands, expect this sequence of events". Deterministic, fast, and the expected output is legible text.

  • Pair event sourcing with the expect idiom: the snapshot is the event stream, and a human can review it like a story
  • Audits and consistency checks over the log let the agent verify its own work without you standing over it
  • Keep the browser for the handful of flows where the browser is the point

8. Keep a living wiki

Codebase context
you

The decisions that are not in the code are the ones that get re-litigated. Write down the why once.

agent

Agent instructions, skills and project notes are a living wiki whether you call it that or not. Feed user feedback and post-mortems back into it so the next session starts smarter.

9. Read the docs

No substitute
you

For the tools you use and the platforms you deploy to. The agent's knowledge of them is a snapshot; yours can be current.

agent

Point it at the actual docs. Guesswork about a platform's pricing or defaults is how a weekend project becomes an invoice.

10. Climb the trust ladder

Earn autonomy one rung at a time
you

What you know, you know. What you don't, you don't, and there are unknown unknowns. Clarity of thought is not always there; experimenting is how you work it out.

agent

Agents can see screens and drive computers now, so they can verify their own work. Let them, in a sandbox, before you let them touch anything with consequences.

  1. Small, vanilla agent start here
  2. Add plugins and skills your conventions
  3. Add connectors (MCPs) your systems
  4. Deploy to the cloud unattended

Building your own small harness, even a toy one, is still the fastest way to understand what a coding agent is actually doing.

05 · Choosing your agent

Pick the tool for your platform, not the leaderboard

There is no right way to do AI coding, so there is no right tool. For an individual the choice turns on where your code runs, how much of the harness you want to own, and what you need to be able to inspect.

ToolShapeFits an individual who…Speaker's view
piSmall, vanilla, hackable harnesswants to understand what a coding agent does, and build up plugins, skills and connectors one rung at a timeto be added
Claude CodeTerminal-first agent with skills, hooks and subagentslives in a repo and a shell, wants long autonomous runs and a way to encode conventionsto be added
CodexCloud sandboxes plus a CLIwants parallel tasks running away from their laptop, each in its own environmentto be added
AmpCodeEditor-integrated agent with shared threadswants the agent inside the editor and a record of sessions to go back toto be added
Platform first
Where does the code run, and can the agent run it there too? The tool that can execute your stack in its own sandbox saves you from being the test harness.
Harness ownership
How much of the loop do you want to see and change? A small harness teaches you the mechanics; a large one gives you more out of the box and hides more.
Legibility
Can you get the "why" out of it afterwards? Threads, transcripts, plans and diffs you can read later matter more than the benchmark score.
Model inversion
Whichever you pick to author with, keep a second model around to review. Different tools make this easier or harder.

The shapes above are a starting point; the speaker's own views on each go in the last column.

The speaker's desk

Everything in the two runs happens in cmux, a native macOS terminal built on libghostty with a multiplexer made for agents: each agent in its own pane, a sidebar of workspaces showing what each one is doing, a ring and badge when an agent needs input, and an embedded browser pane so the agent can look at the app without leaving the terminal. brew install cmux.

// cmux workspace: greenhouse
┌──────────────────────────┬──────────────────────────┐
│ pi · domain half         │ claude code · ui half     │
│ just new command …       │ impeccable + animations  │
│ expect snapshots         │ stagehand flow           │
├──────────────────────────┼──────────────────────────┤
│ process-compose logs     │ browser pane             │
│ db · minio · api · web   │ the app · agentation     │
└──────────────────────────┴──────────────────────────┘
sidebar: greenhouse · harness · review-bot   (badge = needs you)
Why not tmux
Notifications. One agent is working at a time, but it is not the only thing on the desk: a pane that rings when the agent needs you beats a pane you forgot while reading logs.
Panes are roles, not parallel building
Author, reviewer, logs, browser. Exploration threads run elsewhere (a portal, not a pane) and report back; the two agent panes never build the committed version of one ticket at the same time: pi does the domain half, then Claude Code does the UI half, then the reviewer runs.
The browser pane
Where Agentation runs: point at the thing that looks wrong, copy the structured note, paste into the agent pane next to it.
Speaker's additions
to be added: dotfiles, keybindings, what is in AGENTS.md globally

06 · Reference project

Greenhouse

One small repo that does everything the playbook asks, so each practice can be shown running instead of described. Greenhouse is a planning room in the spirit of GitHub Next's Chopin: a place where people and an agent write a plan together, and every decision in it is owned, dated and attached to the part of the plan it changed. Clone it, just up, plan the ticket inside it, then hand the plan to pi or Claude Code and watch the basics do their job.

Why this and not a CRUD app

Chopin names three gaps in how we plan with agents: plans are not interactive, decisions have no owner, and agents explain in text when a picture would do. A tool that fixes those is also, conveniently, the perfect specimen for this workshop. Decisions are events, so event sourcing is the obvious model rather than a flourish. A plan room with people and an agent in it is the multiplayer harness, so the harness demo and the product are the same code. The agent-built artifacts from the planning skills below have a home to live in. And you dogfood it on stage: the ticket for Greenhouse gets planned inside Greenhouse.

Scope, honestly. Chopin is months of work by two people and includes a real-time collaborative MDX editor, research blocks, and GitHub-repo organisation. Greenhouse is the smallest cut that still proves the point: block-level plans (no character-level co-editing; each edit is an event, last writer wins per block), comment threads, a decision log, an agent that participates through the same commands as a person, embedded artifacts rendered from Markdown, and an MCP server so any coding agent can read the plan and write decisions back. Deferred: CRDT text editing, presence cursors, research blocks, multi-repo. Chopin itself is open source (githubnext/chopin); the point here is not to clone it but to build the thin version on the stack below so every practice is visible.

The domain: a plan room

A plan belongs to a repo. It is made of blocks. Anyone in the room, human or agent, can edit a block, open a comment thread on it, or ask for an exploration. Threads end in decisions. Decisions stay attached to blocks. That is the whole model, and it needs a real vocabulary, an event log, auth, a file store for artifacts, and an agent in the loop.

// the ubiquitous language, as types the user would recognise
Plan         — a document tied to a repo; a stream of events
Block        — a unit of the plan: prose, artifact, or research
Thread       — a comment thread anchored to one block
Decision     — how a thread ended: who, when, what, which block
Exploration  — an agent thread implementing one option, reporting back
Artifact     — an agent-built interactive thing embedded in a block
Participant  — a person or an agent; same commands, same rights

// commands anyone issues      // events that get recorded
EditBlock       ───────────▶  BlockEdited
OpenThread      ───────────▶  ThreadOpened
Reply           ───────────▶  ReplyPosted
ResolveThread   ───────────▶  ThreadResolved ──▶ DecisionRecorded
RequestExploration ────────▶  ExplorationStarted … ExplorationReported
AttachArtifact  ───────────▶  ArtifactAttached
ForkPlan        ───────────▶  PlanForked        // a branching entry point, not a dead end

Three speakers, one vocabulary: the person says "resolve this thread", the code says ResolveThread, and the agent, reading the repo, says the same thing back. The agent is a Participant, nothing more: it holds no command a person cannot issue, which is also how you keep it honest.

The stack: good enough, boring on purpose

LayerChoiceWhy it is good enoughPractice it shows
runtimeBun + TypeScriptOne toolchain for scripts, server and tests. Fast enough that the feedback loop stays in milliseconds.run anywhere
frontendTanStack StartRouter, Query and Form from one family; file-based routes the agent can navigate without a map.simple components
editorBlock-level Markdown, rendered with embedded artifactsEach block is plain Markdown; an artifact block is a self-contained HTML file in an iframe. No MDX compiler, no CRDT: edits are events, which is simpler and already gives history and forks.simple tech choices
realtimeDurable Object per plan, WebSocket fan-outThe plan's event stream lives in one DO; every open tab subscribes. Same mechanism the harness uses for sessions, so there is one way to do live.event sourcing
uishadcn/ui + TailwindComponents live in your repo as plain code, so taste is applied by editing, not by overriding a library.taste
backendEffectServices, layers, typed errors, schemas. The type system carries the invariants and the agent cannot forget to handle a failure.types as design language
schemaEffect Schema, sharedOne definition of Decision used by the API, the UI, the MCP server and the tests. The vocabulary cannot drift between layers.one vocabulary
dbPostgres + DrizzleDrizzle schemas are readable TypeScript and migrations are plain SQL; both are legible to a reviewer and to the agent. Wired through @effect/sql. Local Postgres from Nix; in prod a hosted Postgres (Neon) reached through Hyperdrive.make the data visible
eventsAppend-only events tableNo event-store product. One table, one append, projections as Effect programs. Enough to replay and to test.event sourcing
authBetter AuthSessions, OAuth and passkeys in your own DB, no third-party dashboard to configure out of band.simple tech choices
filesS3 API, MinIO locallyArtifacts and exploration reports go to a bucket. Locally that bucket is MinIO, in prod it is R2. Same code path, same S3 client.run anywhere
agentpi-durable harness, one per plan roomThe room's agent is a durable pi session whose tools are the same commands people have, plus the planning skills. It runs explorations, builds artifacts, and resolves threads when asked. Mockable in tests by replaying its stream.legibility · trust ladder
mcpGreenhouse MCP serverAny coding agent (Claude Code, Codex, Amp) can read a plan, list open decisions, and write a decision back. Plan in Greenhouse, implement anywhere, review against the plan.one vocabulary
localNix flake + process-composePostgres, MinIO, mail catcher and the app start from one just up. Works on a fresh laptop and inside an agent sandbox.DX is agent DX
deployAlchemy on CloudflareInfrastructure as TypeScript in the same repo: Cloudflare.Website.TanStackStart for web and api on Workers, R2Bucket, Hyperdrive to Postgres, Durable Objects for sessions, secrets. The agent can read the deploy, not just the code.read the docs
coding agentspi + Claude Code, via the skills folder and the MCP serverSame skills consumed by both. pi for the harness walkthrough, Claude Code for the long runs; both read the plan through MCP rather than being pasted a wall of Markdown.trust ladder

Deploy footnote. Cloudflare is the easy path here: Alchemy's TanStack Start adapter is first-class on Workers, R2 speaks S3 so the MinIO code path is unchanged, and Durable Objects give pi-durable a per-session home for free. The one thing Cloudflare does not have natively is Postgres. Two honest options: keep Postgres (local from Nix, hosted Neon in prod, Hyperdrive in between) for full local/prod parity, or move to D1 and SQLite everywhere. The page assumes Postgres; D1 is a smaller, cheaper demo if the audience will not care about parity. Agent sandboxes run as Cloudflare Containers through the Sandbox SDK.

Repo layout

greenhouse/
├── flake.nix              # postgres, minio, mailpit, bun — one env everywhere
├── process-compose.yaml   # what `just up` starts
├── justfile               # the only commands anyone (or any agent) needs
├── alchemy.run.ts         # workers, r2, hyperdrive, durable objects, secrets
├── packages/
│   ├── domain/            # Plan, Block, Thread, Decision: commands, events, projections
│   │   └── __expect__/    # expect tests: command in, event stream out
│   ├── api/               # Effect HTTP, Better Auth, plan-room Durable Object
│   ├── agent/             # the room's pi-durable harness and its tools
│   ├── mcp/               # MCP server: read plan, list decisions, record decision
│   └── web/               # TanStack Start + shadcn/ui; block editor, threads, log
├── e2e/                   # event-replay e2e, and a few Stagehand flows
├── scripts/               # scaffolding: new-command, new-event, new-projection, new-route
├── skills/                # the collection below, loaded by pi and Claude Code
├── docs/
│   ├── GLOSSARY.md        # the ubiquitous language, kept next to the code
│   └── decisions/         # living wiki: why, not what
├── AGENTS.md              # shared agent instructions
└── CLAUDE.md              # → AGENTS.md

Scripts the demos run

A justfile is the contract between you, the agent and the sandbox. If a thing is not a recipe here, the agent will invent its own way to do it.

just up                 # nix develop + process-compose: db, minio, mail, api, web
just test               # expect tests (ms) then event-replay e2e (s)
just test:ui            # Stagehand flows against the local app (min)
just new command Name   # scaffold command + schema + expect test stub
just new event Name     # scaffold event + append to the registry
just new projection Name
just new route /path    # TanStack route + loader wired to the api
just plan GH-12        # open a plan room for the ticket; agent drafts blocks
just explore GH-12     # one exploration per approach, reported back into the plan
just trace session-id  # animated walk through what the agent touched
just replay stream-id  # rebuild a projection from the log, print the story
just review             # model-inversion review of the current branch
just deploy             # bun alchemy.run.ts

How a coding harness works

Before the multiplayer version, the single-player loop, because most of what feels like magic is six lines of plumbing. A harness is a program that assembles context, asks a model, executes whatever tool call comes back, and feeds the result in again until the model stops asking.

// the whole loop, honestly
context  = system prompt + AGENTS.md + skills + conversation + tool results
loop:
  reply  = model(context, tools)
  if reply has no tool call: break
  result = execute(reply.tool_call)         // shell, read, write, browser…
  context += reply + result                  // this is where context grows
you decide: which tools exist, what needs approval, what gets compacted,
            what persists between sessions, who else can see the thread
Context assembly
Everything the agent "knows" was put there by the harness: instructions files, loaded skills, tool results. Skills are just files added to context on demand. This is why the living wiki and AGENTS.md matter so much.
Tools and permissions
The model only asks; the harness executes. The trust ladder is literally a permission table in the harness.
Durability
Two different things hide under this word, and the next block separates them: a transcript you can reopen, and an execution that survives being killed mid tool call.
Legibility
Every turn, tool call and result is a record. A harness that keeps them is a harness you can audit, replay and learn from. Same idea as the event log.

Context economics: tokens, caching, compaction

The model remembers nothing between requests, so every turn re-sends the whole conversation. Cost grows with the square of session length unless the harness is careful. Three mechanisms keep it survivable, and all three are decided by the harness, not the model.

// one request, in the order Claude Code sends it (stable first, volatile last)
[ system prompt + tool definitions ]  changes when: the tool set changes, upgrade
[ CLAUDE.md · auto memory · rules   ]  changes when: session start, /clear, /compact
[ conversation · tool results        ]  changes when: every turn (appended at the end)

// the cache matches the PREFIX, exactly. change byte 1 and everything after it is recomputed.
turn n:    [sys][ctx][msg1 … msg n-1] ← read from cache [msg n] ← processed
/model:    [sys][ctx][msg1 … msg n  ] ← all recomputed: each model has its own cache
Caching
Cached tokens bill at a fraction of the input rate; the rest is processed in full. Cache lifetime is 5 minutes of inactivity on an API key (1 hour for the main conversation on a subscription within plan usage; promptCacheTtl: "1h" sets it yourself). The first turn back after a break is slow because the prefix expired.
What breaks it
Switching model, changing effort (on most models), toggling fast mode, changing the loaded tool set (an MCP server connecting with tools loaded upfront, or denying a whole tool), compaction (by design), upgrading. Pick model and effort at the top of a session and leave them.
What keeps it
Editing files (reads are appended), invoking skills (appended as messages), changing permission mode, /rewind (truncates back to a prefix that is already cached), spawning a subagent (its own cache; the parent's is untouched). Editing CLAUDE.md mid-session keeps the cache because it does not apply: the new text loads on the next /clear, /compact or restart.
Compaction
Replaces history with a structured summary. Reloaded from disk afterwards: CLAUDE.md, memory, rules, the most recently modified files, and the body of each skill you invoked (capped at 5,000 tokens per skill). Not reloaded: skill descriptions, and anything the summary left out. Run /compact at a boundary between tasks rather than letting auto-compaction fire mid-task; after a long break it is the most expensive command you have, since the summarisation request reprocesses the whole history uncached.
Token diet
MCP tool schemas are deferred by default and loaded on demand, so connectors cost a name, not a schema. Research that would dump a library into context goes to DeepWiki or its own throwaway session, and only the answer comes back, as a paragraph you read first. Tool output is tokens: a just test that prints 400 lines on success is a tax on every later turn. Auto memory loads only its first 200 lines or 25 KB.
Where to look
/context shows what is in the window. /usage shows the session's cache hit ratio and names the likely cause of the last miss ("tool definitions changed"). A status line can show cache_read_input_tokens against cache_creation_input_tokens live: reads high and creation low means it is working.

Rules for Greenhouse sessions

Model and effort chosen before the first prompt. AGENTS.md short and stable; the detail lives in skills, which load on demand. just recipes quiet on success, verbose on --verbose. Expect snapshots kept short because they will be read back into context. just review runs the second model in its own session, so the cold start never lands in the authoring session's cache.

Rules for your own harness

Order the prompt stable-to-volatile and put the cache breakpoint after the stable part. Never rewrite history in place; append. Compact by summarising into a new entry, keep the old entries on disk (pi-durable's store already does this). Let sessions compound: what one session learned goes into a file the next one loads, not into a longer transcript.

Two kinds of durability

Vanilla pi and Claude Code both write the conversation to disk as it happens and can reopen it. Neither resumes a tool call that was running when the process died. pi-durable is built for exactly that gap: it checkpoints the loop itself, so a killed process picks up from the last committed step. The table is the slide.

pi (vanilla)Claude Codepi-durable
transcriptSession file on disk, reopen laterJSONL at ~/.claude/projects/<project>/<id>.jsonl, saved continuously; --continue, --resume <name>, /branch, --fork-sessionCommitted entries in a store: SQLite (openNodeSqliteStorage), JSONL or in-memory
killed mid tool callTool result lost; you re-promptCall is marked cut off before its result was recorded; the model is told to check whether it took effect before running it again. Not rerun automaticallyResumes from the last durable checkpoint. Tools declared replay: 'safe' rerun; others are reported to the model as interrupted. Model requests can be resent (and billed again)
same prompt twiceRuns twiceRuns twiceA reused requestId returns the existing submission and its answer. Input dedup only; effectful tools still need their own idempotency
second deviceNoRemote Control: a phone or browser attaches to a running session. Two terminals on one session interleave into a single transcript, no lockingroot.viewState(context): a subscribable view of committed entries, running tool output and queued inputs, so a reconnecting client rebuilds the screen
message while busyQueuedQueued as the next turnFollow-up by default, or whenBusy: 'steer' to join at the next tool-round boundary
what does not surviveAnything in flightBackground subagents and background Bash end with the process; they show up as "did not finish" notes on resumeNothing is exactly-once: checkpointed, not transactional across the world. One process must own each store; WAL with synchronous = NORMAL can lose the newest commit on power failure
statusStableStable, documentedExperimental; pin the lockfile

The honest line for the talk: Claude Code gives you a resumable conversation; pi-durable gives you a resumable run. For a coding session on your laptop the first is usually enough. For an agent that runs unattended in the cloud, triggered by a webhook, the second is the whole point.

pi-durable, picked apart

Three packages, two files, one store. The example below is the shape of the Flavio Copes walkthrough, trimmed to the parts that matter for the demo.

// tools.ts — a tool that takes 10s and declares it is safe to replay
import { defineTool } from "@earendil-works/pi-ai";

export const serviceStatus = defineTool({
  name: "service_status",
  replay: "safe",                       // rerun after a crash; no side effects
  async execute(input, context) {
    await delay(10_000, undefined, { signal: context.abortSignal });
    return { checkout: "degraded" };
  },
});

// agent.ts — open a store, get the root conversation, submit work
import { openNodeSqliteStorage } from "@earendil-works/pi-durable";
const storage = openNodeSqliteStorage("./agent.sqlite");   // one process owns this file
const harness = createHarness({ storage, tools: [serviceStatus], model });

const root = await harness.root(context, { conversationId: ROOT_CONVERSATION_ID });
harness.resume();                                        // pick up anything left mid-flight

await root.submit(context, {
  requestId: "incident-106",              // same id twice = same answer, no rerun
  text: "What is the checkout status?",
  whenBusy: "steer",                      // or default: queue as a follow-up
});

// ui.ts — any client, reconnecting at any time
for await (const view of root.viewState(context)) {
  render(view.entries, view.runningTools, view.queuedInputs);
}
What is committed
Entries, in order: the submission, each model turn, each tool round and its result. A crash between tool start and tool result leaves the result uncommitted, so recovery restarts that tool (if safe) rather than guessing.
The kill demo
Start incident-106, wait for "Tool started", kill -9 the process, run the same command again. Same submission id, resumes from the checkpoint, tool reruns because its result never landed, answer arrives. Then run it a third time: the saved answer comes back with no tool call at all.
The two-client demo
A terminal and a web page both subscribed to viewState of the same root. Type in one, watch the other. Close the browser mid-run, reopen, it rebuilds from the snapshot. This is multiplayer with zero extra code.
Conversations, tasks, documents
pi-durable's own description: a "durable conversation, task, and document runtime". Child conversations are how subagents are modelled; documents are durable shared state an agent can update atomically. Both are what the Greenhouse review bot needs.
Prior art to borrow from
disler/durable-pi already builds the network: a per-device backend owning one agent.sqlite per session, a hub that holds device tokens, a web client and a TUI feeding the same frames into the same reducer, sync as hello → snapshot → deltas, fork at any past entry, change the tool set mid-run, jobs that pause for human approval. "The agent lives on the device, not in the client."
The Cloudflare step
pi-durable's storage is an interface (memory, JSONL, Node SQLite ship with it). A Durable Object already has SQLite and already enforces one owner per object, which is exactly the one-process-per-store rule. Writing a DO-backed storage adapter is the single piece of new code in the cloud demo; everything else is wiring.

Building the cloud multiplayer harness on pi-durable

The walkthrough: take the single-player loop above and make it survive and share. pi stays small and vanilla; pi-durable gives it a persistent, resumable session. In Greenhouse this is not a side demo: a plan room is a durable session with people in it, so the harness you build here is the product's agent layer.

What you build

A session is already an event stream in pi-durable: submissions, turns, tool rounds, results, as committed entries. The UI is viewState, a projection of that stream. Multiplayer falls out: two people subscribed to one root, either of them able to submit. One agent, one thread, many watchers. Your only decisions are where the store lives and who may submit.

What the agent gets

A sandbox per session (a Cloudflare Container via the Sandbox SDK), the Greenhouse repo checked out inside it, just recipes as its tools, and the skills folder in context. It verifies its own work by running the same tests you run.

  1. Single-player, localVanilla pi against Greenhouse. Show the loop in the logs: context in, tool call out, result back in.trust ladder · rung 1
  2. Add skills and the justfile as toolsWatch behaviour change with nothing but files added to context. This is the whole skills story in one diff.rung 2
  3. Make it durableSwap the loop for pi-durable with a SQLite store. kill -9 mid tool call, rerun the same requestId, watch it resume from the checkpoint. Then a second client on viewState: a terminal and a browser showing the same run.durability
  4. Put the sandbox in the cloudA Durable Object per session is the store (DO SQLite behind pi-durable's storage interface, one owner per object); a Cloudflare Container per session runs the repo and just. The loop runs there; viewState streams back to everyone watching over a WebSocket from the same object.rung 4
  5. Trigger it from a webhookA PR opened starts a review session. Sandbox, agent, webhook: the simple code-review agent from the notebook, now legible end to end.review for understanding

The skills collection

All loaded from skills/ by both pi and Claude Code. Third-party ones are pinned by commit; project ones are ours. Each row says when it fires, because a skill nobody triggers is a document nobody reads.

SkillFromGuardsFires when
impeccablePaul Bakaus · pbakaus/impeccableUI craft: hierarchy, spacing, type, the "AI-generated look"any change under packages/web
review-animations, improve-animations, animation-vocabulary, pick-ui-libraryEmil Kowalski · npx skills add emilkowalski/skillsMotion and component choices that feel right instead of merely presentanything with a transition, dialog or toast
anti-slop (TypeScript)Matt Carey's rules, as ESLint config plus a skillDefensive noise, needless abstraction, comments that restate code, anyevery TypeScript edit; enforced by lint, explained by the skill
slop-guard (Markdown)community skill, pinnedProse slop in docs, decisions and PR descriptionsany edit under docs/ or a PR body
viz-explainerours, on manimglRenders a short animated explainer of a flow from the event stream or a diagram specjust explain <stream-id>, and in the talk
claude-artifactsAnthropic's artifact skillsSelf-contained HTML pages for prototypes and show-me reviews"show me", before any UI gets built for real
testingoursWhich test to write: expect at the library level, event-replay e2e through the domain, Stagehand for browser flows. Never a unit test for its own sakeany new command, event or route
ddd-vocabularyoursNew nouns must appear in GLOSSARY.md and as a schema before they appear in codea new type, table or route
event-sourcingoursCommands validate, events are facts, projections are pure. Scaffolds with just newanything under packages/domain
review-for-understandingoursWalkthrough first, stacked PRs, questions before comments, model inversionjust review, PR webhook
deployoursRead Cloudflare and Alchemy docs before touching alchemy.run.ts; never guess a limit, a price or a default (Workers CPU time and D1 row limits bite quietly)any infra change

Planning as a boundary object

Maggie Appleton's "Planning with Agents" names the problem with how we plan today: the agent writes about 4,500 words a minute, you read about 240, so the plan arrives as a wall of Markdown you skim and approve. Her remedy is two ideas from Suchman and Star: plans are "a weak resource for ad hoc activity", not a contract, and the plan should be a boundary object, something that serves the human's way of seeing as well as the agent's. Her line for builders: "the agent can and should do 1000x more work to make the human more effective." Greenhouse takes that literally. The speaker has been doing this by hand in a product; the skills and scripts below are that practice, written down so the agent builds the interface instead of you.

Skill / scriptWhat the agent producesReplacesAppleton's pattern
just plan <ticket> · planning skillA short plan with every open decision as a link to a built artifact, not a question in prose. Decisions are answered in place and written back to the plan with a timestamp.The multiple-choice interview nobody finishesBoundary object; decisions logged
just explore <ticket> · explore-threads skillOne thread per candidate approach, each a separate implementation opened in the portal. No branches, no worktrees. Each thread ends with the same structured report so they can be compared.Deciding from a paragraph describing options nobody has triedPre-handoff exploration, "making contact with reality"
decision-report skillAn interactive comparison across the explored options: call sites touched, mechanical vs judgement-call changes, silent behaviour changes, the invariant each option risks, and the expect snapshots side by side. Built with the claude-artifacts skill."Option A, B or C?"Retry-logic decision report
option-explorer skillFor anything perceptual (spacing, motion, copy, colour): a bespoke control rendered against the running app, with the chosen value saved back to the plan. Pairs with the animation skills and Agentation.Three text options for something you have to seeLive-app manipulation; shadow and animation tuners
state-explorer skillFor a command's lifecycle: the states and transitions of a stream rendered as a diagram you can click through, with a button that adds a missing transition as a new event type.Reading a reducer to find the gapState machine explorer
just trace <session> · viz-explainerWhat the agent touched and why, as a short animated walk through files and events from the pi-durable stream (manimgl under the hood).Scrolling a 3,000-line transcriptAgent-run trace views (Mindwalk)
just lookaheadWhile you answer one decision, the agent prepares the artifacts for the next two, so you never wait on it.Idle agent, busy humanParallel lookahead

The GH-12 plan, as a boundary object

One real decision: is a decision a separate fact (ThreadResolved then DecisionRecorded, two events, so a thread can close without a decision) or one fact (ThreadResolved carrying the decision)? just explore runs both as explorations. The decision report, embedded in the GH-12 plan, shows the resulting event streams side by side, which projections each touches, and which one makes "a decision references exactly one thread" a type instead of a check. You click one. The plan records who clicked, and when.

Rules the skills enforce

Never ask a question in prose that could be a rendered choice. Never present an option that has not been tried. Every decision carries who made it and when. Plans orient; they do not bind: a thread that meets reality the plan did not predict reports back instead of pushing through. And the agent, not the human, pays the cost of being understood.

The social half of Appleton's argument (colleagues and agents debating a decision together) is what Chopin is for, and Greenhouse keeps the mechanism (a shared room, threads, an agent as participant) while leaving team process out of the talk: one person planning with an agent is the case shown; a second person joining the room is one click more, and that is the only team-level thing said all evening.

Connectors and tools the agent reaches for

Skills tell the agent how to think; these give it somewhere to look. All four are used in the runs.

ToolWhat it isUsed forPractice
Mobbin MCPSearchable library of real app screens and flows, exposed to the agentBefore designing the split dialog: "how do three shipped apps let a user split an amount?" Inspiration from products people use, not from the model's priors.taste · show me
DeepWiki MCPDevin's remote, no-auth MCP that answers questions about any public GitHub repo from a generated wiki"How does Better Auth handle passkeys?" answered from the source, with citations, instead of from memory. The deploy and testing skills tell the agent to ask it first.read the docs
Claude in ChromeBrowser extension that lets the agent drive your real Chrome, with your sign-insDogfooding on the agent's side: open the deployed app, upload a receipt, split it, report what it saw. Also the quickest Stagehand-free smoke check.dogfood · verify
AgentationAgent-agnostic visual feedback: click an element, select text or drag an area on the page, add a note, copy structured markdown with CSS selectors and positionsYour show-me review loop. Point at the wrong padding, paste the note into the agent pane; it finds the selector in the codebase. Replaces screenshots and "the thing on the left".show me · taste

The testing skill, spelled out

Write these

  • Expect tests in __expect__/: a command and a starting stream in, the resulting events out, as a snapshot a human reads like a story. Milliseconds, deterministic, simulated clock.
  • Event-replay e2e: a scripted sequence of commands through the real API against a real local Postgres, asserting on the stream and the projections. Seconds, no browser.
  • Stagehand flows: the three or four journeys where the browser is the point (open a plan, comment on a block, resolve the thread, see the decision on the block and in the log). Natural-language steps, so the test reads like the user's intent and survives a redesign.

Do not write these

  • Unit tests of a function the types already constrain
  • Mocks of your own modules; mock the model and the network, nothing else
  • Browser tests for anything the event stream can prove
  • Tests whose expected value nobody could read and judge

The rule the agent follows: if a test's expected output is not something you could show a user and get a nod, it is the wrong test.

Demo script: each practice, shown live

  1. Fresh clone to green tests, with nobody at the keyboardHand the agent a bare checkout. just up, just test. If it needs you, that is a DX bug, and we fix it on stage.run anywhere
  2. Plan the ticket in the tooljust plan GH-12 opens a room. The agent drafts blocks, runs two explorations, embeds a decision report. You resolve the thread by clicking. The plan is now a boundary object with one owned decision in it.planning · boundary objects
  3. Add a field, follow the trellisAdd rationale to Decision in the shared schema. Watch the compiler walk the agent through api, UI, MCP server and tests.types as design language
  4. A new feature as command, event, projectionjust new command ResolveThread. The scaffold writes the expect stub; the agent fills it; the snapshot is reviewed as prose.event sourcing · expect tests
  5. End to end without a browserReplay a full plan (edit, thread, replies, resolve, fork) through the API and assert on the decision log. Then the one Stagehand flow, to show what it costs by comparison.testing skill
  6. Taste under supervisionAsk for the resolve action "to feel better". impeccable and the animation skills turn that into specific edits; you judge the result by using it.taste · dogfood
  7. Correct code that is wrongHave one tool author a change that passes every test but breaks a glossary rule. Have a different model review it with just review.model inversion · review for understanding
  8. Explain it backjust trace renders the event flow of a real session with viz-explainer and attaches it to the plan as an artifact block. The agent's account of its own work, as a picture, where the decision lives.augment your learning
  9. Implement from the plan, anywhereOpen Claude Code with the Greenhouse MCP server. It reads the plan, sees the one decision, implements against it, and writes "implemented in PR #n" back as a decision. Plan here, build there, review against the plan.one vocabulary · legibility
  10. Ship itjust deploy from the agent's sandbox, after it has read the Cloudflare docs via the deploy skill. Same repo, same vocabulary, now on Workers.read the docs · trust ladder

07 · Workflow and release

From merge-ready to released

A green PR is the middle of the job, not the end. The listing promises a workflow from requirements to production and a release checklist with product fit, staged rollout and a rollback path. Here they are, sized for one person.

The workflow, one task end to end

1 · Interview
Talk to the user who asked, or the one who would. Write the feature, not the ask. you
2 · Name it
New nouns go in the glossary and the schema first. If a word has no type, stop here. you
3 · Estimate
Brooks's fractions. The coding sixth is the agent's; budget the other five sixths for yourself. you
4 · Plan as a boundary object
just plan: open decisions come back as built artifacts and explored threads, not prose questions. You decide by clicking on something real; the plan records it. shared
4b · Scaffold
just new … so the shape is right before any code exists, including the expect stub. agent
5 · Build in the loop
Domain first, UI second, each with its own test layer. Show-me reviews on artifacts before real UI. agent
6 · Dogfood
Use it. The Stagehand flow proves it works; only you can tell whether it feels right. you
7 · Review inverted
A different model, the glossary in context, walkthrough attached to the PR. shared
8 · Release staged
Checklist below. Ship to yourself, then a slice, then everyone, with the way back decided in advance. you
9 · Feed it back
What the release taught goes into docs/decisions and the skills, so the next session starts smarter. shared

Release checklist

Lives in the repo as docs/RELEASE.md; the PR template links it. Short on purpose: a checklist nobody finishes protects nobody.

Product fit

  • The user's sentence. One line, in the user's words, of what is now possible. If you cannot write it, you built an ask.
  • Dogfooded. You used the feature on real data at least once today.
  • Vocabulary intact. No new noun in code that is missing from the glossary and the UI copy.
  • Signal defined. Which event in the stream tells you it is being used, and what number you expect in a week.

Staged rollout

  • Behind a flag. New commands are gated per user; default off in prod.
  • You first. Flag on for your own account; run the Stagehand flow against prod.
  • Gradual deployment. Workers versions split traffic; move the new version from 1% to 100% in steps you can watch, not in one push.
  • Migration is additive. Schema changes add; nothing is dropped or renamed in the same release as the code that stops using it.
  • Watch window. Errors and the usage event, for a stated time, before the next step.

Rollback path

  • Decided before deploy. The rollback command is written in the PR, not improvised.
  • Flag off is step one. Kills the behaviour in seconds without a deploy.
  • Previous version pinned. Workers rollback to the prior version is one command; you know the version id.
  • Events are facts. Rollback never deletes events. A bad projection is rebuilt with just replay; a bad command is compensated with a new event, which is the one advantage event sourcing buys you at release time.
  • Postmortem in decisions. If you rolled back, the why goes in the living wiki before the retry.

08 · Changing what people already use

The four questions a live product asks

Everything before this assumed a clean slate. Real products have users mid-task, data in old shapes and opinions about your changes. Four things the agent will get wrong unless the basics are in place first.

1 · Changing events people already recorded

The log is a record of facts, and you do not change the past. So an event-sourced product evolves by changing how events are read, not what was written. There is a ladder, least invasive first, and the agent should be told to climb it from the bottom.

0 · Avoid it
Keep streams short-lived where you can. A plan is one stream and lives as long as the work does, so Greenhouse cannot fully dodge this; a thread, by contrast, opens and resolves within days. Frequent event changes usually mean the model, not the schema, is wrong.
1 · Simple mapping
New optional fields are nullable, new required fields get defaults, a renamed field keeps its old JSON name. No code beyond the schema.
2 · Upcast on read
A small function between the store and the domain turns DecisionRecorded.v1 (no rationale) into .v2 (rationale, defaulting to the thread's last reply). Registered per event type, tested with an expect test whose input is a real old event from prod.
3 · New event type
When the meaning changed, not the shape, it is a new fact with a new name. Old projections keep working; new ones handle both.
4 · Transform or migrate
Rewrite a stream into a new one (merge, split, clean up) as a one-off job that itself emits events. Last resort, done in two phases: ship code that reads both, migrate, remove the old path.

Why this matters for the agent: an agent asked to "add a rationale to decisions" will happily edit the event schema in place and break every replay of every existing plan. The event-sourcing skill makes the ladder explicit and makes the expect tests the gate.

2 · Feature flags: behaviour, not code

Two axes, keep them apart

Versions decide which code runs. Workers gradual deployments split traffic between two uploaded versions. Flags decide which behaviour runs inside one version serving all traffic. Rollback a version when the code is broken; flip a flag when the feature is wrong.

What the agent is told

Every new command ships behind a flag, default off. The flag check lives in one place (the command handler), never sprinkled through the UI. A flag older than two releases is a lint error.

Standard
Code against OpenFeature, the CNCF vendor-neutral flag API, so the provider is swappable.
On Cloudflare
Flagship is Cloudflare's own flag service on OpenFeature: evaluated locally in the Worker through a native binding, rules by priority with optional percentage rollout, boolean to JSON values. Closed beta at the time of writing, so have a fallback.
Fallback for one person
A flags table in your own Postgres keyed by user id, read through an OpenFeature provider you write in an afternoon. Better Auth already gives you the user. PostHog flags if you want a UI and percentages without building them.

3 · Rollouts: a sequence you can watch

You
Flag on for your own account in prod. Run the Stagehand flow against prod. Dogfood for a day.
A named slice
An allowlist of users who asked for it, or who you interviewed. They are the people from tenet 6; tell them it is on.
A percentage
Flag rule at 5, 25, 100. At each step, a stated watch window on two things: error rate, and the usage event you defined in the release checklist.
The code version
Separately, the Worker version goes 1% to 100% via gradual deployment. Two knobs, moved on different days if you can.
Data last
Migrations are additive and ship before the code that needs them; drops and renames ship a release after the code that stopped using them.

4 · Letting users send you bugs the agent can reproduce

A bug report is a repro you did not have to write. Design the report so it carries enough for the agent to reproduce it without a call. In an event-sourced app most of that is already there.

The report button

One button, always visible. It files a ReportFiled event carrying: the user's note, the session id, the plan and block they were on, the last few events in that plan, console errors, and a screenshot. The user types one sentence; the system attaches the rest. In a planning tool the report can also open as a thread on the block in question, which is where the fix will be discussed anyway.

What the agent does with it

just replay <stream-id> rebuilds exactly what the user saw. The agent reads the story, writes the failing expect test first, then the fix. The report, the test and the fix share a vocabulary because they share a stream.

Off the shelf
Sentry's User Feedback widget attaches the report to the error and the session replay; PostHog gives replay and surveys in one SDK; Jam records a shareable repro with console and network. Any of them is fine; the point is that the report arrives with context, not that you built it.
Design feedback is different
For "this looks wrong" from you or a designer, Agentation beats a bug tracker: the note arrives with the selector, and the agent fixes the element rather than hunting for it.
Close the loop
A fixed report gets a reply with what changed, and the report count per release goes on the dashboard next to the usage event. Users who see their bug fixed send the next one.

09 · Close

You are the gardener

The agent grows the code. The basics are how you shape what grows: the soil it runs in, the trellis of types and tests, the names on the labels. None of that is new. What is new is that growing is no longer the bottleneck, so the shaping is the job.

Estimation exercise

Pick a small CRUD app that does one thing with AI (a note-taker that tags entries, a form that summarises uploads). Then, as a group:

  1. Write the feature, not the ask: who is better off and how would you know.
  2. Estimate it with Brooks's fractions. Put the coding slice at one sixth and see what the other five sixths contain.
  3. Mark each piece of work you or agent. Notice which pile the essence lands in.
  4. Name the first test the agent would need to verify its own work without you.