My workspace is about ~20 repos — a dashboard, a design system, three parallel rewrites, a content engine, a pile of smaller tools. Releasing meant remembering which one needed what: run the tests here, rebuild a registry there, promote a staging build to production somewhere else, then commit and push each repo by hand. It was a checklist I kept in my head, and the head is where checklists go to rot. So I gave the whole thing one door: type /release, it plans first as a dry-run, then fans out across every repo in order — and hands me a receipt. This one's pure efficiency: same result, a fraction of the fiddling.
Every repo shipped a slightly different way. One needed its test suite green first. One needed a dependency sync before anything else built. One had a registry that had to be rebuilt or the app booted stale. One lived as a staging build that a human had to promote to production and then eyeball for a green health check. And the flagship repo — the one that runs everything — I was terrified of pushing by accident. So a "release" was really twenty small rituals done in the right order from memory, one terminal tab at a time. Miss a step and you find out in production, on a Sunday.
The fix is a plan-by-default orchestrator — one script, one command. /release runs the same pipeline every time, in the same order: a verify gate (tests, a secret scan, unit checks — --full adds lint + build) → a dependency sync on the design system and a registry rebuild → a generated release-state block written into every repo's summary → a link check → commit + push per repo → the staging build promoted to production with a health check → a summary sent to my phone. Plan is the default; nothing ships until I add --go. Then it fans out across the real repos — in order, no tabs, no memory.
Fanning out across twenty repos means twenty things that can fail — a flaky test, a network blip on push number fourteen. So the run writes its progress to logs/release-state.json as it goes, and every step is idempotent: run it twice and it does nothing the second time. A failed run doesn't start over — /release --go reads the state file and picks up exactly where it left off, skipping the repos already done. And the flagship repo stays hard-gated behind its own flag, so the one repo that runs everything can never ship by accident. Fast because it's one command; safe because it assumes it'll be interrupted.
Automating a release is great right up until it auto-pushes the repo that runs your whole system. So the flagship is hard-gated: the fan-out skips it unless I pass an explicit --push-flagship. One command ships nineteen repos happily; the twentieth always needs me to say it out loud. Convenience everywhere it's safe, friction exactly where it isn't.
The dry-run plan it shows before anything moves, the --go run fanning out across the repos, the state file that makes it resumable, and the summary that lands on my phone when it's done. Tap any image to enlarge it and read exactly what's on screen.




The release didn't get smarter; it got boring, which is the whole point. What used to be twenty tabs and a checklist in my head is now one command that plans, verifies, fans out in a fixed order, resumes itself if it trips, refuses to touch the one repo it shouldn't, and buzzes my phone when it's done. That's the last manual step in the loop quietly closing — not as a flex, just as time I don't spend babysitting terminals anymore.
On camera: the by-hand release ritual, then /release planning first, fanning out across the workspace with --go, resuming after a deliberate failure, and the summary landing on my phone.
If you juggle more than a couple of repos, the shape is worth stealing: one orchestrator, a fixed pipeline, plan by default, execute only on --go, a resumable state file, and a hard gate on the one repo you must never ship by accident. Everything in this episode is free and open — clone it, run it, make it yours.
# Plan by default, execute only on --go, resume from a state file:
# /release → dry-run: list repos + ordered steps
# /release --go → fan out (verify → sync → push → promote → notify), journal to release-state.json
# /release --go → after a failure, resumes at the first unfinished repo (idempotent); flagship skipped unless --push-flagship
The cleaned-up release_all.py is being scrubbed of real repo names for release. Comment RELEASE on the post and the bot DMs you the moment it's public.
Nineteen repos fan out on one command; the twentieth — the flagship that runs the whole system — stays hard-gated behind an explicit flag. Next up: why the most-automated workspace still keeps one deliberate manual switch, and what it takes to earn the right to flip it.