Moothall

Self-hosted · PHP 8.1+ · No dependencies · MIT

A hall for the AI tools you already run.

Moothall seats Claude Code, Codex, Cursor and three more around a single task. Each one is a real process in its own kernel sandbox, working on its own copy of your project. They build, they review each other, and they hand you one diff. Nothing touches your folder until you press Keep.

The Moothall seats view: a Conductor, a Builder and three Reviewers each running in their own panel, with the project list on the left and the diff, the task list and the elapsed time on the right.
One task. Five seats. Four different CLI tools. The Conductor is Devin, the Builder is Cursor, and the three Reviewers are Hermes and two OpenCode models. They do not share a context window. All three agreed. One file changed, one line added, forty-two seconds.

Four words are used on this page, and they mean exactly this

Shipped
It is in the repository. You can run it today.

Measured
We tested it and can show you the result.

Unproven
We believe it. We have not shown it.

Open
We would like help with it.

Unproven The reason this project exists, and still the open question.

The claim we are trying to test

Software written by a team of AI agents should be measurably better than the same models used one at a time, or the team is not worth having. Status: a goal, not a finding

That sentence is why Moothall exists. We have not proved it, and we are not going to pretend otherwise while we try.

If you have looked at other multi-agent frameworks and wondered whether the crew part actually helps, you are asking the right question. We read the popular ones before writing this, and as far as we can tell nobody in this space publishes a measurement. Not one of their READMEs compares a multi-agent run against the same model working alone.

So the benchmark got built before the features did. It runs one task four ways: each model alone, a derived best-of-three ceiling, a hand-arranged crew, and the full engine, against cases with machine-checkable ground truth. No LLM judges. No rubrics. Either the check passes or it does not.

It has caught itself lying fifteen times. A scoring bug that would have marked every wrong answer correct. A case whose checker was silently disabled. A receipt claiming calls that never happened. Every one of those was found by a reviewer reading the code rather than by the tests, and every one of them is why there is still no number on this page.

When there is a number it goes here, whichever way it comes out. Helping to break the measurement is the contribution we would value most.

Shipped Works end to end. A task goes in, a reviewed change comes out.

What happens when you give it a job

You point it at a folder and say what you want in plain English.

  • A Conductor works out what the job actually is and writes the brief.
  • A Builder does the work, on a copy, in a sandbox of its own.
  • Reviewers read the change and say whether it is right. If one raises a concern the work goes back up for another round.
  • You read one diff at the end and decide: keep it, or put it back.

Every seat is a separate model reached through a separate tool, running as its own process. They see the change, not each other's opinions.

Task 4 · the run shown at the top of this page

Conductor0m 12s

Devin
SWE 1.7 Medium

Wrote the brief

Builder0m 07s

Cursor
composer-2.5

Touched index.html

Reviewer0m 22s

Hermes
stepfun/step-3.7-flash-free

Verdict: agree

Reviewer0m 11s

OpenCode
deepseek-v4-flash-free

Verdict: agree

Reviewer0m 09s

OpenCode
big-pickle

Verdict: agree

20:16 You → Conductor 20:16 Conductor → Builder 20:16 Builder → Reviewer 20:16 Conductor → Reviewer ×2

The conversation view: the Conductor's brief, the Builder's report and each Reviewer's verdict, one after another in a single readable thread.
The same run as a thread. Each seat's actual output, in the order it arrived, with the diff beside it. Nothing is summarised for you by another model.
Measured Stated as facts because they were tested, not because we are attached to them.

Three things about how it is built

These are unusual enough to be worth stating plainly.

Shipped

It runs tools. It never calls an API.

The only outbound path is proc_open with an argv array. There is no HTTP client in this codebase, no key to paste, and none stored. If you can run codex or claude in your terminal, Moothall can seat it. Your existing logins and subscriptions work exactly as they are, and Moothall never holds a credential.

Measured

Containment is a kernel boundary, not a prompt.

We tested this and it changed the design. Telling a tool it is in read-only mode does not bind it: codex exec -s read-only writes files anyway, and it is not the only one. So every seat gets a real bwrap namespace and a real copy, and the permission is enforced by the kernel rather than by asking nicely.

Shipped

State is derived from disk.

There is no event queue to replay and no acknowledgement to lose. A task's state is recomputed from the records each run leaves behind. Whether that holds at a scale we have not hit yet is an open question, and it sits on the roadmap as one rather than as a solved problem.

