A multiplexer for coding agents.
Real terminals, persistent sessions, Tailscale-native.
Optimized for mobile: ship from anywhere.
It owns the pseudoterminals, so Claude Code, Codex, opencode and any other CLI run exactly as they do outside it. Around them: one status vocabulary telling you which agent is working, which is blocked and which is waiting on you; sessions that outlive the browser, the daemon and app updates; and the same interface on your phone over your own tailnet, with nothing turned off. Underneath, a record taken from the work rather than from the agent's account of it, and finished branches landed one at a time behind a check you approved.
uv tool install swe-mux
Isolated environment, and mux, muxd,
swe-mux on your PATH globally. No desktop shortcut - no Python install makes one.
On Windows, uv tool install "swe-mux[desktop]" adds the native window and the
tray.
The workbench
Sessions, panes, tabs, notes, files, git, previews, a Run menu you define. Everything you look at.
The control plane
Deterministic evidence, model-free detectors, ranked incidents, an interrupt budget, a return path agents can read. Decides what you look at.
The second is only buildable on top of the first. You cannot measure a fleet whose terminals, shells, and input telemetry you do not own.
The whole workspace, on your phone
Live terminals, git review, the Markdown editor, files, the queue, previews, the Run menu, lock-screen push. No feature exists on the desktop and not on the phone. What is desktop-only is hidden terminal pre-warming, the collapsed sidebar rail, and keyboard chords a phone cannot produce. Other orchestrators' phone clients watch; their own pages call them companions.
- The actual terminal. Not a rendered chat log. The real TUI, with the diff colours, the picker, and the approval prompt as the CLI drew them.
- One session, several devices, exactly one writer. Input ownership is arbitrated and the size negotiated, so the desktop does not fight the phone over the same PTY.
- A projection, not a second layout. The phone flattens the same workspace tree into one rail. There is no separate mobile build to drift.
- Your dev server, on your phone. A listener a session owns is proxied
through swe-mux's own URL, so
127.0.0.1:5173opens from the couch with no port exposed anywhere. - No relay. It reaches your machine over your own tailnet. No swe-mux login, and no backend this project operates.
Every harness, and every shell
Anything that runs in a terminal runs here, unchanged. PowerShell, CMD, Git Bash, WSL, bash, zsh, vim, lazygit, an agent CLI that shipped this morning and has never heard of swe-mux. Real pseudoterminals, real signals, real Unicode widths, real bracketed paste. A harness swe-mux does not recognize still works; you just do not get the layer on top, and adding one is a descriptor and an adapter rather than a branch through every feature.
- InputNewline, submit, paste, copy, and caret placement behave the same in every CLI. Each harness's measured composer quirks live in one resolver.
- StatusOne vocabulary across vendors: working, ready, awaiting approval, blocked. Derived from hooks, then transcript, then PTY, then the CLI's own state.
- TranscriptsOne reader over every conversation format, including the store-backed ones that are not files at all.
- HistoryOne search box over every conversation any supported harness has written on this machine, and resume back into any of them.
- AccountsOne switcher and one quota view across providers. Saved accounts, login swap, per-account reset windows, usage that survives the switch.
Native transcripts are never moved, rewritten, or deleted. The searchable copy is a local derivative you can throw away and rebuild.
Know which agent needs you
Every session carries a state you can trust: working, ready, awaiting approval, or blocked, derived from provider hooks first, then the transcript, then the PTY, then the CLI's own reported state. Every transition is written to a durable ledger with the layer readings that produced it, so when a status looks wrong you can read exactly why it changed, hours later. A watchdog catches sessions that stopped reporting.
Sessions that outlive the app itself
Every terminal is a pseudoterminal held by a supervisor process separate from the daemon and from the UI. Close the browser, restart the daemon, rebuild and redeploy the whole desktop application, and the agents keep working. The next daemon rediscovers the supervisor and reattaches every live session from mirrored metadata plus a scrollback snapshot. Reconnecting replays only the bytes you missed, so a phone that slept through a long turn comes back to an intact buffer.
A supervisor cannot survive its own death: a crash, a force close, or a power loss takes the processes with it. Cold session recovery covers that, bringing those sessions back as readable, resumable rows carrying what they last printed.
The workbench
One Project is one folder you register. It owns its sessions, layout, notes,
files, and history for their whole lifetime, and a terminal that wanders elsewhere with
cd never changes who owns it.
- Mixed workspaceA recursive split tree where every leaf holds its own tab stack: terminals, notes, files, dev-server previews, transcripts, history, queues. Panes and tabs are viewports, so closing one kills nothing.
- Promotion in placeNo backend picker. Type
claudein a plain shell and the session promotes where it stands: same pane, same scrollback, now carrying a transcript, a status, a queue, and a context meter. - A Run menu you defineImports your
tasks.json, rootpackage.jsonscripts, and its ownactions.toml. Nothing runs until you approve that file's exact bytes, and any edit revokes the approval. - Prompt queueStage ordered messages against a conversation mid-turn. Durable across restarts, strict head-of-line, and bound to the first run so a cleared conversation strands the queue visibly instead of firing into a stranger.
- Previews without exposed portsA loopback listener a session owns becomes a Preview tab, proxied through swe-mux's own URL. HTTP and websocket both, so hot reload works from a phone.
- Worktrees, atomicallyCreate the worktree, run your setup command, and start a session in its exact root as one operation. Worktrees stay git artifacts and never become sidebar rows.
Git that knows which agent did it
Branch, HEAD, dirty count, upstream divergence, and lines changed against a comparison ref you choose per Project, polled read-only so a status check never takes a lock in a repository your agents are working in. Review changed files, annotate a diff line by line, and send the comments back to the agent that wrote them. Every commit carries durable provenance: which session and which conversation produced it, split into committer and contributor, with a confidence level and the files each contributor's writes account for.
Finished branches land through a queue, one at a time. It reconciles the branch with the trunk, runs the verification command whose exact bytes you approved, and fast-forwards. It decides nothing - a conflict or a failed gate comes back to the session that asked.
Notes that are a real editor
A WYSIWYG Markdown editor built in house, not a textarea with a preview pane bolted to it. Headings, lists, tables, code blocks, outline navigation, find, and a formatting rail that works with a soft keyboard up. Every note is an ordinary Markdown file in your Project, written with revision checks so two devices cannot clobber each other, and gitignored by default. Send a selection straight to an agent, or have an agent write into the same file and watch it update.
Drive it without touching it
Speech-to-text decodes on your own machine in both shipped
configurations: faster-whisper by default (the voice-local extra, whose models
download once from Hugging Face and then run offline), or Windows Speech Recognition. There is
no cloud speech path and no browser fallback - without an engine, transcription returns a typed
error rather than sending audio anywhere. Dictate across natural pauses, navigate by spoken
coordinate, ask the fleet for status, approve a prompt, interrupt a run. Read aloud and
hands-free conversation are off until you turn them on.
Push notifications reach your lock screen, raised from normalized lifecycle events - a turn completing, a session going ready, an approval or question, a failure, a confirmed unexpected quota reset - rather than from terminal activity, with three rules holding back the ones not worth interrupting for. The detector reads several layers, has explicit unknown states, and resolves ambiguity to the conservative prior rather than to a guess.
The control plane
The agent CLIs are the data plane; they do the work. This layer observes, records, and routes attention without ever sitting in an agent's execution path. It never types, approves, spawns, or edits anything, and every write path ends at a human pressing something. Capture and detection are deterministic and spend nothing; a model is reached for only at the last mile, under a hard cap.
Nothing here runs until you switch it on, per Project. Every automation below ships off, with one exception: a permission gate that reads nothing and spends nothing. Before an agent can trigger a land, four separate things have to be true - the install-wide switch, the Project's opt-in, an authority level raised from its default of "a human approves the request", and a verification command whose exact bytes you approved.
- Tier 0 factsEvery file write hashed on the exact bytes written, every command with its exit class, test output parsed down to the failing set, git operations, tool calls. Each fact points back to the moment it happened.
- Operational telemetryDurable process, quota, reset, compaction, and tool evidence, plus a status timeline you can query by time range long after the incident.
- Model-free detectorsLoops with a no-progress gate, work declared done that never ran a test, documentation debt, provenance edges. Annotations only, with the facts each finding rests on attached.
- Code graphBlast radius, test gaps, dead code, import cycles, and a per-session change map. Tree-sitter parsing, not a language model.
- Fleet faultsSessions that stopped reporting, conversations two sessions both claim, transcripts that went stale underneath a running agent.
- Behaviour timelineA cheap model reads the conversation forward and extracts structured records, including the dead ends. Daily, hourly, and per-run budgets, and it writes nothing rather than guess when a response fails validation.
- Attention rankingFindings merge into incidents and route to one of four channels by what they cost you to resolve, under a default budget of four interrupts a day and two an hour. Held-back items stay counted and visible with the reason, because a hidden item is indistinguishable from a broken detector.
- An MCP endpoint per sessionRegistered at spawn. Agents read sibling status, run briefs, transcripts, history, Project notes, and Agent Context sources, scoped to their own Project unless asked to widen.
- Cross-session memoryWhat a previous session already resolved, what it verified, and what it tried and abandoned. A new agent can find the dead end instead of walking into it.
- Bounded writesMessage another session, request a spawn, interrupt, or end a run. Every one waits for a human by default, and refusals are typed rather than silent.
Also in the box
- Process ownershipAttribution by PID plus creation time, unioned with job-object membership, so a detached grandchild is still yours. Find the dev server from Tuesday still holding the port, and the headless browser windows nothing else can see.
- Agent environmentWhat skills, MCP servers, hooks, plugins, and policies this CLI is running right now, and whether any of it has drifted since it started. Read-only, and it never prints a hook's command line.
- Agent contextWhich instruction files the agent actually loads, with reversible, revision-guarded sync across harnesses so your instruction files stop disagreeing with each other.
- Remote accessYour tailnet only. No swe-mux login, no port forwarding, no Funnel, no relay. Optional HTTPS for the microphone and clipboard APIs that demand a secure context.
- Usage analyticsCost and token history by source, model, and tool, with quota windows and reset tracking per saved account.
- DiagnosticsSupervised background loops with per-loop cost accounting, event-loop lag sampling, a durable state log, and
mux doctorto export the whole picture. - Small thingsThemes, per-device UI scale, configurable session rows, command palette, network accounting, device presence, guided onboarding, QR pairing for a phone.
Install
You need at least one agent CLI already installed and logged in. swe-mux does not install, manage, or proxy them. It runs the ones you already have, on the subscription you already pay for.
This section is drawn from the same release manifest the app's own update check reads, so it fills itself in on the first release that carries a Windows installer.
Until then the Python install below is the whole product, and on Windows
swe-mux[desktop] is the same native window and tray icon the installer will set
up for you.
From PyPI
Python 3.12 or newer.
$ uv tool install swe-mux # isolated env; mux, muxd, swe-mux on PATH $ mux doctor # read-only health report $ muxd # daemon on 127.0.0.1:8765
Open 127.0.0.1:8765 and register a Project folder. Nothing spawns
until you ask. pipx install swe-mux is the same isolated, on-PATH install without
uv.
No Python install of any kind creates a desktop shortcut or a Start Menu entry. Wheels have no post-install hook and pip runs no install-time code, so that is structural rather than a step somebody forgot: start swe-mux from a terminal.
On Windows, take the desktop extra - uv tool install
"swe-mux[desktop]" - for the native window and the tray icon, which want the WebView2
Runtime. Without it, swe-mux still exists and fails on a missing import. The extra
is declared Windows-only, so on Linux and macOS it resolves to nothing and the daemon plus a
browser is the whole product.
pip install swe-mux is a different act. It installs into
whichever environment is active and puts nothing on PATH globally, so mux works
only inside that environment. pip says so in a WARNING: The scripts ... are installed in
'...' which is not on PATH that scrolls past unread. If that is where you are:
$ python -m swe_mux # the daemon, no PATH setup at all: this is muxd $ python -c "import sysconfig; print(sysconfig.get_path('scripts'))" # where the three executables went $ pip show -f swe-mux # every file this install wrote
From source
$ git clone https://github.com/jatoran/swe-mux $ cd swe-mux $ uv sync --extra desktop $ npm --prefix frontend ci && npm --prefix frontend run build # only the source flow needs Node $ uv run --extra desktop swe-mux
The frontend build output is gitignored, so a fresh clone serves the API and no interface until that build runs once. A published wheel carries the built frontend already.
The wheel is pure Python, and CI builds and install-smokes it on Windows, Linux, and macOS on every push. What no CI job does anywhere is start the daemon - Windows is the platform that proves this thing running, and the macOS leg is not yet required to pass.
Upgrading, uninstalling, and what to do when the daemon will not start: OPERATOR_LIFECYCLE.md.