AI Agents
Orchflows: Self-Improving Skill Workflows
You don't need prompt collections. You need skill workflows.
There are 10,000 skill libraries competing right now. GStack. Superpowers. Compound Engineering. Pocock. You're supposed to pick one, memorize its slash commands, and drive its workflow by hand. Here's Pocock's:
Everyone else's looks the same. /brainstorm, /plan, /subagent-workers, /review, /push. Why am I typing this shit out every time I want to make a change? The agent knows what a plan is. It knows what a review is. It can count the files in the task. Why can't I install one library and let the agent pick the workflow that fits?
That's orchflows: token-optimized, self-improving, error-correcting loops that can run for 24 hours. Or 4 minutes. The skills are legos. The agent snaps together a workflow sized to the task in front of it. You don't run skills. You ask for what you want, and the agent runs workflows built out of skills.
github.com/DanMcInerney/orchflows
Principles
Orchflows borrows heavily from, and builds on top of, Matt Pocock's skills. To see why, let's look at Superpowers' /brainstorming skill:
OK cool. Now a Pocock skill at the same zoom:
These libraries have similar GitHub stars. How is that possible.
TERSE
Single giant manifesto skills are band-aids on current models' weaknesses. You wrote 400 lines of step-by-step instructions because last year's model needed its hand held, and next year's model will be actively worse for following them. Orchflows makes terseness a *build error*: skill bodies are capped by a validator at 25 lines for core skills, 40 for workflows, and 140 characters for descriptions. The binding parts of a skill (what it requires, what it must never do, what it returns) are contracts; the middle is a default method a stronger model may substitute, as long as every invariant and check still holds. Build for the model six months from now instead of the one you're apologizing for today.
COMPOSABLE
Skills call other skills. The delivery workflow doesn't contain a verifier, it calls the verify skill. The verify skill doesn't know what a delivery is. There's no reason to stuff everything into one monolith; let a small skill call other small skills until the job is done. This is also what makes the routing work: the agent can hand you one lego or the whole castle because the castle is literally made of the legos.
DOMAIN-BLIND
By domain I mean the category of the task. Writing a blog? orch-deliver. Building an API? orch-deliver. Composing a research report? orch-deliver. The skills codify the *process* of getting a job done (spec, decompose, execute, verify) and the process doesn't care what the deliverable is.
The domain specifics live in packs: small files of vocabulary, slicing rules, and oracle policy. The code pack says "oracles are test suites, workspaces are git worktrees." The content pack says "oracles are judged rubrics, workspaces are document slots." At release there are four (code, design, research, content) and you can write your own, maybe a finance pack or a SQL pack, whatever your shop does. When you ask for work, the agent stamps the right pack onto the run and the same workflow just... works there.
Install
git clone https://github.com/DanMcInerney/orchflows
cd orchflows
./install.sh # install.cmd on Windows
The installer detects whatever harness you have (Claude Code, Codex, or both) and wires it up. 37 skills, 4 domain packs, and a routing block that teaches the agent to size the workflow itself. Updating is git pull and rerun. Everything else is in the README.
Usage
You tell the agent what you want done. That's it. You don't memorize skill names, because intake routes every request to the smallest workflow that fully holds it. That routing is written into the library as law. But let's look at what actually happens, small to large.
Small
"fix the flaky retry test"
No ceremony. The orchestrator writes ONE ticket (objective, completion test, budget) and goes:
flowchart TD
A["you: 'fix the flaky retry test'"] --> B["orchestrator cuts ONE ad-hoc ticket:<br/>objective + completion test + bound"]
B --> C{"do the oracles already exist?"}
C -- "yes — repo's own test suite" --> D["execute inline<br/>(zero extra contexts)"]
C -- "no — executor writes its own checks" --> E["fresh worker child does the work"]
E --> F["orch-check: a second fresh context<br/>hunts tautological checks, corrects once"]
F --> G["orch-verify re-runs the completion test"]
D --> H["orch-verify: the oracle decides,<br/>never the model's claim"]
G --> I["orch-integrate: one join rules the result"]
H --> I
I --> J["the ticket file is the durable record"]
If the task is a handful of independent pieces, the orchestrator cuts a handful of tickets and fires parallel workers at them. This shape is the built-in pattern, the thing Claude and Codex already do when you ask them for anything ("spawn three subagents, gather"). Orchflows adds durability and honesty to it. Durable: the tickets are files, so the work survives the session dying. Honest: the record includes who authored the checks that passed, and acceptance resting only on the executor's own artifacts is marked UNVERIFIED by law. A model grading its own homework with tests it wrote itself is how you get confidently green garbage, so if the agent had to write its own checks, a *second fresh context* reviews the work AND the checks before anything is accepted.
And the floor is cheap: if the checks already exist (your repo's own test suite), the agent does the work inline. Zero extra contexts. One ticket file plus one verification is the entire overhead over raw Claude.
Medium (delivery)
"give me the actual state of prompt-injection defenses in 2026: what works, what's marketing"
Same library, zero code involved. The request stamps the *research* pack and buys real structure: a frozen spec, bounded evidence lanes, parallel investigators, one gate.
flowchart TD
A["you: 'state of prompt-injection defenses, 2026'"] --> B["orch-spec: freeze the question + acceptance,<br/>stamp pattern=deliver, pack=research"]
B --> C["orch-decompose: cut bounded<br/>evidence lanes under the pack's slicing"]
C --> D["orch-investigate:<br/>vendor claims vs. shipped patches"]
C --> E["orch-investigate:<br/>academic evals + benchmarks"]
C --> F["orch-investigate:<br/>real-world incident reports"]
D --> G["orch-synthesize: one traced answer —<br/>disagreement preserved, never averaged"]
E --> G
F --> G
G --> H["orch-review-fix: ONE gate —<br/>critique lanes, correct once, verify once"]
H --> I["orch-verify: evidence oracles —<br/>every claim cites a source that resolves"]
Every piece of this transfers unchanged to a code delivery or a blog delivery:
- Rolling frontier. The moment a lane's dependencies are complete, it's in flight. No "wave 2 starts when wave 1 finishes" idle time.
- Lanes are blind to each other. Each investigator answers one bounded question from primary evidence and returns cited findings. Disagreement between lanes gets preserved and traced in the synthesis step instead of silently averaged into mush.
- One gate. Critique lanes run over the same fixed revision, findings get validated together, ONE correction pass.
- The agent cannot mark its own work complete. Terminal status is written by the join after external oracles decide. Here, "every claim cites a source that resolves" is a real check the run has to pass.
- Authority attenuates. Every subagent's write scope is a strict subset of its caller's. Workers physically can't wander:
Swap the research pack for the code pack and the same diagram ships a feature: lanes become tickets in git worktrees, evidence oracles become test suites. That's the whole domain-blind pitch in one picture.
Large (orch-goal)
"get test coverage to 90% and keep CI green"
No ticket list covers that. It's a *condition*, and orch-goal treats it as one: delivery with an evolving spec doc, loop(orch-deliver) against an external done-check.
flowchart TD
A["you: 'get coverage to 90% and keep CI green'"] --> B["orch-goal = loop(orch-deliver)"]
B --> C["iteration N: FRESH context,<br/>reads only the worklog + living spec"]
C --> D["one full delivery run:<br/>spec → tickets → frontier → gate"]
D --> E{"done-check: external oracle<br/>(coverage ≥ 90%?)"}
E -- "not yet" --> F["worklog: verified increments +<br/>failed approaches (never re-walked)<br/>spec evolves with what was learned"]
F --> C
E -- "green" --> G["exit: complete"]
E -- "budget spent" --> H["exit: limited —<br/>partial results returned, never silent"]
Every iteration is a fresh context that reads a worklog instead of a 400k-token transcript. Unlike a medium run, the spec stays alive: each iteration folds in what got verified and what got learned, so iteration five is executing a smarter spec than iteration one. The worklog also records every approach that already failed, with the evidence that killed it, and an iteration never re-walks a dead approach. The loop is bounded too: blow the budget and it exits limited with partial results and receipts, instead of burning tokens in the dark until you notice.
This is the "runs for 24 hours" mode. It's also the "runs for 4 minutes" mode. Same legos, different stack height.
Self-improvement
This is the part I actually care about.
The self-improve loop
Every session, friction gets logged automatically: a step that took three attempts, a missing doc, a surprising output, a workaround. The agent logs what happened vs. what was expected and moves on. Diagnosis comes later.
orch-self-improve mines those logs plus the run state the workflows leave behind:
flowchart LR
A["friction logs<br/>(auto-logged every session)"] --> D["orch-self-improve"]
B["run state:<br/>tickets, worklogs"] --> D
C["session traces"] --> D
D --> E["cluster observations →<br/>one causal owner each"]
E --> F["qualify: check the claimed defect<br/>against the owner file's current text"]
F --> G["REPLAY the original ticket<br/>against the amended skill"]
G -- "red replay" --> X["disqualified — noise stays noise"]
G -- "green replay" --> H["proposal on disk,<br/>passive until a human merges"]
The bar for a proposal is brutal on purpose. The claimed defect gets checked against the owner file's *current* text (maybe it's already fixed). Then the original ticket gets replayed against the amended skill in an isolated workspace. A red replay disqualifies the proposal. Nothing merges itself; proposals sit on disk until a human says yes. And ranking ties break toward proposals that DELETE text over ones that add it, because a self-improvement loop with an addition bias is just a bloat generator with good PR.
The self-improve skill is itself a skill, which means you can run it twice: the second pass scoped against the first. Self-improving the self-improver.
You can also end any custom workflow with a self-improve pass over the current session. Build me a workflow that loops over my GitHub repos and summarizes open issues, and when the loop is done, run self-improve on the workflow itself. The library eats its own exhaust.
Receipts, because this claim is easy to fake: I pointed 14 parallel review agents at the library itself. They came back with 108 raw findings that deduplicated to 6 root causes. The fix that closed all of them touched 37 files at net negative fourteen lines, while *adding a whole new skill* in the same commit. A loop that grows the library on every run is measuring its own enthusiasm. Findings should mostly delete. (Much more on this below; the development story of this library is basically one long self-improve run.)
The evolve loop
orch-evolve is tournament-style improvement over *anything*:
flowchart TD
A["incumbent artifact:<br/>a skill, an architecture, a prompt"] --> C["orch-bench: freeze criteria, task set,<br/>and judges BEFORE any variant exists"]
B["generation brief"] --> C
C --> D["spawn N variants"]
D --> E["every variant runs the<br/>same frozen task set"]
E --> F["orch-panel: blind judge lanes —<br/>no judge sees another's scores"]
F --> G["loss check: what did the winner<br/>LOSE that the incumbent had?"]
G -- "next generation" --> D
G --> H["winner replaces incumbent"]
Static artifacts work: evolve your architecture doc through five generations. Runnable artifacts work better: evolve a *skill*, where every variant replays the same frozen real-world tickets and blind judges score the outputs. The bench (criteria, tasks, judges, weights) is frozen *before* any variant exists, so nobody optimizes the goalposts. And there's a standing "loss check" criterion: what did the shiny winner lose that the boring incumbent had? That one line is the anti-Goodhart insurance for the whole loop.
Bounded runs compose with self-improvement: run 5 generations, then call self-improve scoped at the evolve run itself, "the judges disagreed twice, tighten the gates." Loops improving loops.
Architecture
Four layers. Contracts at the bottom, everything else is bricks:
orchflows
│
├── Layer 0 · contracts/ — Shared forms that keep every part of the system speaking the same language
│ ├── delegation — Says what another agent should do, use, avoid, and return
│ ├── pack-signature — Lists what every project-type setup must provide
│ ├── spec — Records exactly what the user wants made
│ ├── verdict — Records whether a check passed and what proves it
│ ├── work-item — Describes and tracks one piece of work
│ └── worklog — Records the progress and current state of a larger job
│
├── Layer 1 · skills/ — Things the agents know how to do
│ │
│ ├── kernel/ — Basic building blocks used by the rest of the system
│ │ ├── orch-check — Has a fresh agent double-check the work and correct problems
│ │ ├── orch-critique — Reviews something and lists the most important problems
│ │ ├── orch-decompose — Breaks a large job into smaller pieces in the right order
│ │ ├── orch-delegate — Hands one clearly defined task to another agent
│ │ ├── orch-elicit — Asks the user when a decision cannot safely be made for them
│ │ ├── orch-integrate — Decides whether returned work is acceptable and can be used
│ │ ├── orch-investigate — Researches one focused question using reliable evidence
│ │ ├── orch-judge — Rates one option using standards agreed on beforehand
│ │ ├── orch-mechanize — Turns a repeatedly performed step into a reusable script
│ │ ├── orch-synthesize — Combines findings from several sources into one answer
│ │ ├── orch-verify — Runs the agreed checks to see whether the work passes
│ │ ├── orch-worklog — Updates the job's progress record
│ │ └── orch-workspace — Prepares a clean and safe place in which to work
│ │
│ ├── engines/ — Reusable ways of organizing work
│ │ ├── orch-task — Takes one ready piece of work from start to acceptance
│ │ ├── orch-frontier — Starts each piece of work as soon as the work it needs is finished
│ │ ├── orch-loop — Repeats work until an agreed check says it is done
│ │ └── orch-panel — Uses several independent reviewers to compare choices fairly
│ │
│ ├── workflows/ — Complete processes made from the smaller building blocks
│ │ ├── orch-spec — Turns a request into a clear, agreed plan
│ │ ├── orch-deliver — Runs a project from the agreed plan to a checked final result
│ │ ├── orch-goal — Runs the delivery process again to improve the result further
│ │ ├── orch-bench — Sets the rules and tests before different options are compared
│ │ ├── orch-evolve — Creates and compares improved versions over several rounds
│ │ ├── orch-diagnose — Reproduces a problem and finds what is actually causing it
│ │ ├── orch-fix — Finds the cause of a problem, repairs it, and proves it stays fixed
│ │ ├── orch-repair — Applies the smallest change that fixes a known problem
│ │ ├── orch-review-fix — Reviews the result once, fixes valid problems, and checks it again
│ │ ├── orch-build — Creates or changes a reusable part of the orchflows library
│ │ ├── orch-fixture — Saves a finished task as an example that can be run again later
│ │ ├── orch-self-improve — Studies past difficulties and proposes improvements to the system
│ │ └── orch-triage — Sorts a list of work into what is ready, blocked, or needs a person
│ │
│ ├── instances/ — Skills that perform a particular kind of hands-on work
│ │ ├── orch-tdd — Writes software in small steps and checks each step with tests
│ │ ├── orch-resolve-conflicts — Decides how to combine two sets of changes that clash
│ │ ├── orch-draft — Writes one section using only the supplied information
│ │ ├── orch-edit — Combines separate sections into one consistent document
│ │ └── orch-render — Builds a screen and checks how it actually looks and behaves
│ │
│ └── utilities/ — Small optional helpers
│ ├── orch-visualize — Turns supplied information into a diagram
│ └── orch-off — Stops orchflows from automatically choosing skills
│
├── Layer 2 · packs/ — Setups for different kinds of projects
│ ├── orch-code-pack — Tells the system how to organize, save, and check software work
│ ├── orch-content-pack — Tells the system how to organize and review written documents
│ ├── orch-research-pack — Tells the system how to answer questions using trustworthy sources
│ └── orch-design-pack — Tells the system how to build and visually check interfaces
│
└── Layer 3 · compositions/ — Example playbooks showing how the parts can be combined
├── delivery-loop — Repeats delivery until a chosen measurement says to stop
├── drift-canary — Reruns known examples to detect changes in agent behavior
├── evidence-to-document — Researches a subject first, then turns the findings into a document
├── evolve — Produces several versions and selects the strongest one
├── feature-plus-docs — Builds a software feature and then documents what was built
├── improvement-delivery — Turns an approved process improvement into a tested change
├── renovate — Reviews an existing project and completes selected improvements
└── skill-tournament — Tests competing versions of a skill to see which works best
Everything couples through the six Layer-0 contracts: what a ticket is, what a verdict is, what a delegation packet carries. N workflows, M packs, and H hosts meet in six data shapes: N+M+H mutual understandings instead of N×M×H. The contracts are hash-pinned; changing one is a breaking change that has to land as a deliberate supersession, so the foundation can't drift under you while the loops run.
The other axis is *how much work* a request is. The library sizes everything on a ladder, and routing means finding the lowest rung that holds your request:
UNITS OF WORK — the orchflows ladder
│
├── (floor) Tested script
│ no model, no ticket — a unit of certainty, not of work
│ orch-mechanize keeps pushing repetition down here
│
├── U0 — Direct answer
│ question answered from context already in hand
│ no deliverable change → no record, no ticket
│ explicitly not orchflows' business
│
├── U1 — Verified ad-hoc ticket
│ │ one ticket + one execution + one external verdict
│ │ orchestrator cuts the ticket — worker never authors its own
│ │
│ │ independence law: acceptance resting only on the
│ │ executor's own artifacts is UNVERIFIED. It must enter via —
│ │ • oracle wholly pre-existing → inline OK, zero dispatches
│ │ • oracle authored-here → fresh checker context
│ │ • judged verdict → fresh context
│ │
│ └── U1×N — ad-hoc set with edges
│ small ticket graph, no spec doc, no worklog
│ runs under orch-frontier; ≤ one orch-review-fix before close
│
├── U2 — The run (spec → delivery)
│ entry criterion: a frozen spec is genuinely load-bearing
│ (must survive session death / feed blind engine reads /
│ govern enough tickets that ticket-local statements would drift)
│ ticket graph → rolling frontier → one gate → final verify
│
└── U3 — Composition
control flow OVER units, not a unit itself
chained runs, goal loops (e.g. orch-goal)
Two details I like. The *floor* of the ladder has no model in it at all: any step that repeats twice gets mechanized into a tested script, because a script is a unit of certainty, not of work. And U0 is explicitly outside orchflows' business: if you ask a question, you get an answer, no ticket. Frameworks that ceremonialize "what does this function do?" deserve their uninstall.
The packs side by side:
┌───────────────────┬─────────────┬───────────────┬───────────────────┬─────────────────────┬─────────────────────────────┐
│ pack │ delivers │ oracle class │ executor │ assembly │ workspace │
├───────────────────┼─────────────┼───────────────┼───────────────────┼─────────────────────┼─────────────────────────────┤
│ orch-code-pack │ code │ deterministic │ orch-tdd │ none — repo is it │ git (per-item worktree) │
│ orch-content-pack │ document │ judged │ orch-draft │ orch-edit │ doc tree (outline slots) │
│ orch-design-pack │ rendered UI │ captures │ orch-render │ none — views are it │ git+render (view×bp×state) │
│ orch-research-pack│ an answer │ evidence │ orch-investigate │ orch-synthesize │ evidence store (lane pkts) │
└───────────────────┴─────────────┴───────────────┴───────────────────┴─────────────────────┴─────────────────────────────┘
Visualize anything
orch-visualize renders any subject you hand it as verified diagrams: a workflow, a plan, a run's ticket graph, a trace log, a codebase, an entire agent session. It's manual-only and invisible to models, so it never fires unbidden. And it refuses to trust the model's diagram: every graph passes through a hard-coded mermaid verifier that returns the exact broken node before anything renders. (That verifier exists because of a specific painful night. See below.)
Point it at a finished orch-goal run and you get the full call graph of what actually happened: which tickets spawned which workers, what failed, what got retried. Point it at a session transcript and you get a map of an agent's evening. Every mermaid diagram in this post went through it.
How this thing actually got built
The public repo has exactly one commit: orchflows: initial public release. One tidy green square.
That commit is a lie of omission. Behind it: 9 days, 267 commits, 281 logged friction entries, ~280MB of Claude transcripts, 585 Codex sessions, one abandoned tournament, one deleted watchdog, and a multi-day bug hunt that ended with the library rewriting its own constitution. On ship day I blew away the entire history and sealed it in a private archive. Then, for this post, I pointed a team of agents at the buried transcripts and had them dig the story back out. This is what they dug up.
It started as a teardown
July 9. First session, on Codex, in a directory I'd unimaginatively named orchestrator-skills:
"in ../skills you will find matt pocock's skills which he says should be used like so: /grill-with-docs, /to-spec, /to-tickets, /implement, /code-review. I want you to deeply review the skills and understand the flow since many of these skills reference other skills."
So the library that's supposed to kill manual skill-chaining began life as a reverse-engineering job on the best manual skill chain I could find. And the first act was subtraction: "create a skills/ directory with just the skills that exist in the flow... leave out stuff like ask-matt and teach." Delete first. It set the tone.
The founding goal statement, same day, had one constraint that would tax me for the next nine days: the whole thing "should work in both codex and claude code." And the core architecture got argued out loud, me versus the model, in one of my favorite exchanges of the whole project:
"i am confused. the spec doc you gave me is building right now but it's full of json files and stuff... explain the design don't write code" "so then if it's creating basically just webs of skills, what's with all the json? why doesn't it just create skills that call other skills? no code writing" "but can't we get all of that through just subagents that spawn other subagents? then each subagent gets a simple skill? that way no subagent is overloaded with the entire workflow?... it's just a cascade"
That's the entire library in three impatient messages. Skills calling skills, dispatched to subagents, no glue code, nobody's context overloaded. Everything since is bookkeeping.
The bug I made up that was already real
Day one, the very first sessions, this started appearing in tool output:
"Python was not found; run without arguments to install from the Microsoft Store, or disable this shortcut from Settings > Apps > Advanced app settings > App execution aliases."
Windows ships a fake python that opens the app store. 112 of my Codex session files contain the string "Microsoft Store."
Two days later, designing the self-improvement loop on the Claude side, I needed a hypothetical example of the kind of friction the loop should catch, and I typed, off the top of my head:
"every time the workflow is run, an agent or subagent always tries to find python through $PATH but it should be using the bundled python"
I had invented, as my imaginary example, the exact bug that was actively destroying my sessions in the other terminal. My hypothetical was autobiography. The failure eventually got frozen into the regression suite as a named canary, wrong-python-runtime, and the fix (uv run --no-project python, codified into the repo's law file) is load-bearing to this day. The stub is still on this machine. It will outlive us all.
"wwhy does it take 30m??"
The mined transcripts are not flattering to me. Building agent workflows means testing agent workflows, and testing agent workflows means sitting there while a live end-to-end run does its thing. My contribution to the engineering process, verbatim, one night:
"wwhy does it take 30m?? Can't you design a workflow that doesn't take that long? just a fast one!" (25 minutes later) "ok hows it going why is it still taking so long" (18 minutes later) "hows it going it's been a long tie" (11 minutes later) "can you just wrap it up"
And after three consecutive background test-suite failures in forty minutes, at 2:48 in the morning, the message that best captures the dignity of the craft:
"just kill the tests and ship them ill fix them later."
The model's next action was, I swear, a single TaskStop call. All that adversarial-verification architecture, and the strongest force in the repo was still a tired guy pushing 3am. I'm told this is called "having a human in the loop."
There's a counterweight, though, and the transcripts show it everywhere: I didn't trust agreement. "Don't just agree, figure this out yourself." "Tell me your opinion of this, don't just agree with me, think about this deeply." "No, I want to know your reasoning." A model that folds when you push back is useless as a design partner, so half the design conversations are me trying to provoke the thing into having a spine.
Every skill fights for its life
The mid-project transcripts read like a purge. Real messages, hours apart:
"i dont even think I want the /find skill at all. what's the point, the model will auto determine what skill to use anyway" "lets remove wayfinder. then lets remove eval-skill. then pr merge" "ok remove prototype"
"The model will auto-determine what skill to use anyway" is the most correct line in the pile: it's the decision to delete the router and trust the model, which is the whole bet of the library. The doctrine got stated explicitly a few days later: "Every skill must fight for it's life and should only exist if we can't already abstract it away." At its peak the library had ~48 skills. It shipped with 37, and the shipped version does more.
The aesthetic standards were similarly rigorous. Tuning the visualizer, I sent the model a reference link for the flowchart style I wanted. The design review process in full:
"that's still not a pretty flowchart." (two iterations later) "sick. pr merge"
That visualizer also earned its verifier the honest way: a generated diagram silently failed to render (the model's own words mid-run: "Mermaid rejected or failed to load the first graph pass — the panel is blank") and I'd had enough of trusting diagrams I couldn't see. Hence the hard-coded mermaid verifier that pinpoints the broken node. There was no foresight involved anywhere in this library. Every safeguard exists because something ate an evening.
Terseness gets humbled
Mid-sprint I ran the experiment this whole blog has been bragging about. I took a real published skill (a 37K-line Python monster with a 2,090-line SKILL.md) and had the model rebuild it the orchflows way: a 190-line script and a 16-line skill. ~180x smaller, and it ran twice as fast. I was ready to print the t-shirts.
Then I made the model blind-rate the outputs. Original: 6/10. My beautiful terse rebuild: 3/10. Reddit came back 403-dead, engagement numbers were missing. All that bloat I'd been sneering at was partly scraper scar tissue: accumulated workarounds for real-world hostility that a terse rewrite cheerfully deleted. V2 got back to 6/10... and was now *slower than the original*.
I kept the terseness religion (the caps are still validator-enforced) but the sermon got more specific: keep the instructions terse and keep your hands off the checks. The rebuild failed because the checks were load-bearing and I deleted them along with the prose. That distinction (contracts are sacred, method is substitutable) is now the actual law of the library, and it came from losing this bet.
Same day, I dogfooded /orch-evolve for the first time as a full tournament: one designer model proposing four structurally distinct candidates, four Sonnet workers building them blind, judge panels to follow. The workers finished. The judges never ran. I halted the whole thing at ~545k subagent tokens across 11 agents, with no champion ever crowned. An expensive lesson in why orch-bench now exists: freeze the criteria, the task set, and the judges *before* any candidate exists, or you'll be five hours and half a million tokens deep with no way to score what you built.
Burning it down
July 15, ~9pm, the message that reorganized everything:
"I am realizing I'm building something akin to a programming language for the orchestrator > subagent pattern."
A language: skills are statements, contracts are types, packs are stdlib bindings per domain, and the orchestrator is the runtime. Once I saw it that way, the existing repo was unsalvageable in shape. This was the state of it, 48 skills of accumulated cleverness:
Wrong primitives, wrong boundaries, tiers organized for *me* browsing the repo instead of for an agent resolving a skill mid-run. (I'd literally asked the model earlier: "Think about your own thinking. If you were an agent reaching for skills, what would make it easiest for you?" and then ignored the answer for four days.) So:
"go ahead and remove all the old orchflow skills"
Total rebuild from scratch. Four layers, six hash-pinned contracts at the waist, every skill re-admitted through the new validator or not at all. The rename to orchflows happened in this same stretch. In the finest tradition of this project, I used the library's own flagship orch-goal workflow to do the rename. It renamed every file, every reference, 13 worktrees, and the GitHub repo... and then hit a wall, because a Windows process cannot rename the directory it's standing in. The model's status report is going on my wall: "this session physically cannot rename the directory it's running inside." It ended up leaving behind a detached watcher script to finish the job the moment the session died. The self-improving orchestrator renamed its entire world except the ground under its own feet.
The bug that bit the review that was hunting it
This is the one bug that stalked the whole project.
Subagents kept finishing their work perfectly, ticket done, diff clean, and then going silent. No final report. The orchestrator sits at the join staring at an idle child, then has to crack open the ticket files and read the diff itself to find out what happened. It happened on day 2. It happened on day 5. The friction log kept counting: occurrence 3, occurrence 4...
First fix attempt: build a watchdog. A deterministic script that monitors children and alerts when one stalls. Spec'd, reviewed, shipped as its own PR. Weeks later (okay, *days*, everything here is days) the friction log delivered its verdict: the original failure mode, still occurring, on both hosts, with no watchdog alert observed. The fix didn't fix. The watchdog got deleted from the library entirely.
The actual root cause fell out of a three-lane research dispatch much later, and it was nobody's fault but mine: the harness's teammate transport drops a child's plain final text by design. It's in the docs. A child's normal closing message simply never gets delivered to anyone. The children were shouting into a disconnected pipe the whole time, and every "child under-delivered" blame record in my logs was actually me under-specifying the return channel.
The bug even bit the review that diagnosed it. During a 13-lane parallel review of the library, six of the thirteen reviewer lanes went silent and had to be individually nudged for their findings, and among those findings was the diagnosis of why lanes go silent. The fix went in as a constitutional amendment: delegation rule 10, *artifact primacy*. A child's result must live in a durable artifact its packet names; the closing message is just a pointer to it. If the pointer gets dropped, the result still exists. The contract got superseded, every workflow inherited the rule, and silent children stopped mattering the same day.
The loop that says no
Whether the self-improvement stuff actually works comes down to what it *refuses* to do, and my favorite receipts are the ones where the machinery embarrassed itself first:
- The friction logger lost its own friction entry: invoked from a worktree, it wrote the entry into the worktree's
.orch, which got deleted with the worktree, taking the record of the failure down with it. (Fixed; the fix was itself a mined proposal, and my ruling on the heavy-handed alternative is preserved verbatim in the record: "let users shoot themselves in the foot.") - The trace miner once returned zero observations over 2,451 events from two sessions riddled with dozens of known tool failures, because its failure-detector only recognized one exit-code phrasing. It couldn't see the exact class of problem it was built to find.
- The capture hook was double-writing every ledger record, inflating friction counts 2×. And the improvement policy *forbids the loop from proposing fixes to its own machinery*, so it had to flag itself for a human instead of rewriting its own evidence pipeline. That paranoia is on purpose; the alternative is a self-improvement loop that gets to edit its own report card.
- Of the first three full mining cycles over 281 friction entries, the number of improvement proposals emitted was zero, zero, and zero, with the disqualification reasons written down each time ("single occurrence, no library owner text contradicted"). A loop that only speaks when it has recurrence plus a checked contradiction is a loop you can leave running.
- And when a proposal did qualify (the python-stub one, naturally), its recommended fix was
py -3. The proposal's own critique pass caught thatpyisn't on this machine's PATH either, meaning the proposed improvement wouldn't have prevented its own motivating friction. Both findings fixed before the proposal was finalized. The improvement loop caught its improvement being wrong.
That discipline is what made the flagship run trustworthy. July 17 was the biggest day of the project (106 commits) and it rolled into the 14-lane library review I mentioned up top: 108 raw findings, deduplicated to 6 root causes, closed at net −14 lines while adding a new kernel skill. The model's own summary line from that session is the best one-sentence definition of self-improvement I've seen, so I'm stealing it:
"This deletes ~15 findings and — more importantly — makes them unrecurrable, which is the only way the 10th review run gets shorter than the 1st."
Ship day
July 18. "Alright we're shipping today... we need to blow away all commit history." Full backup first (14,627 files mirrored, zero failures), then a production audit that stripped 18 maintainer-only improvement proposals and every other piece of local-dev laundry, then a brand-new repo: MIT license, 153 files, all checks green, one commit.
The 267-commit history, every friction entry, every zero-proposal mining cycle, every deleted watchdog, went into a private archive. Which means the public story of a *self-improving* library shipped with the self-improvement scrubbed out. This post is the missing history, excavated by the tooling it documents: I gave agents the transcript directories and told them to mine the whole mess for the parts worth telling. A couple of the mining agents finished their digging and went idle without sending their reports back, which is the exact silent-child behavior described eleven paragraphs ago, now downgraded from bug to personality trait. They got nudged, per the law the bug produced.
Nine days. The library reviewed itself, deleted parts of itself, caught its own fixes being wrong, and got shorter while getting stronger. And on this machine, typing python still opens the Microsoft Store.
Clone it, break it, log the friction. The library will read your complaints and draft its own fix. That's the whole point.
github.com/DanMcInerney/orchflows