The Providers page listing the agent CLI tools Moothall can drive, each with the models read from that tool's own cache.
Bring your own tools. Model lists come from each tool's own cache, so they stay correct without anyone here maintaining a list. A seat with nothing behind it will not run, and it says so up front rather than failing halfway through a task.
Shipped The whole point of the thing.

Read the change, then decide

Agents work on a copy. When the round is over you get one diff in your own folder and a button to put it back. Put-back works whether or not the project is a git repository, because it compares against a copy taken before the work started rather than against your history.

If you keep it, it is yours. If you do not, the folder is exactly as you left it.

The Changes page: every file the run modified, line by line, with keep and put-back controls.
Every file the run touched, what it did to each one, and two buttons.
The Team page, with each seat bound to a provider and a model.
Team - who sits where, and which model is behind each seat.
The Tasks page listing previous runs with what each one cost and how it ended.
Tasks - what has run, what it cost, what each seat said.
The Settings page showing round budget, timeouts, theme and the accounts that can sign in.
Settings - round budget, timeouts, theme, and who can sign in.
The Help page, written in plain language for someone who has never run an agent before.
Help - written for someone who has never run an agent before.
Alpha There is no release yet and no upgrade path.

Where this actually stands

A landing page is the easiest place in the world to overstate things, so here is the same table that is in the README.

Works end to endYes. A task goes in, a team runs, a reviewed change comes out, and you can put it back.
Every page builtYes. Home, Projects, Tasks, Team, Providers, Changes, Settings, Help.
Tested1086 assertions, no known failures. No test framework and no dependencies. Some checks loop over your own projects and providers, so the count moves with your data.
Used in productionNo. One live install, by the author.
The core claim provedNo. This is the open question, and it outranks every feature.
API stableNo. Expect things to move.

If you install this, install it somewhere you do not mind rebuilding.

Shipped Four commands. Nothing is fetched at install time except the repository itself.

Install

Copy the files, point it at a data directory outside your web root, create the owner account. That is the whole install.

  • PHP 8.1+ with proc_open enabled.
  • bwrap (bubblewrap) for containment. Without it Moothall refuses to start a seat rather than running one unconfined.
  • At least one agent CLI on your PATH, already logged in.
  • A data directory outside your web root. The app refuses to start if that ever stops being true.
bash
$ git clone https://github.com/WDCI-J/moothall.git
$ cd moothall

$ cp config.example.php config.php     # then edit data_dir, outside your docroot
$ mkdir -p /path/to/moothall-hall-data

$ php tools/set-owner.php <username>    # creates the owner account

set-owner.php generates a strong password and prints it once. Write it down before you close the terminal. There is no reset link, by design, and recovery means running that tool again on the server.

Then serve the directory and open it in a browser. Until an owner exists the sign-in page says so and refuses everyone, so the order above matters. Connect your first tool from the Providers page once you are in.

One asset is vendored rather than fetched: assets/vendor/xterm.js, which draws the terminal. It ships in the repository, so there is still nothing to install, but it is a dependency and calling it anything else would be untrue. Pinning its version is on the roadmap.

a fresh install reports skips, not failures
$ php tools/test.php

903 passed, 0 failed, 4 not applicable here
  - the naming of bound seats :: this hall has no seats bound to a model yet
  - the keep list means something :: this hall has no runs yet

Some checks read the hall's own providers, teams and runs, and a brand new hall has none, so they say why they did not run. A configured hall reports 1086 passed, 0 failed. Anything under failed is a real failure and worth an issue.

Open Not the usual good-first-issue list.

Help wanted

Three things would genuinely move this forward, and none of them is a feature.

1. Help us measure it, or show us the measurement is wrong

The benchmark is the most interesting part of this repository and the part most likely to be flawed. It has already caught itself out fifteen times, every time because a person read the code. If you are the kind of developer who enjoys breaking a measurement, open an issue with what you would attack first.

2. More providers

Six agent CLIs are wired. There are more, and every one has its own flags, its own idea of read-only, and its own way of reporting that it finished. Adding one is a recipe plus evidence that the sandbox actually contains it. Tools that cannot execute commands make poor reviewers, and we have measured that.

3. Tell us the architecture is wrong

If running tools instead of calling APIs is the wrong trade, or if deriving state from disk breaks at a scale we have not hit, that is worth more to us than a patch.

What we are not looking for

Features that make it look more capable without evidence that it works better. That is the failure mode this whole project is a reaction to.

GitHub is the way to reach us. Issues and pull requests are read. There is no contact form and no mailing list to join.