by mixpeek
Open-source Claude Code agent multiplexer — run dozens of parallel AI coding agents unattended via tmux
# Add to your Claude Code skills
git clone https://github.com/mixpeek/amuxOpen-source control plane for AI agents. Run dozens of parallel agent sessions from your browser or phone — with a web dashboard, kanban board, notes, CRM, email, browser automation, slash-command skills, and agent-to-agent orchestration. Self-healing, single-file, zero external dependencies. Currently supports Claude Code via tmux.
amux.io · Getting started · FAQ · Blog
git clone https://github.com/mixpeek/amux && cd amux && ./install.sh
amux register myproject --dir ~/Dev/myproject --yolo
amux start myproject
amux serve # → https://localhost:8822
License: MIT + Commons Clause — free to use, modify, and self-host. Commercial resale requires a separate license.
| Problem | amux's solution | |---------|----------------| | Claude Code crashes at 3am from context compaction | Self-healing watchdog — auto-compacts, restarts, replays last message | | Can't monitor 10+ sessions from one place | Web dashboard — live status, token spend, peek into any session | | Agents duplicate work on the same task | Kanban board with atomic task claiming (SQLite CAS) | | No way to manage agents from your phone | Mobile PWA + native iOS app — works anywhere, offline support | | Agents can't coordinate with each other | REST API orchestration — send messages, peek output, claim tasks between sessions | | Agents operate in a vacuum — no shared context | — 1:1 inter-session chat with @mentions so agents can coordinate in real time | | No persistent knowledge between sessions | — markdown documents agents can read, write, and reference across sessions | | No way to automate recurring work | — named cron-style recurring jobs with built-in management UI |
No comments yet. Be the first to share your thoughts!
/commit, /review-pr) that agents can invokeParses ANSI-stripped tmux output — no hooks, no patches, no modifications to Claude Code.
| Condition | Action |
|-----------|--------|
| Context < 50% | Sends /compact (5-min cooldown) |
| redacted_thinking … cannot be modified | Restarts + replays last message |
| Stuck waiting + CC_AUTO_CONTINUE=1 | Auto-responds based on prompt type |
| YOLO session + safety prompt | Auto-answers (never fires on model questions) |
| /rate-limit-options (any session, fleet-wide) | Auto-presses 1, records reset time, auto-resumes at reset |
When a single Max/Pro account's usage cap is hit, every active Claude Code
session on that account blocks at the same /rate-limit-options prompt
within seconds. amux's watchdog detects this fleet-wide, presses option 1
("Stop and wait for limit to reset") on each blocked session, parses the
reset time from the surrounding scrollback, and steers a resume message
to every still-parked session once the reset time passes.
The dashboard shows a per-session "Rate-limited until HH:MM" badge plus a header pill summarizing the fleet ("N of M rate-limited, reset HH:MM").
Per-session resume text — set CC_RATE_LIMIT_RESUME_TEXT in
~/.amux/sessions/<name>.env to override the default continue. Useful
for orchestrators or supervisors that need a richer resume prompt:
echo 'CC_RATE_LIMIT_RESUME_TEXT="peek workers, surface phase STOPs, resume monitoring"' \
>> ~/.amux/sessions/orchestrator.env
Fleet auto-resume mode — set AMUX_RATE_LIMIT_MODE in
~/.amux/server.env:
| Mode | Behavior |
|------|----------|
| off | Detect prompt and press 1, but do NOT auto-resume — user must steer manually |
| capped (default) | Auto-resume up to AMUX_RATE_LIMIT_BUDGET times per session per UTC day (default 3); fall back to manual after the cap |
| unlimited | Auto-resume every time, no cap |
A user who manually intervenes on a rate-limited session (picks option 2/3, types something new, archives it) is detected at reset time via a state-aware scrollback check, and auto-resume is skipped for that session.
Manual verification: install the feature on a development server, then inject a fake prompt into a test session's tmux scrollback:
tmux send-keys -t amux-rl-test \
$'What do you want to do?\n❯ 1. Stop and wait for limit to reset\n 2. Add funds\n 3. Upgrade your plan\nresets 23:59\n' \
Enter
Within ~3-15 seconds the dashboard card should show the badge and
~/.amux/logs/server.log should contain [rate-limit] session=... auto-selected option 1, reset_at=....
Simulation caveats: tmux send-keys lands text at Claude's input
prompt, not as raw terminal output, and Claude may render or re-render
it differently than a real rate-limit event. Two pitfalls to be aware of:
The strict reset-time parser may not match Claude's actual rendering; when that happens the watchdog applies a 5-minute safety fallback so the auto-resume path still exercises end-to-end. Real rate-limit windows are always >1h, so the fallback never causes premature resume.
If the menu text persists in Claude's input area without being
submitted, the detector will re-fire every ~12 seconds (10s cooldown +
3s tick). Send C-c to the session after the initial detection if you
want to stop the loop while observing badge/pill behavior:
tmux send-keys -t amux-rl-test C-c
The simulation is a sanity check; the integration test for the real
rendering can only be done against an actual rate-limit event. If you
hit one on a development account, capture tmux capture-pane -p -t amux-<session> -S -300 to a file and feed it through the parser:
python3 -c "import sys; sys.path.insert(0,'.'); \
import importlib.util as iu; \
spec = iu.spec_from_file_location('a','amux-server.py'); \
m = iu.module_from_spec(spec); spec.loader.exec_module(m); \
print(m._parse_rate_limit_reset(open('capture.txt').read()))"
# Send a task to another session
curl -sk -X POST -H 'Content-Type: application/json' \
-d '{"text":"implement the login endpoint and report back"}' \
$AMUX_URL/api/sessions/worker-1/send
# Atomically claim a board item
curl -sk -X POST $AMUX_URL/api/board/PROJ-5/claim
# Watch another session's output
curl -sk "$AMUX_URL/api/sessions/worker-1/peek?lines=50" | \
python3 -c "import json,sys; print(json.load(sys.stdin).get('output',''))"
Agents get the full API reference in their global memory, so plain-English orchestration just works.