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
English · 简体中文 · 繁體中文 · 日本語 · 한국어
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).
- 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, mu's own model, on your Mac; another decision model from Hugging Face; your own System One server; or any LLM.
Contents: Quick start · How a turn works · Decision points · Judges · How mu is built · Measured · The hive · The board · Desktop app · Command line · Privacy · Documentation · Contributing
Desktop app. Download the installer for macOS, Windows or Linux from Releases, open it and sign in with ChatGPT, or paste an API key for any provider. There's nothing else to install.
Command line.
npm i -g mu-agent # Node.js 22.19 or newer
mu setup # connect a model
mu # start a session in the current directoryYou 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.
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:<provider>/<model>, llm:<provider>/<model> 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
/goalcondition 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.
-
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_KEYwithCLOUDFLARE_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).
-
OpenAI's decision model,
gpt-6-luna, answers through OpenAI's Decisions API with an OpenAI API key:MU_JUDGE_OPENAI_KEY, or the OpenAI key mu already has. Pick it withmu setup --judge openaior under Settings → Judges (details). -
Other decision models from Hugging Face (local, a Mac with Apple silicon):
mu judge model add <link>(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: amu.jsonthat 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:<provider>/<model>. 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:<provider>/<model>.
Judges can be chained in tiers, cheapest first:
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 and the MLX 8-bit edition (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:
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 environmentOn 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 (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 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.
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.
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:
The code map, and where each step lives: docs/architecture.md.
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.
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, and the method is in 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/.
The numbers below come from the repository's own scripts. Folding was measured on 2026-10-25 with test-log-repeats.ts; goal-aware selection on 2026-09-21 with 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.
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.
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.
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% |
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.
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.
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 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.
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)
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.
npm i -g mu-agent
mu # interactive session in the current directory
mu doctor # check the installation, the judges and the connections
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 <file> 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 <judges> |
Set which judges answer, in which order: jev, mude,jev, jev-opencode-free, openai, classifier:<provider>/<model>, llm:<provider>/<model> |
/mu route <point> <judge> |
Give one decision point its own judge |
/mu mode <point> <off|shadow|active> |
Switch one decision point's mode |
/frame |
Show the task frame: the goal, your constraints with their source and the acceptance criteria |
/goal <condition> |
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.
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.
- Getting started · Configuration · Judges · Troubleshooting
- Reference: every decision point · every feature and option · Changelog
- For contributors: How mu works · Adding a decision point · Translations · Writing style
Bug reports, fixes, new decision points, judge measurements and translations are welcome, in English or Chinese. Start with CONTRIBUTING.md; issues labeled good first issue are a good way in.
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. Report security problems privately, as described in SECURITY.md.
- Questions and ideas: Discussions. There's also discussion in Chinese on linux.do.
- Bugs and feature requests: Issues.
- More: SUPPORT.md.
If you use mude in your work, please cite it:
@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}
}mu is under the MIT license (LICENSE; the desktop app's is desktop/LICENSE). It is built on 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, and the continuation check (turn.continue) and the bulk judging tool (judge_items) are based on oh-my-pi. Third-party code in the judgment kernel is listed in THIRD_PARTY_NOTICES.md. mude 1.0 is a fine-tune of 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; the files it took from AionUi, listed in desktop/APACHE-FILES.txt, stay under the Apache License 2.0 (see desktop/NOTICE).



