# mu moves the small decisions out of the big model

> qybaihe/mu is a coding agent built on pi that adds a judgment kernel: a small fast model answers bounded questions at 40 decision points per turn, deciding what enters the context, whether a command is safe and when a turn is done. It is pre-release software, and the README says so plainly.

**qybaihe/mu** — mu (μ): a coding agent that thinks before it acts. A small, fast judge makes the routine calls, the big model does the work. Built on pi and AionUi.

- Repository: https://github.com/qybaihe/mu
- Website: https://usemu.dev
- Stars: 540 · Forks: 62
- Language: TypeScript
- License: MIT
- Published: 2026-10-22 · Updated: 2026-10-22 · Language: en
- Canonical page: https://hysenlabs.com/projects/qybaihe-mu

## The argument: not every decision needs the expensive model

The core claim in the README is about cost distribution rather than model quality. A coding agent makes hundreds of decisions per session that have nothing to do with the code itself: what stays in the context, whether a command is safe, whether a finding is worth passing to another agent, when the work is finished.

The project frames both obvious answers as wrong. Left to the big model, those decisions burn tokens, latency and attention. Left to fixed rules, they are wrong too often. mu puts them in a third place, a judge, described as a small and fast model that answers one bounded question at a time at 40 decision points in every turn.

That is a specific architectural bet. Instead of one model doing everything, a cheap model handles classification-shaped questions and the large model keeps its attention for the actual engineering. The judge is called Jev, and it handles yes/no questions, choice questions and score questions, returns a probability with each answer, and records every verdict in a ledger. A local judge named Laya can take a decision point instead, as can any LLM.

The README also states the limits of the design honestly: rules remain the floor, a dangerous-looking command is caught by rules first, and the judge only vouches that you asked for it. The judge never decides whether to ask you.

## Quick start: an npm install, a setup step, a session

There are two entry points. The desktop app is a native application that carries mu and its runtime, with installers for macOS, Windows and Linux on the releases page. You download it, open it, paste an API key or sign in with a ChatGPT, Claude, Grok or Google subscription, and there is nothing else to install.

The command line route is three commands:

```bash
npm i -g mu-agent   # Node.js 22.19 or newer
mu setup            # connect a model
mu                  # a session in the current directory
```

The package on npm is `mu-agent`, and the Node floor is 22.19 or newer, which is worth checking before you install anything, since the repository's own package manifest is the private `pi-monorepo` root rather than the published package.

The judge is not a separate purchase at this stage. The README says no judge key is needed to start, and that until you set one, the free Jev on OpenCode Zen answers. Every decision point acts on those verdicts from the first turn, and each verdict is logged. You can read the log three ways: the `/status` command in a session, the `mu ledger` command, or the judgments tab in the desktop app.

There is also a safe way to start. To only record what the judge would do, without letting it change anything, the README says to put `{"modes": {"default": "shadow"}}` in your configuration file, `~/.mu/agent/mu.json`. Shadow mode is the sensible first configuration for anyone evaluating this, and it is the mode the README itself suggests for comparing judges before switching one on.

## Decision points are named, and each can be routed to a different judge

Everything mu does at this level is expressed as a named decision point, and the README's turn diagram is built entirely from those names. Input handling runs through `input.preflight`, `task.frame` and `input.interjection`. The model runs, produces a tool call, and the tool call passes through `tool.risk`, `tool.constraint` and `tool.approval` before it runs. On the way back, `tool.injection` handles web pages and MCP output, and `tool.admission` decides chunk by chunk what enters the context and what is archived behind a pointer. A turn ends through `turn.completion`, `turn.continue`, `turn.drift`, `turn.rewind`, `memory.applied`, `board.read` or `cache.warming`.

Each decision point has a mode. `active` is the default. `shadow` means the point is asked and logged but changes nothing, which the README describes as the way to compare judges before switching one on. `off` disables it. And each point can name its own judge: `jev`, `laya` for the local one, `classifier:<provider>/<model>`, `llm:<provider>/<model>`, or a cascade such as `laya,jev`.

