Chris Dilger

← Writing · · workflow, agents, beads

Planning with beads: how Physical Soccer and Joystick Jammers get built

My loop for new projects is deliberately boring.

  1. Write the plan. A real document: what the thing is, who it is for, what “done” means, and how we will know.
  2. Turn it into beads. Every requirement becomes an issue in beads, using Jeffrey Emanuel’s beads_rust (br), stored in the repo next to the code, with real dependencies between them.
  3. Let the graph decide. br ready lists only the beads with no open blockers. That is the whole scheduler.
  4. Run a herd. With herdr and ntm I keep a few agent panes open side by side, each claiming one ready bead, so the work fans out and the graph keeps it honest.
  5. Review, playtest, write the next beads. My job is steering and taste.

Two of my current projects show what that looks like, and they show quite different shapes. One of them has since been rebuilt from scratch, which gave me a rare second run of the same game with a different method.

Physical Soccer: plan first, then let it flow

Physical Soccer is a party football game where anything can be a controller: phones, pads, keyboards, half a touchscreen. Before a single bead existed, it had a plan: plan.md, now on its fifteenth revision. Each revision closed real gaps. Revision 3 decided who owns the room state. By revision 4 the plan had a journey matrix and dependency cuts, and it said, in so many words, that it was “ready to convert into small, testable tasks”. The revisions kept coming anyway: revision 7 pinned the physics clock (the original game runs at 0.85x wall-clock, so the port carries an explicit time scale).

Then it was converted: a coverage index (plan-beads-map.md) maps every requirement to a bead ID, and every bead carries its own contract (what to build, which checks prove it, which evidence a parent bead needs from its children).

Physical Soccer: beads created vs closed, hour by hour

created (total)closed (total)open right now
050100150 010203040 hours since the first bead beads
About 130 beads were written in the first afternoon, straight from the plan. Closing started almost immediately and ran as a steady stream: 64 closed in the first 42 hours, with the open count falling as soon as the planning burst ended. That is what a good plan buys you: agents never ran out of well-specified, unblocked work.

Physical Soccer: 194 beads, 451 blocking links, 24 layers deep

closed 64in progress 3blocked 6open 91deferred 30
no blockers 24 layers deep
Each dot is a bead, placed further right the more beads must close before it can start. Filled dots are closed. You can see the work moving through the graph as a wave from left to right. 162 of the 194 beads wait on at least one other, and the longest chain is 24 beads long: the real critical path, which no number of agents makes shorter. Grey outlines are ideas deferred on purpose. Titles are left out deliberately; the shape is the point.

Why did this one flow so well?

Joystick Jammers 0.1: a polishing swarm

Joystick Jammers is a party racer and demolition derby: the TV is the arena, phones are the pads. It is open source, so you can read the code and every one of its beads yourself. It is in a different phase. The game works, and the job now is polish: player readability, controller latency and reconnect confidence, tutorial and onboarding, wheelies and stunt payoff. That kind of work is discovered by playing, not planned up front.

Joystick Jammers: beads created vs closed

created (total)closed (total)open right now
050100150200 051015 days since the first bead beads
A small start in mid June, then a single review day (day 15) that filed 151 polishing beads at once. Since then the swarm has closed 10 to 27 a day, speeding up as the polishing beads got sorted and claimed. 89 are still open: this one is very much still going.

Joystick Jammers: 207 beads, 313 blocking links, 10 layers deep

closed 114blocked 3open 89deferred 1
no blockers 10 layers deep
A much shallower graph than Physical Soccer: 10 layers instead of 24. Polish work is wide, not deep, so the herd can attack it in parallel. 4 different authors created beads, including agent identities like OliveFox and SilverBass: the swarm files follow-up work for itself as it finds it.

The coordination rules are written into the repo, so every agent reads them on start:

Joystick Jammers 0.2: the same game, planned the Physical Soccer way

Polishing only goes so far. Jammers 0.1 was a Python server and a browser game grown feature by feature, and the next things I wanted (anyone dropping in mid-round, cars that shed doors and wheels, tracks generated from Australian places, controllers on WebRTC) wanted a different foundation. So 0.2 is a from-scratch rebuild: a Rust server, a Rust/WASM simulation running in the host’s browser, Three.js on the TV and WebRTC to the phones. The 0.1 game stays playable while 0.2 is built beside it.

This time it went the Physical Soccer way. A set of owner rulings came first, then a master plan, then a Playtest 1 plan cut down to one car and the new stack, and only then beads: every bead carries its plan task ID, its acceptance checks and the evidence it owes (the definition of done spells it out), and a bead map ties every plan requirement to a bead. All of it lives on the public v0.2-revamp branch, beads included. The repo even states the order of authority: owner ruling, then master plan, then Playtest 1 plan, then beads, then code. A bead cannot overrule the plan; if it disagrees, the plan gets fixed first.

