cmux-factory is a small cmux harness for named coding agents and a shared
project brain.
The user talks to one lead agent. The lead assigns work to agents in other tabs.
All agents read and write plain files under .factory/.
The proof of concept does nine things:
- It uses the current cmux tab as the Lead.
- It creates Builder, Reviewer, and Watchdog tabs in the same pane.
- It launches each configured agent with its role prompt.
- It records exact cmux workspace, pane, and surface IDs.
- It shows a readable watchdog journal and status report.
- It sends agent messages through local inbox files.
- It wakes an idle agent when that agent has unread mail.
- It requires each non-Lead turn to end with mail to the Lead.
- It gives Builder and Reviewer separate Git worktrees.
The watchdog reports a closed agent surface and tells the Lead. It does not restart the agent in this version. Recovery comes after the launch and observation loop works in real use.
The Watchdog monitors agents. It uses the structured cmux events stream and
the cmux agent lifecycle records. The Lead does not poll worker terminals.
Agents exchange files under .factory/inbox/<recipient>/. Agents do not poll or
wait for mail. The Watchdog counts unread mail every two seconds. If cmux says
that an agent is idle, the Watchdog sends one short wake-up turn. It can also
use an idle factory state when cmux has no lifecycle record. It does not
interrupt a working agent.
A lifecycle hook can be lost. In that case, an agent can be idle while its
record still says working or running. If unread mail waits for 30 seconds,
the Watchdog reads only that agent's last 30 screen lines. It sends input only
after the same normal Codex or Claude prompt stays unchanged across two reads.
It does not send input to an active screen or a permission prompt. This screen
check is a recovery path, not the normal monitor path.
Every non-Lead turn must send mail to the Lead before cmux emits its Stop hook. The Watchdog logs each Stop event and whether that turn sent a handoff. If it did not, the Watchdog sends one reminder turn. If that turn also ends without mail, the Watchdog marks the agent as needing attention and alerts the Lead.
STOP builder hook received event=... state=working handoff_sent=false reminders=0
DECIDE builder wake worker because Stop had no Lead handoff
factory status shows the current unread count for each agent. The Watchdog
journal records the inbox count, factory state, cmux lifecycle, screen checks,
wake-up decisions, actions, and results. It records inbox collected; unread=0
after the agent reads its mail. It also records an inbox count summary every 60
seconds.
OBSERVE builder inbox unread=1 factory=working cmux=running
ACT builder read screen because inbox waited 30s while cmux lifecycle is running
DECIDE builder confirm the idle prompt on the next screen check
DECIDE builder wake agent because inbox unread=1; idle prompt stayed unchanged for 6s
RESULT builder wake-up sent; agent state is working
RESULT builder inbox collected; unread=0
Urgent mail still has a direct path. It pings an idle recipient at once. If the recipient is working, cmux shows a notification and does not type into the active prompt.
Mail uses a Lead-centered topology. Builder, Reviewer, and Watchdog can send
mail only to the Lead. Only the Lead can send mail to a non-Lead agent. The
factory mail command enforces this rule.
Git ignores the inbox because a permission event can contain command text.
Durable facts and lessons stay under .factory/brain/.
factory status
factory mail lead builder "Please add the focused test" \
--kind assignment --base BASE_SHA
factory mail builder lead "The change is ready for review" \
--kind handoff --base BASE_SHA --head HEAD_SHA
factory inbox lead --archiveBuilder works on the persistent factory/builder branch in
.factory/worktrees/builder/. Reviewer uses a detached worktree in
.factory/worktrees/reviewer/. A review assignment checks out the exact head
commit and its recorded submodule commits before it sends mail to Reviewer.
Worker processes start in the main project root so they can use shared factory
state. Their prompts require source and Git work in the named worktree.
Only Lead can push code. Builder and Reviewer hand off commits and never push. Lead asks for permission before each push that updates an open pull request in a public repository.
factory mail lead reviewer "Review this parser change only" \
--kind assignment --base BASE_SHA --head HEAD_SHAThe factory refuses to move or reuse a dirty worker worktree. It does not reset,
merge, rebase, cherry-pick, or remove worktrees. factory status shows each
worktree path, commit, and clean state.
For a new machine, follow Install on a fresh machine.
git clone https://github.com/mullender/cmux-factory.git \
~/.local/share/cmux-factory
cd ~/.local/share/cmux-factory
./install
cmux hooks setup
factory doctorThe installer creates symlinks. Update the source, links, and the nearest project rules with:
factory updateThe command uses git pull --ff-only. It keeps project-specific rule changes
and writes a .new file when both the project and central template changed.
- Task-based tutorial site
- Install on a fresh machine
- Getting started
- Edit agent instructions
- Update cmux-factory
Run factory init from any directory inside a Git project. It finds the Git
root. If the factory already exists and has a valid configuration, it preserves
project rules, refreshes safe metadata, and prints READY.
factory initThe command prints the next steps. You can open the project from a normal terminal:
cmux /path/to/projectThen start a Lead in the new cmux terminal:
codex /start-factory
# Or:
claude /start-factoryFrom an existing cmux terminal, one command can create the workspace and start the Lead:
cmux new-workspace --name project --cwd /path/to/project \
--command 'codex /start-factory' --focus trueSee Getting started for the full workflow and the Claude equivalent. See Edit agent instructions to change shared rules, writing style, roles, identities, or provider commands.
Useful commands:
factory status
factory update
factory update --no-pull --use-upstream # accept all reviewed upstream rules
factory events --follow
factory check-in builder working "Investigating the parser"
factory mail builder lead "The parser is ready" \
--kind handoff --base BASE_SHA --head HEAD_SHA
factory inbox lead --archive
factory note "Builder proposed a service when one function was enough"
factory stopThe program uses the Python standard library. Run the tests with:
python3 -m unittest discover -s tests -vThe tutorial site is plain HTML, CSS, and JavaScript under docs/. Preview it
locally with:
python3 -m http.server 8000 --directory docsGitHub Pages must use the main branch and /docs directory.
- No automatic restart
- No automatic merge, rebase, reset, or worktree cleanup
- No message queue
- No GitHub watcher
- No database
- No background updater
These limits are deliberate. Add a mechanism only after an observed failure shows that it is needed.