That routing is the part that makes the design more than a demo. You can put a cheap classifier on `tool.admission`, a local model on `memory.worth`, and a capable model on `turn.completion`, and change any of it per point rather than globally.

The README also draws a hard line around the tool. A dangerous-looking command is caught by rules first, before the judge is consulted, and the judge's role in approval is to confirm that the request was yours. So the model cannot talk itself past a rule, and the judge does not become a new authority with the power to let anything through.

## Context admission and memory are where the token savings come from

The context decision points are the most concrete part of the design, because they describe what actually happens to a large tool output.

`tool.admission` is asked per chunk of a long tool output whether it matters now. What matters enters the context, and the rest is archived behind a pointer. `tool.admission.test-log` handles the special case of test logs, where the question is what repetition is: exact repeats are folded once and losslessly, and optionally the judge selects from the rest. `context.forget` fires above a context threshold and asks which tool results are stale, with each one becoming a one-line tombstone in outgoing requests. `context.compact` asks whether to keep or prune a passage, and the README is specific that compaction is by judgment and that no summary is written.

That last detail is the interesting one. Most compaction schemes replace content with a generated summary, which loses information quietly. mu prunes by decision and writes no summary, so what disappears from the context is what the judge decided was not worth keeping.

Memory has its own chain. `memory.recall` asks which lessons apply to the current task and brings them in. `memory.capture` asks whether a message corrects the agent or sets a rule, in which case it becomes a lesson. `memory.outcome` asks, after going in circles, whether the way out deserved a lesson, and the answer describes the source as a lesson from the run rather than from you. `memory.worth` asks whether a proposed lesson is useful again, a one-off or already known, and `memory.merge` asks whether a lesson matches an existing one, is more precise, or contradicts it.

Disclosure is filtered the same way. `skills.disclosure` decides which skills enter the prompt and leaves the rest findable, and `capability.disclosure` decides whether an installed pack or MCP server is needed at all, opening it and starting its process only then. Starting fewer processes and prompting with fewer skills is cheaper than any token counting trick.

## Prompt injection is handled by withholding, not by filtering

The `tool.injection` decision point is the one that will interest anyone deploying this against real web content. The README's description of it is short and specific: web pages and MCP output, instructions aimed at the AI, are withheld.

The design decision here is that mu does not try to detect an injection and then decide whether it is dangerous. The content is simply not passed to the model in a form it can follow as an instruction. This inverts the usual approach, where a filter reads untrusted text, looks for imperative phrasing, and guesses. Reading the untrusted content at all, in the model context, is what creates the exposure.

That approach has a cost, and it is worth naming. A page that legitimately contains instructions, for example a documentation site whose text tells the reader which command to run, is in the same category as a page trying to manipulate the model. Withholding works by refusing to distinguish them, which means a human may need to open the page themselves.

Combined with the rule floor and the judge's limited role, the model in mu is never the component that decides what it is allowed to do. Rules block dangerous commands, the judge confirms intent, and untrusted instructions never reach the model as instructions at all.

## Pre-release software with a monorepo behind it

The README flags the status without hedging: early development, pre-releases in the 0.1.x line are on npm and under Releases, the authors use it every day, and names, settings and formats may still change. The listed releases are v0.1.8 on 2026-10-19, v0.1.7 on 2026-10-07 and v0.1.6 on 2026-09-30, and the last push was on 2026-10-20.

The repository behind it is a monorepo named `pi-monorepo`, marked private, using npm workspaces. The workspace list covers `packages/*` and `apps/*` plus several example extensions, including ones for a custom Anthropic provider, a GitLab Duo provider, a sandbox and one called gondolin. The build script walks the workspace in a fixed order, building telemetry, then chord, then tui, then codemode, then mcp, then ai, then durable, then env, then agent, and finally coding-agent, which tells you the dependency direction of the whole system: the agent sits on top of everything else.

