---
title: Mullet
canonical: 'https://www.dealmobile.co.uk/projects/mullet'
url: 'https://www.dealmobile.co.uk/projects/mullet'
type: Project
summary: 'A Python tool that runs large coding jobs unattended with your own Claude Code, checks every step itself, and returns a branch and an evidence report.'
---

# Mullet

A job runner that plans a coding job, runs it unattended in a sandboxed clone, and marks each step done only when its own checks pass.

![Mullet in a terminal. mullet job list shows a finished job with 5 of 5 nodes passed, and mullet job report shows one node, calc.sub, passing on its first attempt: a table of gates G1 to G7, each with its result and detail, then the worker’s own summary, labelled as a claim that was not checked. Output trimmed for length.](https://www.dealmobile.co.uk/sites/default/files/styles/almanac_shot_md/public/content/images/products/mullet-job.png.webp?itok=7chb-8ZK)

- **Kind:** Tool
- **Status:** Maintained
- **Started:** 2026
- **Licence:** BSL 1.1
- **Stack:** Python, SQLite, Git, Model Context Protocol, ChromaDB, pytest, GitHub Actions
- **Links:** [Source on GitHub](https://github.com/tomgould/mullet-public)

Mullet runs large coding jobs while you are away, and checks every step itself. You give it a goal. A read-only Claude session proposes a task tree, and you approve it. The job then runs unattended, each step in a sandboxed private clone of your repo, and a step passes only when Mullet’s own checks pass. You get back a branch and an evidence report. Your own checkout is untouched until you merge.

## How a job works

```
mullet job plan "<goal>"
mullet job approve <id>
mullet job run <id>
mullet job report <id>
mullet job merge <id>

```

The planner breaks a goal into a tree of steps, up to 3 levels deep and 40 steps, until each one fits a single pass. Each step runs in a private clone with its git directory out of the worker’s reach, under bubblewrap on Linux. There is no network, no home directory and no unsandboxed fallback: if the sandbox can’t start, the job refuses to run.

The worker is your own logged-in `claude -p`. Mullet never reads or passes Claude credentials, runs one Claude worker at a time across all jobs, and pauses when Claude Code reports a usage limit, then carries on after the reset.

A step is judged by gates that read the diff and the test results: a real change, scope and protected paths, a secret scan, test weakening, build, tests compared with a baseline, and a read-only review that can block a step but never pass one. A step that fails is retried with the gate output, up to 3 times, then blocked. Its status comes from the ledger, a SQLite database of gate results, never from a model’s reply.

`mullet job merge` fetches the job’s branch into your repo as a new branch and stops. It never pushes.

I wrote this up in [Mullet 2, coding jobs you can leave running](https://www.dealmobile.co.uk/writing/mullet-2-coding-jobs-you-can-leave-running.md), [Gates, not a model’s word](https://www.dealmobile.co.uk/writing/gates-not-a-models-word.md), [Sandboxing an AI coding worker](https://www.dealmobile.co.uk/writing/sandboxing-an-ai-coding-worker.md) and [Running your own Claude subscription unattended](https://www.dealmobile.co.uk/writing/running-your-own-claude-subscription-unattended.md).

## Spending limits

Nothing is limited until you set a value, and `mullet doctor` warns when nothing is. A daily and a weekly envelope cap what every job and every paid provider may spend together, per-provider limits cap one provider, and a job has its own cap. They are checked before every attempt, and the key proxy stops an attempt the moment its allowance is spent, so a step that goes wrong stops spending part way through it.

Cost comes from the provider’s own responses. OpenRouter states it; other providers are priced from a table you configure, cache rates included. At the end of every job the report sets the ledger beside what each provider says was spent while it ran, so a wrong figure shows up. I found out the hard way why that matters: [we checked the bill, and our ledger was wrong by half](https://www.dealmobile.co.uk/writing/we-checked-the-bill-and-our-ledger-was-wrong-by-half.md).

Every session also starts by asking what you want to spend and how much to delegate: [every session starts with one question](https://www.dealmobile.co.uk/writing/every-session-starts-with-one-question.md).

## Safe by default

- Web pages cannot drive `mullet serve`. It checks the Host and Origin of every request and, for one user, a token that only you have.
- A cheaper model that reads web pages gets web and browser tools only. Terminal and file tools are something you grant per provider with `delegation.toolsets`.
- The file and docker tools refuse credential locations: your SSH keys, cloud and token files, Mullet’s own state and `.env` files.
- Editor, dev container and shell-hook files are protected from a job’s changes.

The reasoning is in [safe by default](https://www.dealmobile.co.uk/writing/safe-by-default-a-local-ai-server-and-a-cheap-model-with-a-shell.md).

## Everything is a setting

`mullet config show` lists every setting, its default and where its value came from, with secrets hidden. `docs/CONFIGURATION.md` in the repo is the reference.

## What remains of the older Mullet

Mullet still serves an MCP server with Trawl, a knowledge engine that grew out of [Trove](https://www.dealmobile.co.uk/projects/trove.md). It indexes collections of documents and code, called pools, and searches them by keyword and by meaning together.

The earlier version routed each task to the cheapest model that could do it, and checked what a delegate had changed. I wrote about that in [Picking the cheapest model that can do the job](https://www.dealmobile.co.uk/writing/picking-the-cheapest-model-that-can-do-the-job.md) and [Checking a delegate’s edits before trusting them](https://www.dealmobile.co.uk/writing/checking-a-delegates-edits.md). That routing is still there, behind the older delegation tools, and `MULLET_DELEGATION=off` turns it off. Jobs can also use a cheaper worker, opencode with Kimi or an OpenRouter model under the same sandbox and gates, but only where a repo’s profile allows it. I have benched it on Mullet’s own repo only: see [the delegation ladder](https://www.dealmobile.co.uk/writing/the-delegation-ladder.md), and [why Mullet doesn’t use FreeLLMAPI](https://www.dealmobile.co.uk/writing/why-mullet-doesnt-use-freellmapi.md) for the free rung.

The orchestration modes from the earlier version are gone.

## Install

Install from GitHub with uv or pipx, using `scripts/install.sh`; `scripts/install.sh --version 2.2.0` pins a release. Do not run `pip install mullet`: that is a different project.

```bash
git clone https://github.com/tomgould/mullet-public.git
cd mullet-public
scripts/install.sh
mullet doctor

```

`mullet doctor` checks Claude Code, bubblewrap, socat and a stray `ANTHROPIC_API_KEY`, which in `claude -p` would silently replace your login and bill per token. Settings live in `~/.config/mullet`, and `mullet paths` prints where everything is. `mullet setup-claude` registers the MCP server and skills, records what it changed, and `--uninstall` undoes exactly that. Hooks are opt-in.

Jobs run on Linux, where the sandbox is bubblewrap. The rest of Mullet works on macOS too, but I don’t have a Mac to test a sandbox on, so there a job refuses to start rather than run without one.

## Tests and licence

The suite has about 18,000 tests and runs in parallel in about 5 minutes, cut off from the network, provider keys and your home directory.

Mullet is source-available under the Business Source License 1.1, and becomes Apache 2.0 on 3 April 2030. You can use it in production, free, for any purpose: on your own, inside a company or team, on any number of machines, to build software you sell or ship. The one thing the licence doesn’t cover is offering Mullet, or a service whose value comes substantially from it, to other people as a hosted, managed or embedded service. That needs a commercial licence. I explain why in [Mullet is free for your company](https://www.dealmobile.co.uk/writing/mullet-is-free-for-your-company.md).

---

Index of this site: [llms.txt](https://www.dealmobile.co.uk/llms.txt)