Joystick Jammers 0.2: beads created vs closed, hour by hour

created (total)closed (total)open right now
050100150 020406080100120 hours since the first bead beads
A hundred beads in the first six hours, straight from the plan, and closing under way by hour twelve. After that, closes arrive in steps rather than a stream. The step near hour 76 is my own design reviews (rounds 4 and 5): owner reviews are beads too, and a dozen interface beads closed with them. The big jump near hour 115 is the verifier: finished beads queue for it, and one pass closed about forty at once. 131 of 193 closed in under six days, with 7 more done and waiting for the verifier.

Joystick Jammers 0.2: 193 beads, 616 blocking links, 17 layers deep

closed 131awaiting verification 7in progress 1open 50deferred 4
no blockers 17 layers deep
Compare it with 0.1 above: 17 layers instead of 10, and 3.2 blocking links per bead instead of 1.5. A rebuild has a real critical path (the network stack before the controllers, the simulation before the damage, the car before the playtest), and the plan writes it down instead of discovering it. Pale yellow dots are beads an agent has finished and handed to a separate verifier: closing is a second agent's job now, so "done" is checked, not claimed. 7 authors created beads, most of them one planning agent working from the plan's task list.

Two things changed from 0.1, and both came from Physical Soccer:

Where I am the bottleneck

The layered drawings above answer “how deep is this”. They hide a question I care about more: how much of this is waiting on me? In both projects some beads can only be closed by me: a design or taste review, a couch playtest with real people and real phones, a release call. Agents can prepare everything around them, but they cannot close them. So I drew the same graphs the way a beads viewer does, as a force-directed network where tightly linked work clumps together, and picked out my own gates.

Joystick Jammers 0.2: my 6 gates and what waits behind them

closed open my design review (filled once done) my playtest my release call
Owner design review round 4G-DESIGNOwner design review round 5Playtest-1 qualification

53 of 193 beads sit downstream of at least one of my 6 gates; 4 of them are open and waiting on a gate I have not closed yet.

Every dot is a bead, pulled towards the beads it is linked to. Ringed dots are mine; their size is how much open work sits behind them. The design gate and its review rounds 4 and 5 each had over fifty beads downstream: more than a quarter of the whole plan could not finish until I had looked at the screens and said yes. That is the step near hour 76 in the chart above. Pick a gate to see exactly what it holds up.

That is the honest cost of taste. Design reviews are cheap for me to do and expensive to wait for, so in 0.2 they became small, frequent rounds with their own beads (round 3, 4, 5) instead of one big verdict at the end, and the agents work on everything that does not depend on the look while a round is open.

Physical Soccer: my 16 gates and what waits behind them

closed open my design review (filled once done) my playtest my release call
First public stable joinS1 representative human playtestsMusic approvalComplete gameplay couch playtestStyle guideAnnouncer voice and cuesS1 qualification and promotion

36 of 194 beads sit downstream of at least one of my 16 gates; 12 of them are open and waiting on a gate I have not closed yet.

A different shape. Physical Soccer's gates sit at the far end of the plan: the style guide, the announcer voice, the couch playtest, the human playtests and the release calls. Each has about 33 beads behind it, mostly the same ones: the release candidate and everything that integrates into it. Only 12 open beads wait on a gate right now, but 2 of the 19 links on the remaining critical path are me. No number of agents makes those shorter; a free Saturday with a couch full of people does.

Two habits came out of looking at this:

Deep vs wide

ProjectBeadsBlocking linksLongest chainClosedShape
Physical Soccer1944512464planned, deep
Joystick Jammers 0.120731310114polishing, wide
Joystick Jammers 0.219361617131planned rebuild, deep
This site (previous version)99117785small, quick

The longest chain is the number I watch now. A herd of agents makes a graph wide cheaply: more panes, more parallel beads. Only planning makes it shallow, by finding the dependencies early and cutting them where they are not real. Physical Soccer’s 24-deep chain is the honest critical path of a networked physics game with a relay, two hosts and owner playtests in the loop; Jammers 0.1’s 10 layers is what let a five-pane swarm close two dozen beads a day. Jammers 0.2 sits in between at 17: the same game, but a rebuild has to lay its foundations in order, and the plan made that order explicit before the first agent started.

The part that surprised me is how much the graph helps me. When something goes wrong, the fix is usually a better bead (clearer acceptance checks, a missing dependency), not a better prompt. The wording I hand an agent barely matters any more; a clear goal, a real way to check the result and the effort to keep going until it passes matter a lot. I made the first half of that argument in Your Prompts Do Not Matter (Anymore): prompt engineering stopped being the hard part. Beads are where the rest of it lives.