There is a parallel offline build script, native build targets for the TUI on darwin, linux and win32, and a check script that runs Biome with write, then four custom dependency and import checks, then `tsc --noEmit`, then a browser smoke check. The custom checks are the interesting part: pinned dependencies, runtime dependencies, TypeScript import rules and entry graphs are all enforced by scripts in `scripts/`, so the boundaries between packages are mechanically checked rather than documented.

The tree also holds `desktop/` for the Electron app, `kyrn/`, `nix/`, a `flake.nix` and `flake.lock` for Nix-based environments, a `.pi/` directory, `biome.json` for linting and formatting, and governance documents including `GOVERNANCE.md`, `CODE_OF_CONDUCT.md`, `SECURITY.md` and `SUPPORT.md`. The licence badge reads MIT plus Apache-2.0.

## When mu is the wrong tool

There are clear cases where this design is not what you want.

If you want a model with the largest possible capability on a single hard problem, a judgment kernel adds a hop rather than removing one. Every decision point is a round trip to another model, and a local judge still costs inference. For a short, single-file task, the big model answering directly is likely faster and better.

If you need a stable configuration format today, the 0.1.x pre-release status is a problem. The README says explicitly that names, settings and formats may still change, and the mode configuration example itself is a JSON file with a `modes` map whose shape is part of that moving surface.

If your environment is air-gapped or offline, note that the default judge is the free Jev on OpenCode Zen, which is a hosted service. The local judge Laya and the `llm:<provider>/<model>` routing exist for that case, but you have to choose them deliberately, and the local judge is a separate piece of software you have to run.

Finally, if you are building on pi itself rather than using mu, note that mu is described as a layer on pi. The `pi` directory and the package layout suggest the boundary, and the fact that the build compiles `coding-agent` last suggests mu's kernel lives close to that layer. Anyone extending the underlying agent has to check where the judgment kernel sits before assuming it can be replaced piecemeal.

## Conclusion

Adopt mu if you run long coding sessions on pi and the cost you care about is context, latency and attention rather than raw model capability, since the judgment kernel exists to spend a small model where a small question suffices. Do not adopt it if you need a stable interface today, because the README states that names, settings and formats may still change in the 0.1.x pre-releases. Before you point it at a real repository, run it in shadow mode with the configuration the README gives, read the ledger of verdicts, and check the tool.approval and tool.risk decision points first, because those are the ones that decide what your agent is allowed to run.

## FAQ

### What is mu and what problem does it solve?

mu is a coding agent built on pi that adds a judgment kernel, a small and fast model that answers one bounded question at a time at 40 decision points in every turn. The idea is to move context, safety and completion decisions off the large model, so the large model keeps its attention for the work itself.

### How do I install and start the mu coding agent?

On the command line, install the package globally with `npm i -g mu-agent` on Node.js 22.19 or newer, run `mu setup` to connect a model, then run `mu` for a session in the current directory. The desktop app is a separate download from the releases page for macOS, Windows or Linux, and needs nothing else installed.

### What is Jev and how do I change which judge handles a decision?

Jev is the judge, handling yes/no, choice and score questions and returning a probability with each answer, with every verdict recorded in a ledger. Each decision point can name its own judge: `jev`, `laya` for the local judge, `classifier:<provider>/<model>`, `llm:<provider>/<model>`, or a cascade such as `laya,jev`.

### What is shadow mode in mu and how do I enable it?

A decision point in shadow mode is asked and logged but changes nothing, which the README describes as the way to compare judges before switching one on. To enable it, put `{"modes": {"default": "shadow"}}` in `~/.mu/agent/mu.json`.

### How does mu handle prompt injection from web pages and MCP output?

The `tool.injection` decision point withholds instructions aimed at the AI found in web pages and MCP output, rather than passing them to the model. Rules remain the floor for dangerous commands, and the judge only confirms that the request was yours.

## Sources

- [License: MIT](https://github.com/qybaihe/mu/blob/main/LICENSE)
- [Project website](https://usemu.dev)
- [qybaihe/mu on GitHub](https://github.com/qybaihe/mu)
- [README](https://github.com/qybaihe/mu/blob/main/README.md)
- [Releases](https://github.com/qybaihe/mu/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/qybaihe-mu
