The orchestrator that learns which model to trust
You have five AI models on tap — Claude, GPT, Kimi, GLM, MiniMax — and a steady stream of jobs to run: “research this topic,” “implement this fix,” “review this diff.” Two questions decide your bill and your quality, and you’re probably answering both by guessing:
- Which model should handle this job?
- Is that still the right answer a month from now?
The problem: your orchestrator picks once and never learns
Most setups answer question one by hardcoding a choice — usually the cheapest model, or the one that looked best the day you wired it up — and answer question two never. The config you wrote in March is still routing your jobs in September, even though the models have shifted underneath it and you’ve accumulated thousands of runs of evidence about which one actually wins each kind of work. Nothing reads that evidence. Nothing acts on it.
So you land in one of two bad spots. Either you play it safe and send a frontier model at everything — paying premium rates for jobs a cheap model would have nailed — or you guess cheap and quietly ship worse results on the jobs that needed the strong model. Both are the same underlying failure: you’re routing blind, and the routing never improves.
An orchestrator that always routes the same way isn’t orchestrating. It’s a static config file with extra steps.
mini-ork is a CLI agent orchestrator built to fix exactly this. It treats every model as a contestant, every run as a graded match, and sends the next job to whoever has been winning — automatically, and for reasons you can read off a SQLite file by hand.
How it solves it: make the models compete, then keep score
mini-ork runs your workflow across competing model “lanes” — opus_lens, codex_lens, kimi_lens, glm_lens, minimax_lens. After each run it scores what happened and writes the scores to a local state.db. Before the next run, a router reads those scores and decides whether the evidence justifies moving a job off its default lane.
flowchart TD
RUN["A run finishes\n(lanes competed in parallel)"] --> SCORE["WRITE HALF\ngrade every run"]
SCORE --> DB[("state.db\n(plain SQLite)")]
DB --> ROUTE["READ HALF\nrouter reads the scores"]
ROUTE --> GATE{"Enough evidence?\nsamples high enough\nAND a lane is clearly ahead?"}
GATE -->|yes| FLIP["route this job →\nthe winning lane"]
GATE -->|no| STAY["stay on the\ndefault lane"]
FLIP -.->|next run| RUN
STAY -.->|next run| RUN
The grading is deliberately boring — no neural network, no training run, just arithmetic you can audit. Two scores carry the weight:
- Grade each run on its own. A six-term checklist (did it succeed, call tools, touch files, get approved, run for a sane duration, cost more than zero) adds up to a number between 0 and 1. Simple enough to verify by eye, which is the point when wrong routing spends real money.
- Grade each model against its rivals. A score means nothing until you know what the other lanes got on the same job. So for each job type, mini-ork takes every lane’s result and expresses it as “how many standard deviations above or below the group average was I?” — a move borrowed from a reinforcement-learning idea called GRPO.
If you want the actual arithmetic, it stays small enough to fit in your head. Each run earns a process reward from six yes/no signals:
Each bracket is 1 when true and 0 when not. The two activity terms are capped together at 0.15, so a noisy run that failed but touched a pile of files can’t outscore a clean success. And the approved term only counts when the run also succeeded, so a generous judge can’t rescue a failure.
Then each lane’s reward on the same job type is turned into a z-score against the group it competed in:
Three pieces, nothing more. is lane i’s own reward from the formula above. is the average reward of every lane that ran this same job type. is how spread out those rewards were. Subtract the average and divide by the spread and you get : how many standard deviations above or below the field that lane landed. Positive means it beat the room, negative means it lagged, zero means it was dead average.
Walk one through. Say three lanes take the same research job and earn rewards of 0.95, 0.70, and 0.55. The average is . The spread works out to . So the top lane’s advantage is , and the bottom lane’s is . Same raw rewards, but now they’re on a scale the router can compare across wildly different job types.
That is the relative advantage in the table below (mini-ork weights more recent runs a little heavier, so the live numbers won’t match this hand example exactly, but that’s the shape). The σ=0 guard further down is just the denominator talking: if every lane scored the same, , so mini-ork records instead of dividing by zero.
Here’s the same three lanes as a real slice straight out of state.db after that research run:
| Lane | role | relative advantage |
|---|---|---|
codex_lens | researcher | +0.90 |
kimi_lens | researcher | −0.07 |
glm_lens | researcher | −1.18 |
Read it directly: on this job type codex_lens ran about 0.9 standard deviations better than the field, glm_lens about 1.2 worse. That’s the table that told the router to stop defaulting to the cheap kimi_lens and start sending research jobs to codex_lens.
And there’s one guard that makes the whole thing trustworthy rather than hand-wavy: if every lane scored the same, or only one lane ran, the spread is zero and mini-ork records zero advantage. No flip.
No competition, no learning. The system refuses to manufacture a signal out of a single data point — it would rather learn nothing than learn something fake.
The router only moves a job off its default once there’s enough evidence and a lane is clearly ahead. “Enough evidence” is a minimum sample count on the prompt’s win rate, , with ties left out of the denominator so a string of vacuous runs can’t fake confidence. “Clearly ahead” is the positive from above. Until both clear, it stays on safe defaults. That gate is the difference between “measured improvement” and “a model gambling with your budget.”
How that’s different from LangGraph, CrewAI, AutoGen, and the OpenAI Agents SDK
To see what’s actually new here, ask the popular agent frameworks the same question: when a step needs to run, how do they decide which model or agent handles it? We read the routing code in each. The answers cluster into three patterns — and none of them is “remember who won last time.”
Everyone else decides routing fresh every run — a hardcoded edge, a fixed order, or an LLM picking in-context — and then forgets. mini-ork is the one that keeps score.
LangGraph models a workflow as a graph you wire by hand. Routing happens through add_conditional_edges — developer-written functions that read the current state and return the next node — plus Command(goto=...), which lets a node hand control to another. It has durable, checkpointed state, but that state is the conversation and graph position, never a record of which model performs best on which task. The topology is whatever you drew; it doesn’t move on its own.
CrewAI offers two process modes: sequential (tasks run in a fixed order) and hierarchical, where a manager_llm reads the goal and delegates to worker agents. The manager is smart, but it reasons from scratch in its context window every time; nothing persists about which agent or model actually delivered last week.
AutoGen runs multi-agent conversations, and its SelectorGroupChat picks the next speaker by formatting a selector_prompt and asking an LLM to name one — _select_speaker literally calls model_client.create() each turn. A fresh, prompted choice from the transcript, with no memory of which speaker tends to win this kind of task.
OpenAI Agents SDK — one of the most-adopted frameworks of 2026 — routes through handoffs: each agent exposes a transfer_to_<agent> tool, and the running LLM decides in-context which one to call. It’s clean and provider-agnostic, but the handoff target is chosen fresh from the prompt every time — the SDK keeps no memory of which agent tends to win a given kind of task. (Reading the source confirms it: handoffs are everywhere, and there isn’t a single reward, win-rate, or advantage signal in the routing path.)
| System | How it picks who runs a step | Routing learns from past outcomes? |
|---|---|---|
| mini-ork | Model lanes compete; router flips to the empirically-winning lane, evidence-gated | Yes — scores persist in state.db and re-route the next run |
| LangGraph | Hand-wired graph edges + conditional functions + LLM Command handoffs | No — topology is fixed; state is conversation, not performance |
| CrewAI | Fixed sequential order, or a manager_llm delegating in hierarchical mode | No — the manager re-decides in-context and forgets |
| AutoGen | SelectorGroupChat prompts an LLM to name the next speaker each turn | No — a fresh prompted choice from the transcript |
| OpenAI Agents SDK | LLM calls a transfer_to_<agent> handoff tool, chosen in-context | No — handoff target re-decided each turn, nothing remembered |
To be fair: LangGraph, CrewAI, AutoGen, and the OpenAI Agents SDK are broad, mature platforms — durable execution, tooling, human-in-the-loop, huge ecosystems — and mini-ork doesn’t try to replace any of them. The comparison is narrow on purpose, on one axis: does the orchestrator measure which model wins and re-route accordingly? On that axis, the others route statically or ask a model to choose in the moment. mini-ork is the only one that treats routing as something to measure and improve over time rather than decide and discard.
How to use it for your own good
The payoff is concrete, and it’s mostly about money and trust:
- Stop overpaying. Pin your jobs to cheap lanes by default and let mini-ork escalate to an expensive model only where the evidence says it’s worth it. You stop paying frontier rates on jobs a cheap model handles fine, without having to figure out which jobs those are by hand — the data does it.
- Get an audit trail, not a black box. Every routing decision is reproducible from SQL. When someone asks “why did this go to the expensive model?”, the answer is a row you can point at, not a shrug. That matters when the bill or the output is being questioned.
- Tune how bold it is with one knob.
MO_LEARNING_MIN_SAMPLES(default 3) controls how much corroborating evidence the router demands before it commits budget to a switch. Crank it up to be conservative; drop it to 1 to watch the loop flip after a single round when you’re demoing or experimenting. - Keep your existing stack. The learned router is orthogonal to the workflow engine underneath it — you can run mini-ork in front of a LangGraph node or a CrewAI crew. You’re adding a routing brain, not rewriting your agents.
- Let failures help you. A lane that produces an empty or rejected artifact doesn’t crash anything; it just earns a negative advantage and gets routed around. Bad runs make the routing better, automatically.
One clarification, since people assume it’s all one system: mini-ork pairs with ContextNest, a separate memory service, but ContextNest sits beside the routing loop, not inside it. It prefetches relevant memory to make each run better-informed; it never touches the scores that flip the router. One service makes each run smarter about context, the other makes the next run smarter about routing — two orthogonal wins you can adopt independently.
The takeaway
If you’re running multiple models behind one orchestrator, the question isn’t “which model is best?” — it’s “is anything measuring which model is best, and acting on it?” For LangGraph, CrewAI, AutoGen, and the OpenAI Agents SDK the honest answer is no: they route blind and forget. mini-ork’s answer is a loop you can read end to end — grade each run, compare lanes on the same job, flip only when the evidence is real — and the result is routing that gets cheaper and better while you do nothing.
Point it at your own jobs and watch the table fill in. The first time you see VERDICT: LEARNING OBSERVED — router moved kimi_lens -> codex_lens scroll past, it stops being a config file and starts being an orchestrator.
Further reading
- mini-ork source: SourceShift/mini-ork. The learning signals live in
lib/process_reward.sh(per-run grading),bin/mini-ork-execute(the comparison + router), andlib/rho_aggregator.sh(prompt-level win rates). - The full technical breakdown — exact formulas, worked z-scores, and the signal-to-table map — is in the repo’s
docs/research/articles/how-mini-ork-learns.md. - The process-reward and group-relative ideas are grounded in the literature the code itself cites: arXiv:2510.08049 and arXiv:2602.09305 (process reward), arXiv:2606.05922 (prompt-level optimization).
Comments
Sign in with GitHub to leave a comment. Threads live on SourceShift/blog-comments — moderated.