Use your same workflow across every harness

A multiplexer for coding agents.

Real terminals, persistent sessions, Tailscale-native.
Optimized for mobile: ship from anywhere.

$ uv tool install swe-mux

TRY THE INTERACTIVE DEMO

full screen ⤢

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.

01

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:5173 opens 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.
02

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.

03

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.

The same rows on a phone: two projects expanded with their session rows, each
                  carrying a status dot, an elapsed time, and a model name.
04

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.

05

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 claude in 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, root package.json scripts, and its own actions.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.
06

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.

The Git drawer's worktree map: branch rows carrying ahead and behind counts and
                  a commit provenance column.

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.

07

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.

The note editor body cropped out of the drawer, showing rendered headings,
                  nested lists, and a checkbox row.
The same Markdown editor on a phone, with rendered document structure.
08

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.

09

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.

What it records deterministic, no model, no tokens
  • 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.
What it notices still deterministic, still free
  • 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.
What it makes of it budgeted model, hard caps, off by default
  • 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.
What your agents can read the return path
  • 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.
The ranked attention inbox with its interrupt budget line and a suppressed item
                  showing the reason it was held back.
The same attention inbox on a phone, with ranked items and the budget line.
10

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 doctor to 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.
11

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.

Desktop download not published yet

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.