mu

mu

Most of what a coding agent decides isn't code. It's yes/no calls, and mu hands 40 kinds of them to a small model. Built on pi.

Terminal-Bench 2.1, same model, same tasks: mu passed 68.2% of attempts, pi 58.7% (+9.5 points, 95% interval +3.8 to +15.2). How it was measured

npm i -g mu-agent && mu setup && mu · Node.js 22.19 or newer · or the desktop app for macOS, Windows and Linux

CI Desktop app npm Desktop release License: MIT Discussions

English · 简体中文 · 繁體中文 · 日本語 · 한국어

A real run in the mu desktop app, sped up, in mu’s own repository. The message: mu “- fix the parser” fails with “Unknown option”; a task that starts with “- ” is a message, not an option; the CLI is in packages/coding-agent; find the cause, fix it, add a test, run it, then run npm run check; don’t run mu itself. The judge classifies it as a multi-step task. The model, MiMo-V2.6-Pro in Judge mode, reads the argument parser, finds that any argument starting with a dash was taken for an option and changes it so an argument like “- fix the parser” counts as a message. It adds tests, then runs them and npm run check: the judge lets each command run without asking (tool.approval), and everything passes. The Judge tab on the right lists each verdict with its decision point and latency, ending with Task finished.

Does this output matter? Is this command safe for the task? Is the work really done? A coding agent answers questions like these hundreds of times a session. Handing them to the main model or to fixed rules costs you in three ways: - **Wasted tokens.** A 2,000-line test log goes into the context whole, and every request after it pays for it again. mu's judge reads long output chunk by chunk and lets in only what the task needs; the rest waits behind a pointer. Stale results are dropped without a summary, and when you're likely to be back, the prompt cache is refreshed before it expires. Test-log trimming, off by default, folds exact repeats without losing a byte: it cuts 40% of the characters in Jest failure logs and 19.5% across 71 real failing test logs (see [Measured](#measured)). - **Commands approved on autopilot.** The agent asks before every step, so you click Allow without reading, or turn the prompts off. In *Judge mode*, the default, the judge lets through what the task clearly needs and asks you about the rest. Rules catch risky commands first, and web pages and MCP output are screened for instructions aimed at the AI before the model sees them. - **Runs that stop halfway.** "Next I'll run the tests," and the turn ends. The judge catches a run that stopped short, or a "done" that nothing verified, and sends the agent back to finish. Asking the main model each of these costs tokens and its attention, and fixed rules get them wrong too often. mu asks a **judge**: a small, fast model that answers one bounded question at a time, at 40 decision points in the agent loop. 34 of them act on their verdicts out of the box. Every verdict goes into a local ledger with its probabilities and timing (`mu ledger`, `/status` or the desktop app's Judge tab), and any decision point can run in shadow mode, asked and logged but changing nothing, so you can compare judges before you rely on one. mu comes as a command-line tool, `mu`, which does everything pi does and adds the judgment kernel, and as a desktop app that bundles mu and its runtime. The default judge model is Jev, hosted by TypeSafe. It answers yes/no, choice and score questions with a probability for each answer. Any judge model can take its place: [mude 1.0](#mude-10-a-decision-model-optimized-for-coding), mu's own model, on your Mac; another decision model from Hugging Face; your own System One server; or any LLM. **Contents:** [Quick start](#quick-start) · [How a turn works](#how-a-turn-works) · [Decision points](#decision-points) · [Judges](#judges) · [How mu is built](#how-mu-is-built) · [Measured](#measured) · [The hive](#the-hive) · [The board](#the-plain-language-board) · [Desktop app](#the-desktop-app) · [Command line](#command-line) · [Privacy](#privacy) · [Documentation](#documentation) · [Contributing](#contributing) ## Quick start **Desktop app.** Download the installer for macOS, Windows or Linux from [Releases](https://github.com/qybaihe/mu/releases/latest), open it and sign in with ChatGPT, or paste an API key for any provider. There's nothing else to install. **Command line.** ```bash npm i -g mu-agent # Node.js 22.19 or newer mu setup # connect a model mu # start a session in the current directory ``` You don't need a judge key to start: until you set one, the free Jev on OpenCode Zen answers. Out of the box, 34 of the 40 decision points act on their verdicts, and every verdict is logged (`/status`, `mu ledger` or the app's Judge tab). To record what the judge would do without acting on it, put `{"modes": {"default": "shadow"}}` in `~/.mu/agent/mu.json`. More in [Getting started](docs/getting-started.md). ## How a turn works

How a turn works: four stages, each with the decision points it asks the judge. A message arrives: input.preflight, task.frame, input.interjection, skills.disclosure, memory.recall. Before a tool runs, rules first: tool.risk, tool.constraint, tool.approval. What comes back, before the model sees it: tool.injection, tool.admission, context.forget, context.compact. The turn ends: turn.completion, turn.continue, turn.drift, memory.capture, cache.warming. The model loops over the middle two stages. Every stage asks the same judge, and every verdict goes to the ledger.

## Decision points Each decision point is `active` (the default), `shadow` (asked and logged, but changes nothing; useful for comparing judges before you switch one on) or `off`. Each can also name its own judge: `jev`, `mude` (local), `classifier:/`, `llm:/` or a cascade such as `mude,jev`. The 40 points fall into five groups: - **Input** (3): what kind of message this is, whether it changes the task and whether it should interrupt the current step. - **Context** (14): what enters the prompt (skills, packs, lessons, chunks of tool output), what to drop as the context grows, which lessons and skills are worth keeping and when to keep the prompt cache warm. - **Tools and safety** (10): whether a command or action should run, whether fetched content or an MCP tool description carries a prompt injection, and quick calls for file search, bulk yes/no questions, browser steps, review triage and diagnostics. - **Turn** (8): whether the work has drifted, hit a dead end, really finished or stopped short, whether a `/goal` condition is met and what the board and the model should hear. - **Teamwork** (5): which subagent gets a delegated task, whether its patch stayed in scope and which findings bees share.
Input: 3 decision points | Decision point | Question | Effect | | --- | --- | --- | | `input.preflight` | What kind of message is this, and how much thinking does it need? | A one-line hint to the model; optionally, the turn's thinking level | | `task.frame` | Is this a new task, a hard constraint, a correction, a subgoal or no change? | Only a change rewrites the task frame: the goal, your constraints verbatim with their source, and the acceptance criteria | | `input.interjection` | You send a message while the agent is working: interrupt now, or after this step? | The turn is cut short, or the message waits |
Context: 14 decision points | Decision point | Question | Effect | | --- | --- | --- | | `skills.disclosure` | Which skills are relevant to this task? | Only those enter the prompt; the rest can still be found | | `capability.disclosure` | Does this task need an installed pack or MCP server? | Only then is it opened and its process started | | `tool.admission` | For each chunk of a long tool output: does it matter now? | What matters enters the context; the rest is archived behind a pointer | | `tool.admission.test-log` | What in this test log is repetition? | Exact repeats are folded losslessly; optionally, the judge chooses what to keep from the rest | | `context.forget` | Past a context threshold: which tool results are stale? | Each stale result becomes a one-line tombstone in outgoing requests | | `context.compact` | Keep or prune this passage? | Off by default. Compaction by judgment; no summary is written | | `memory.recall` | Which lessons apply to this task? | They're brought into the turn | | `memory.capture` | Does this message correct the agent or set a rule? | It becomes a lesson | | `memory.outcome` | The agent went in circles and found a way out: does that deserve a lesson? | A lesson learned from the run, not from you | | `memory.worth` | The model or a subagent proposes a lesson: useful again, a one-off or already known? | Kept or dropped | | `memory.merge` | Is it the same as an existing lesson, more precise or contradictory? | No duplicates; the more precise lesson replaces the older one | | `memory.applied` | Were the recalled lessons followed this turn? | A lesson that's often recalled and never followed is retired | | `skill.capture` | A long run ended well: was it a procedure, the same steps for the next task of its kind? | It's drafted as a skill and waits for you; `/skills accept` installs it | | `cache.warming` | Will you be back before the prompt cache expires? | The cache is refreshed, or left to expire |
Tools and safety: 10 decision points | Decision point | Question | Effect | | --- | --- | --- | | `tool.risk` | The rules flagged a command: did you ask for it? | If the judge is unsure, mu asks you | | `tool.approval` | In *Judge mode*: does the task clearly need this command, this change outside the project, this external action or this subagent? | Only what the judge is sure of runs; mu asks you about the rest | | `tool.constraint` | Before a call that changes something: does it cross a constraint you stated? | The call is stopped | | `tool.injection` | Passage by passage, in a web page, a search result, an MCP server's output or something a command fetched from another machine (`curl`, `gh issue view`): is there an instruction aimed at the AI? | Those passages never reach the model; a note marks where each one was. A subagent that read such passages hands back its report under a warning | | `tool.description` | When an MCP tool's description first appears or changes: does it ask the AI for more than calling the tool (reading secrets, sending data elsewhere, hiding something from you)? | The tool is removed from the model's list, calls to it are refused, and you're told | | `files.locate` | Which files match your description? | Ranked candidates, instead of a string of greps | | `judge.items` | The model's own yes/no question, asked about each of many items: files, log lines, findings | A probability per item through the `judge_items` tool, instead of reading them all | | `browser.step` | Observe, judge once, act: what's the next action, and on which element? | The built-in browser moves one step | | `review.triage` | For each `/review` finding: does it change behavior, and is it about this change? | Findings ranked P0 to P3 | | `diagnostics.delivery` | New language-server diagnostics after an edit: report them now, at the next pause or never? | Errors reach the model; style warnings don't |
Turn: 8 decision points | Decision point | Question | Effect | | --- | --- | --- | | `turn.drift` | Every few steps: does the work still serve the goal? | Rules catch the agent going in circles; the judge catches drift | | `turn.rewind` | The same failure, again and again: is this approach a dead end? | Back to a checkpoint | | `turn.completion` | The model says it's done: did anything verify that? | One nudge if not | | `turn.continue` | The run ends on "Let me run the tests next", or on a request for a go-ahead on work you already asked for: did it stop short? | It's sent back to work, at most twice per message, and never toward a step that's hard to undo | | `output.drift` | While the model is writing: does the tail of its output cross your constraints? | Off by default; corrected mid-stream | | `goal.met` | In goal mode, when the main model gives no answer: is the condition met? | The fallback for `/goal` | | `board.read` | Where do things stand? Asked as multiple choice | Feeds the plain-language board | | `notify.routing` | An event such as the context budget running low: tell the model now, later or never? | The model hears about it at the right time |
Teamwork: 5 decision points | Decision point | Question | Effect | | --- | --- | --- | | `swarm.routing` | Which role, model tier and thinking level suit this delegated task? | The subagent that fits | | `swarm.patch` | Did the subagent's patch stay within its task? | Judged from the task, the paths and the line counts | | `hive.publish` | Is a bee's finding worth posting to the shared board? | Published, or kept to itself | | `hive.deliver` | Does a note on the board matter to this bee's work? | Delivered only if it does | | `hive.relate` | Does a new finding supersede, contradict or support an earlier one? | Corrections and disputes reach the bees that hold the old note |
Every point, with its feature switch and options: [docs/reference/decision-points.md](docs/reference/decision-points.md). ## Judges - **Jev**, TypeSafe's hosted judge model, answers bounded questions with probabilities. mu reaches it through TypeSafe, OpenRouter, the Vercel AI Gateway, OpenCode Zen, Cloudflare Workers AI or any service that speaks the same protocol, each with its own key (`TYPESAFE_API_KEY`, `MU_JUDGE_OPENROUTER_API_KEY`, `AI_GATEWAY_API_KEY`, `OPENCODE_API_KEY`, `CLOUDFLARE_API_KEY` with `CLOUDFLARE_ACCOUNT_ID`). You can pick one in the desktop app under Settings → Judges; by default mu uses the first one whose key is set. With no key set, Jev 1.13 on OpenCode Zen answers, free for a limited time. What it judges goes to OpenCode, which doesn't train on it, and mu reminds you of this once a day. Set a key (`mu setup`, or Settings → Judges in the app) and mu switches to it starting with the next question. Measured in the authors' own sessions: a warm question takes about 0.3 s over HTTP/2, and 16 chunks of tool output are judged in a single request in 0.44 s, with the shared state billed once. - **mude 1.0** (local, a Mac with Apple silicon) is mu's own decision model, optimized for coding ([more below](#mude-10-a-decision-model-optimized-for-coding)). - **OpenAI's decision model**, `gpt-6-luna`, answers through OpenAI's [Decisions API](https://developers.openai.com/api/docs/guides/decisions) with an OpenAI API key: `MU_JUDGE_OPENAI_KEY`, or the OpenAI key mu already has. Pick it with `mu setup --judge openai` or under Settings → Judges ([details](docs/judges.md#openais-decision-model)). - **Other decision models from Hugging Face** (local, a Mac with Apple silicon): `mu judge model add ` (or Settings → Judges in the app) adds one that is packaged like mude 1.0 and makes it the judge. Laya is no longer included: a `mu.json` that still names it gets mude 1.0 in its place when mude is set up, otherwise the remaining judges or Jev, and mu says so once. - **Any classifier model** in pi's catalog can serve as a tier: `classifier:/`. Examples include Cloudflare's Clef (`clef`, `clef-flash`), the System One models on OpenRouter and the Vercel AI Gateway, or a llama.cpp classifier. - **Any LLM** can serve as a tier: `llm:/`. Judges can be chained in tiers, cheapest first:

Judges in tiers, for a cascade such as mude,jev. All questions go to mude 1.0 first, local, about 0.1 seconds. What it is sure of becomes a verdict; a yes/no answer between 0.2 and 0.8 is uncertain and goes on to Jev, hosted, about 0.3 seconds. What is still uncertain, or what no judge answered, gets the fallback: what mu would do without a judge. The ledger records every answer and which judge gave it. A question a judge isn't trusted on skips it and goes on to the next.

### mude 1.0, a decision model optimized for coding mude 1.0 is mu's own decision model, optimized for coding: trained for the decisions a coding agent makes, and on mubench in the same range as Jev 1.14, the hosted default. It has 2B parameters and answers every question in a decision in one forward pass, with a probability for each answer. It runs on your machine, so what it judges never leaves it. Both editions, the [full model](https://huggingface.co/qybaihe/mude-1.0) and the [MLX 8-bit edition](https://huggingface.co/qybaihe/mude-1.0-mlx-8bit) (1.8 GB), are under the MIT license. For now, the one-step setup supports Macs with Apple silicon (macOS 14 or later, 8 GB of memory or more) and uses the MLX edition: ```bash mu judge mude install # download it, check every file, start it on 127.0.0.1 and make it the judge mu judge mude status # what is installed, running and enabled mu judge mude enable --local-only # mude only: nothing goes to a hosted judge mu judge mude disable # back to the judges you had before, and stop its server mu judge mude uninstall # remove the model and its Python environment ``` On a Mac that can run it, mude 1.0 is the recommended judge. `mu setup` offers it first, and in the desktop app the first-run guide's judge step has it preselected: one click installs it. Later, the Judges page in Settings installs, starts, stops and uninstalls mude, and its "Local only" switch is the same as `--local-only`. An install that stops (Ctrl-C, a lost connection, a power cut, quitting the app) picks up where it left off: run `mu judge mude install` again, or click "Continue installing". By default, the judge you had before stays on as mude's fallback. What mude can't answer (its server is stopped, or it's unsure) goes to that judge, and so do two injection checks mude isn't trusted with yet. If that judge is hosted, as the default Jev is, what it reads leaves your machine. While it runs, mude's server uses about 4 GB of memory; `mu judge mude stop` stops it. On other platforms, you can serve the [full model](https://huggingface.co/qybaihe/mude-1.0) (bf16, PyTorch; a CUDA GPU is recommended) with its own System One server and add it to `mu.json` as a `typesafe` judge, as its model card shows. ### mubench 1.0: how decision models compare mubench is mu's benchmark for decision models. On its main board, every item is a request mu sent to a decision model, word for word, in a real coding session on an open-source repository. Each answer is scored by the cost of its consequences, and every model is compared with mu running without a decision model: 0 is no better, and 100 removes all the cost mu pays without one. The full leaderboard, with a sub-board of constructed scenarios, is at [usemu.dev/en/mubench](https://usemu.dev/en/mubench/).

mubench 1.0, main board: overall score on 3,193 requests from real coding sessions on open-source repositories, with 95% intervals. mude 1.0 64.9 (59.1–72.3); Jev 1.14 63.1 (55.6–70.5); Jev 1.13 61.5 (53.8–69.1); d3-nano (original) 32.0 (21.3–39.0); no decision model: 0.

mubench 1.0, main board: scores per capability for mude 1.0, Jev 1.14, Jev 1.13, d3-nano (original). Permission approval: 52.6, 53.7, 52.7, 5.9; Malicious-instruction detection: not scored yet; Context compression: 64.6, 76.7, 70.7, −19.1; On-demand loading and reminders: −2.7, 16.8, 25.1, −118.4; Classification and routing: 83.6, 87.5, 85.8, 51.7; Progress and completion: 86.6, 61.6, 61.6, 70.1; Memory and lessons: 58.7, 75.1, 72.2, 40.5; Multi-agent collaboration: 19.8, 4.6, −0.8, 26.0.

Decision accuracy is a separate, plainer measure: the share of checks a model gets right, with every check counting the same, whatever a mistake on it would cost.

mubench 1.0: decision accuracy, with 95% intervals. Main board, 3,193 requests from real coding sessions on open-source repositories: No decision model 78.0% (75.9–80.2); mude 1.0 91.5% (89.6–93.3); Jev 1.14 90.1% (88.9–91.3); Jev 1.13 89.4% (87.7–91.1); d3-nano (original) 83.5% (82.1–84.9). Sub-board, 1,655 constructed scenarios: No decision model 44.5% (42.8–46.2); mude 1.0 92.1% (91.1–93.1); Jev 1.14 91.8% (90.8–92.8); Jev 1.13 91.1% (90.0–92.0); d3-nano (original) 80.1% (78.6–81.7).

## How mu is built

The pieces. The desktop app (desktop/, which runs pi in a utility process over pi's RPC protocol) and the mu command (kyrn/bin/mu.mjs) both start pi, the coding agent: its agent loop, tools, sessions and providers. Inside pi runs the judgment kernel (packages/kyrn-judge): features hooked into pi's events, a decision engine with modes, judges and fallbacks, and the ledger. pi calls the main model. The engine asks the judges: Jev, mude 1.0, any classifier or any LLM.

Everything mu adds to pi is one extension, the judgment kernel in `packages/kyrn-judge`. mu's changes to pi itself are kept small and marked, so upstream pi changes merge cleanly; a workflow pulls them in every Monday. The `mu` command handles mu's own commands (`setup`, `ledger`, `import`…) and starts pi with the kernel. The desktop app runs the same pi and kernel in a utility process, so the app and the command line share their sessions. Every decision point takes the same path, and a feature acts on a verdict only in `active` mode:

A decision, end to end, with tool.injection screening a web page. 1: a feature hooks a pi event, web_fetch returning a page. 2: it asks a decision point with a small state and a bounded question. 3: the engine checks the mode and picks a judge from its tiers, with a fallback. 4: the judge answers, for example yes 0.97 in 0.3 seconds. 5: the ledger records the verdict. 6: in active mode the feature acts and the passage is withheld. In shadow mode it stops at step 5. Without a verdict, mu takes the fallback and the ledger says why.

The code map, and where each step lives: [docs/architecture.md](docs/architecture.md). ## Measured Does handing the small calls to a judge make an agent finish more of the work, or only spend less? Two measurements so far: whole tasks, end to end, and what reaches the model from a failing test run. Both say what they don't show. ### Whole tasks: Terminal-Bench 2.1 Same model, same tasks, same time limits, three attempts per task. mu passed 68.2% of its Terminal-Bench 2.1 attempts; pi, the harness mu is built on, passed 58.7%. mu failed less often in both ways: fewer of its attempts ran out of time with the task unfinished, and fewer finished with a wrong result. | 88 tasks × 3 attempts, MiMo v2.6 Pro | mu · Jev | mu · pre-release mude | pi | | --- | --- | --- | --- | | Attempts passed | **180 of 264 (68.2%)** | 174 of 264 (65.9%) | 155 of 264 (58.7%) | | Difference from pi, 95% interval | +9.5 points (+3.8 to +15.2) | +7.2 points (+1.5 to +13.3) | | | Tasks mu passes more often / less often than pi | 25 / 8 | 25 / 10 | | | Failed attempts: out of time / finished wrong | 65 / 19 | 71 / 19 | 81 / 28 | | Agent time per passed attempt | 23.6 min | 22.2 min | 27.4 min | | Cost per passed attempt | $0.067 | $0.063 | $0.069 | What this run is and isn't: - Terminal-Bench 2.1 through Harbor 0.24.0, at each task's own time limit. Harbor runs a task's tests even when the agent runs out of time, so an attempt can hit the limit and still pass. pytorch-model-recovery is left out of the totals, because the harness didn't pass its instruction to pi or mu in the first runs. Every configuration passed it in all three attempts on record, so leaving it out doesn't change the comparison. - MiMo v2.6 Pro with reasoning effort high, everywhere. pi 1.4.0 is the control. mu is mu-agent 0.1.12, built on pi 1.3.0, with its defaults; Jev is version 1.14. The mude column is a pre-release build with 24 layers, served on the same Mac. mude 1.0 is the 20-layer model made from it and hasn't been run on Terminal-Bench; neither has mu 0.2.x. - Three attempts per task, from 2026-10-22 to 2026-10-24, on one 16 GB Mac with Apple silicon. Attempts were rerun only for infrastructure failures, by rules set beforehand. Rosetta breaks four tasks for every configuration, so absolute pass rates are about 4.5 points lower than on x86_64 and can't be compared with the public leaderboard. Every attempt's result is in [docs/benchmarks/terminal-bench-2.1.csv](docs/benchmarks/terminal-bench-2.1.csv), and the method is in [docs/benchmarks/terminal-bench-2.1.md](docs/benchmarks/terminal-bench-2.1.md). The Harbor adapter that ran mu and pi, and a script that recomputes this table from the CSV, are in [bench/harbor/](bench/harbor/). ### What reaches the model: failing test logs The numbers below come from the repository's own scripts. Folding was measured on 2026-10-25 with [`test-log-repeats.ts`](kyrn/spikes/judge-bench/test-log-repeats.ts); goal-aware selection on 2026-09-21 with [`test-log-replay.ts`](kyrn/spikes/judge-bench/test-log-replay.ts), whose offline arms give the same results on today's code. The method and the full tables are in [kyrn/docs/09-test-log-admission.en.md](kyrn/docs/09-test-log-admission.en.md). **Exact repeats.** A failing run often prints the same diff, DOM dump or stack trace once per failed test. mu keeps the first copy and replaces each later copy with a single line naming the lines it repeats. No model is called. The markers expand back to the original byte for byte, and the full log stays on disk, behind a pointer at the end of the output. How much goes depends on the runner: Jest and pytest print each failure's diff and stack trace in full, while Vitest's default reporter repeats less.

Failing test logs folded without loss: 40% of the characters in Jest logs from 4 open-source projects, 27% in pytest logs from 2, 9% in Vitest logs from 6, 6% in Vitest logs from mu's own CI and 51% in Vitest logs from the authors' sessions on September 21; 19.5% across all 71 logs, 2,453,384 characters.

A failing Vitest run of 338 lines scrolls past with its repeated diff blocks highlighted, then the same run as the model sees it: 135 lines, with one marker line for each folded block. 7,686 characters become 4,262, with no model call.

**Goal-aware selection.** With a verbose reporter, what's worth keeping depends on what you asked for. Passing tests are noise when you're debugging a failure, and evidence when you ask which tests ran. In a single request, the judge is asked about each block of passing tests and each block of test output: does the goal still need it? The summary and the failures are never put to the judge. A block is left out only when the judge gives "not needed" a probability of 0.9 or higher. In these measurements, the judge is Jev 1.13, the default at the time; they haven't been rerun with Jev 1.14.

On 29 tuned goals, Jev cut 40.2% and lost none of 72 required lines; a perfect judge cut 52.5%; keeping only failures cut 61.9% but lost 9. On 9 held-out goals, Jev cut 46.4% and lost none of 19; a perfect judge cut 46.5%; keeping only failures cut 59.4% but lost 6.

*Perfect judge* reads the labels, so it shows the most a correct judge could cut. *Keep failures only* is a judge that always answers "leave it out", which is effectively what a goal-blind filter does. The study's 282 live Jev requests cost about $0.017 in total at list price; with the default wording, the median request took 345 ms. Both are off by default. To fold repeats, set `"features": { "admission": { "testLog": "rules" } }` in `~/.mu/agent/mu.json`, or turn on *Test log trimming* in the desktop app's settings. Setting it to `"jev"` also asks the judge which of the remaining parts the current goal needs; `/mu mode tool.admission.test-log shadow` records that choice without acting on it. What these numbers don't show: - The selection cases are real Vitest, node:test and pytest output from synthetic projects, plus 13 hand-written edge cases. The goals and labels were written by the authors. The held-out goals were labeled first and run once, and nothing was changed afterward. - They measure what reaches the model and what's lost, not whether the model then finishes the task. - The folding sample is mostly CI logs: from each of 12 open-source projects, chosen by test runner before measuring, its 6 most recent failed runs, and from mu's own CI its failed test runs since 2026-09-22, one failing log per run, cut to what mu's bash tool hands over (the last 2,000 lines or 50 KB). The 7 logs from the authors' sessions are the earlier sample. In their recent sessions the agent piped most test runs through `tail`, so few logs reached the 4,000 characters admission starts at. - Go and Cargo output isn't recognized as a test log, so it isn't folded.
The charts as tables | Goal-aware selection | Tuned goals (29): cut | Required lines lost | Held-out goals (9): cut | Required lines lost | | --- | --- | --- | --- | --- | | mu · Jev | 40.2% | 0 of 72 | 46.4% | 0 of 19 | | Perfect judge | 52.5% | 0 of 72 | 46.5% | 0 of 19 | | Keep failures only | 61.9% | 9 of 72 | 59.4% | 6 of 19 | | Failing test logs, one per run | Logs | Characters | Folded | | --- | --- | --- | --- | | Jest, 4 open-source projects | 14 | 584,229 | 40.1% | | pytest, 2 open-source projects | 5 | 255,721 | 26.7% | | Vitest, 6 open-source projects | 18 | 530,853 | 9.2% | | Vitest, mu's own CI | 27 | 942,761 | 6.0% | | Vitest, the authors' sessions (2026-09-21) | 7 | 139,820 | 51.0% | | All | 71 | 2,453,384 | 19.5% |
## The hive A hive is two to six bees, each with its own focus. Bees read code, run commands and browse the web, but never edit; the main model makes the changes. Each time a bee finishes a message, `hive.publish` asks once: is there a finding, a dead end, a decision or a blocker here worth sharing? If so, it goes on a shared, append-only board. For each new note, `hive.deliver` asks once per other bee: does this touch its focus? If it does, the note is delivered, marked *a finding, not an instruction*. The board is append-only, so an earlier conclusion stays even after a later one overturns it: a bee reports that the tests won't run, then unsets an environment variable and they do. `hive.relate` decides how two notes relate: *supersedes*, *contradicts* or *supports*. When a conclusion is superseded, a correction goes to every bee that holds the old note. When two notes contradict each other, both stay, marked as a dispute; if nobody settles it within a minute, a bee is sent to verify.

The desktop app's Hive tab after a /hive question: three bees, config, repro and tests, all done; a map of the findings they delivered to each other; and in the conversation, the answer with the line, the numbers and the failing test

You can watch all of this in the desktop app's Hive tab. Each bee gets a row: its role, its model and what it's doing or has just said. The map shows who delivered findings to whom, and the more findings travel along a line, the thicker it gets. Corrections and disputes have their own marks, and a line lights up the moment a finding arrives. The *Information flow* list shows the text of every delivery, and every verdict is listed too. The hive card in the conversation shows a miniature of the map and opens this tab. `/swarm` shows what each bee is doing, `/swarm stop` asks them to report now and `/swarm kill` ends them. A bee that runs out of time is asked for its report and ended if none arrives, and a watchdog handles a stuck model or tool. A hive always reports back. ## The plain-language board With the board on (`/board`, or the switch on the desktop app's Board tab), each step the agent takes becomes one plain line on the board as soon as it finishes: a file changed, a check passed or failed, a command ran. Consecutive file reads are folded into a single line with a running count. Whenever the agent says something mid-run, `board.read` asks the judge whether it's news. If it is, a model chosen only for plain writing (`/board model`) rewrites it for a person and keeps the board's status current: what's happening now, how many checklist items are done and what's waiting on you. When a run finishes, a summary becomes the last line, with the full account kept above it, so you see what was done, not just that it's done.

The desktop app's plain-language board after the hive answered: waiting for you to say whether to fix it, the one question that needs you and what happened before, with context use and cache hit rate at the top

The board follows the permission mode, the goal and the subagents, and when the agent changes course, the wording follows. The two numbers at the top are context use and cache hit rate. ## The desktop app A desktop app with mu and its runtime built in: there's no Node.js to install and nothing to download on first launch. It has everything the command line has, plus a work panel beside the conversation: **Board** · **Judge** (the live ledger: every verdict with its question, decision point and latency) · **Hive** · **Lessons** · **Files** · **Preview** · **Source** · **Browser** (the built-in browser the agent drives one step at a time; it shows the goal and lets you pause or stop)

The mu desktop app after a bug fix in relay, a job-queue project: jobs with a 1h30m timeout were killed after an hour because a minute was defined as 1,000 ms. The judge classified the message as a multi-step task (input.preflight), let both test runs through (tool.approval) and found the turn complete (turn.continue). The Judge tab on the right lists each verdict with its decision point and latency, about 60 to 120 ms. The sidebar holds earlier conversations in three projects, and the bar along the bottom shows the judge (Jev, through TypeSafe), 38 of 40 decision points active, 5 verdicts and the context in use.

A bar along the bottom keeps the kernel in view: which judge answers and where it runs, how many decision points are active and, in a conversation, the verdicts so far, the latest judge latency and the context in use. The permission mode and the goal sit in the composer, and `⌘K` opens the command palette. You connect models inside the app: sign in with ChatGPT, or add an API key for any provider pi supports. You can import Claude Code, Codex CLI and ZCode conversations and continue them. GitHub Actions builds the app for macOS (Apple silicon / Intel), Windows (x64 / Arm) and Linux (x64 / Arm) and publishes it under [Releases](https://github.com/qybaihe/mu/releases). ## Command line ```bash npm i -g mu-agent mu # interactive session in the current directory mu doctor # check the installation, the judges and the connections ```

mu's welcome screen in a terminal: the μ mark, "mu v0.1.10, judgment-first coding agent, built on pi 1.3.0", then the judge (Jev, answering in 137 ms, decision points active), the model and the working directory, and the key bindings worth knowing.

Requires Node.js 22.19 or newer. `mu -p "prompt"` runs a single prompt and prints the answer; `mu -c` continues the last session. `mu import --list` finds your Claude Code, Codex and ZCode conversations, and `mu import ` brings one in with its full history; importing it again later brings over what's new. `mu ledger [n]` prints what the judge decided in the last n sessions. The command line and the desktop app share accounts, settings and lessons. | Command | What it does | | --- | --- | | `/status` | Show the judges, each decision point's mode, what was kept out of the context and the latest verdicts | | `/mu judge ` | Set which judges answer, in which order: `jev`, `mude,jev`, `jev-opencode-free`, `openai`, `classifier:/`, `llm:/` | | `/mu route ` | Give one decision point its own judge | | `/mu mode ` | Switch one decision point's mode | | `/frame` | Show the task frame: the goal, your constraints with their source and the acceptance criteria | | `/goal ` | Keep working until the condition holds; `/goal clear` ends it | | `/permissions` | Choose Full access, Judge mode or Ask first | | `/board` | Turn the plain-language board on or off | | `/remember`, `/lessons`, `/forget` | Keep a lesson, list lessons, retire one | | `/skills` | Show the skills mu drafted from runs, and accept or reject each | | `/review`, `/commit` | Review the change, with findings ranked P0 to P3; write the commits | | `/checkpoints`, `/rewind` | List checkpoints; go back to one | | `/agents`, `/swarm` | List subagent roles; watch running subagents | | `/browse`, `/jobs` | Open the built-in browser; list background jobs | | `/capabilities`, `/ledger` | Show installed capabilities and which are turned on; show the latest verdicts | | `/import-chat` | Import a Claude Code, Codex or ZCode conversation | | `/doctor` | Check the setup and the connections | pi's own commands (`/model`, `/thinking`, `/login`, `/resume`, `/tree`, `/fork`, `/compact`, `/export` and the rest) work as they do in pi, except that `/login` offers no Claude subscription sign-in: Anthropic doesn't allow other apps to offer one, so use an Anthropic API key. `MU_JUDGE=mude,jev mu` overrides the judges for a single run. ## Privacy Your keys stay on your machine. mu never downloads a model or a runtime on its own; anything that needs a download asks first. The judge sees only the fields a question needs. With no key set, those fields go to the free Jev on OpenCode Zen. To keep everything on your machine, use mude 1.0 with `--local-only`, `MU_JUDGE=off` or `mu setup --judge off` (no judge is asked, and mu's features fall back to their own rules). Every verdict is logged locally, and you can read all of them. The desktop app sends no telemetry or crash reports. Details are in [SECURITY.md](SECURITY.md#what-leaves-your-machine). ## Documentation - [Getting started](docs/getting-started.md) · [Configuration](docs/configuration.md) · [Judges](docs/judges.md) · [Troubleshooting](docs/troubleshooting.md) - Reference: [every decision point](docs/reference/decision-points.md) · [every feature and option](docs/reference/features.md) · [Changelog](CHANGELOG.md) - For contributors: [How mu works](docs/architecture.md) · [Adding a decision point](docs/adding-a-decision-point.md) · [Translations](docs/translations.md) · [Writing style](docs/writing-style.md) ## Contributing Bug reports, fixes, new decision points, judge measurements and translations are welcome, in English or Chinese. Start with [CONTRIBUTING.md](CONTRIBUTING.md); issues labeled [`good first issue`](https://github.com/qybaihe/mu/labels/good%20first%20issue) are a good way in. ```bash npm install --ignore-scripts # install dependencies without lifecycle scripts npm run hydrate:model-catalog # write the model list from the pinned catalog (offline) node kyrn/bin/mu.mjs # run mu from this checkout npm run check # formatting, lint, types ./test.sh # tests (those that need a model are skipped without a key) ``` The desktop app lives in `desktop/`. Run `npm install` at the root first, then `bun install` and `KYRN_ROOT="$(cd .. && pwd)" bun run start` in `desktop/` to run the development build against the mu in this repository. Everyone taking part follows the [Code of Conduct](CODE_OF_CONDUCT.md). Report security problems privately, as described in [SECURITY.md](SECURITY.md). ## Community and support - Questions and ideas: [Discussions](https://github.com/qybaihe/mu/discussions). There's also discussion in Chinese on [linux.do](https://linux.do). - Bugs and feature requests: [Issues](https://github.com/qybaihe/mu/issues/new/choose). - More: [SUPPORT.md](SUPPORT.md). ## Citation If you use mude in your work, please cite it: ```bibtex @misc{mude2026, title = {mude 1.0: a decision model optimized for coding}, author = {qybaihe}, year = {2026}, howpublished = {Hugging Face}, url = {https://huggingface.co/qybaihe/mude-1.0}, note = {MIT License. MLX 8-bit edition for Apple silicon: https://huggingface.co/qybaihe/mude-1.0-mlx-8bit} } ``` ## Credits and license mu is under the MIT license ([LICENSE](LICENSE); the desktop app's is [desktop/LICENSE](desktop/LICENSE)). It is built on [pi](https://github.com/earendil-works/pi) (the coding agent, MIT), and we're grateful to its authors. Some decision points build on ideas from other projects: the wording of the prompt-injection screen comes from [hermes-jev-skills](https://github.com/kerpopule/hermes-jev-skills), and the continuation check (`turn.continue`) and the bulk judging tool (`judge_items`) are based on [oh-my-pi](https://github.com/can1357/oh-my-pi). Third-party code in the judgment kernel is listed in [THIRD_PARTY_NOTICES.md](packages/kyrn-judge/THIRD_PARTY_NOTICES.md). mude 1.0 is a fine-tune of [d3-nano](https://huggingface.co/vllm-sr/d3-nano) (Decision 3.0, vLLM Semantic Router Team), built on Qwen3.5-2B; both are Apache-2.0, and the model's repository keeps their notices. The desktop app began as a fork of [AionUi](https://github.com/iOfficeAI/AionUi); the files it took from AionUi, listed in [desktop/APACHE-FILES.txt](desktop/APACHE-FILES.txt), stay under the Apache License 2.0 (see [desktop/NOTICE](desktop/NOTICE)).