polymux

One control plane for your coding agents, tmux sessions and servers.

A self-hosted web app for one Linux host. Your projects and their git state, your tmux sessions and the agents running in them, your containers and VMs. Launch agents, read and answer their chats, stop them, from any screen.

Command pm. Single user, MIT licensed. Python 3.13, FastAPI and HTMX, no JavaScript build step.

polymux in the dt theme on a desktop browserEnlarge screenshot: dt theme, desktop: Inbox
polymux in the dt theme on an iPhoneEnlarge screenshot: dt theme, iPhone: Inbox

Thirty tmux sessions, and which one is waiting for me?

I'm a technical guy, not a developer. I built polymux as my own place to experiment with coding agents, and I want to use every coding agent out there, not only Claude Code or Codex.

I work in the terminal and keep many sessions open at once, usually 10 to 50 tmux sessions. With that many it gets very hard to keep track: which agent is waiting for me, what each one answered, and where the docs they wrote ended up.

tmuxwhat tmux tells you
$ tmux ls
api: 4 windows (attached)
billing: 2 windows
blog: 1 windows
docs-site: 3 windows
edge-bgp: 2 windows
infra: 6 windows (attached)
lab-ospf: 5 windows
mail: 1 windows
vm-builds: 2 windows
# ...and 21 more
polymux Inboxsame host

Waiting for you 2

  • Claude Codeapi
  • Codexbilling

Running 3

  • Devindocs-site
  • Cursor Agentinfra
  • Claude Codevm-builds

Idle 2

  • Antigravityblog
  • Codexlab-ospf

Type in tmux or in the browser. It is the same session.

polymux stays in sync with tmux. Every agent and shell is a real tmux pane, so you can type in tmux or in the web UI, from the laptop or the phone, and it doesn't matter: both show the same session.

tmux, api:1, on the laptopclaude
> run the tests and fix what fails
  uv run pytest -q
  2 failed, 148 passed
  Fixed both in tests/test_api.py.
> commit it
polymux chat, on the phoneapi

run the tests and fix what fails

Ran uv run pytest -q: 2 failed, 148 passed. Fixed both in tests/test_api.py.

commit it

Message Claude CodeSend

Any agent, not one vendor

polymux runs the coding agent CLIs you already have, each in its own tmux window, side by side.

  • Claude Code
  • Codex
  • Devin
  • Cursor Agent
  • Antigravity
  • add yours

Launch

Start any of them in a new tmux window with model, effort, permission mode and an optional git worktree.

Follow up

Fork, continue, review, or stop them all. Ended agents keep a permanent page.

Library

See the skills, rules, scripts and MCP servers installed for each agent.

Everywhere you are

I switch screens all day. I needed one place I can open from any of them and still see everything I'm working on.

polymux on a 34 inch ultrawide monitor
34" ultrawide, 3440 x 1440At home, on a Mac mini.
polymux on a Dell 27 inch 2K monitor
Dell 27" 2K, 2560 x 1440At work, next to the laptop.
polymux on a MacBook Pro 14 inch
MacBook Pro 14", 1512 x 982At work, with or without the Dell.
polymux in the classic theme on an iPhone 17 Pro MaxEnlarge screenshot: classic theme, iPhone: Inbox
iPhone 17 Pro MaxOutside. Phone layout with a tab bar.

Where it runs

polymux and your agents run on a Linux VPS or dedicated server. Every device is just a browser pointed at it.

That's on purpose: I don't want coding agents running on my laptop or phone. Your devices never run agents, and you can still reach everything from anywhere.

Want it on your own machine instead? That works too: install it on any Linux box.

Self-hosted, in one place

I want it self-hosted as much as possible. I'd rather not build on a provider's website, and I don't want to copy things back and forth between tools and machines. Everything should live in one place that I choose, and be there when I need it.

Fast, not bloated

I want it fast and not bloated. The core stays small on purpose. If you want another feature, build it as a plugin (pages, nav items, settings, themes, links), so people who want it can install it and everyone else keeps a lean polymux.

Not only code

Much of what runs in my tmux sessions is servers, infrastructure and networking work. polymux keeps it in the same view as the agents: shells, projects, git, containers and VMs.

Host
Resources and processes of the machine pm runs on.
Containers
Docker containers with stop, restart and kill. Names that match your protected globs are never touched.
Stacks
Each project's compose stack, on its project page.
VMs
libvirt guests, per host and per project.
Other hosts
Whether the machines you care about are reachable.
Health alerts
Host health alerts go to ntfy, next to agent state changes.

Optional parts hide themselves when their tool is missing: no Docker, no Stacks; no libvirt, no VMs; no ntfy URL, no ntfy.

What you get

  • Inbox

    All running agents grouped Waiting for you, Running and Idle, with last message, unread badges, recap, exit and resume.

  • Chat

    A live chat view of each agent. Composer with queued messages, file attach and snippets; quick one-off claude -p chats.

  • Projects & git

    Every folder under dev_root is a project. Git badges for dirty, ahead and behind; fetch, pull, push and history.

  • tmux

    Sessions, windows and panes. New session, kill with guards, optional read-only browser terminal.

  • Servers / VMs

    Host resources, processes, Docker containers, libvirt VMs and the reachability of other hosts.

  • Notifications

    Agent state changes and host alerts to ntfy; ntfy topics mirrored into the Inbox.

  • Builder preview

    Agent chat on the left, a sandboxed live preview of the project's static files on the right.

  • Tracker

    Issues, TODO, CHANGELOG and FEATURES live in SQLite and render to Markdown. Agents use the pmctl CLI.

A closer look at dt

Fixture data. Select a screenshot to enlarge it; more on the screenshots page.

  • dt theme, Inbox
    Inbox Agents grouped by who needs you.
  • dt theme, Agent chat
    Agent chat Read and answer one agent.
  • dt theme, Project
    Project Agents, sessions, git and files of one folder.
  • dt theme, tmux
    tmux Sessions, windows and panes.
  • dt theme, iPhone Inbox
    iPhone Inbox
  • dt theme, iPhone chat
    iPhone chat

Two themes, one app

Pick one per browser in Settings or with ?ui=dt on any URL. Set the server default with theme = "dt" in pm.toml.

The classic theme on a desktop browserEnlarge screenshot: classic theme, desktop: Inbox
The classic theme on an iPhoneEnlarge screenshot: classic theme, iPhone: Inbox

classic the default

A sidebar layout with a phone tab bar.

The dt theme on a desktop browserEnlarge screenshot: dt theme, desktop: Inbox
The dt theme on an iPhoneEnlarge screenshot: dt theme, iPhone: Inbox

dt newer, keyboard first

A keyboard-driven shell: tabs, a sessions sidebar, command menus and layered panels. This site borrows its colours.

dt speaks vim and macOS

Vim-style keys for lists and pages, macOS-style search and switching. Use Ctrl instead of ⌘ on Linux and Windows.

JK
Move through a list
⌘Kor⌘⇧P
Search everything
GthenIPT
Go to Inbox, Projects, tmux
>
Typed in search: commands only
/
Filter the list
⌘P
Go to a session
?
Show all keys
⌘B
Toggle the sidebar
Esc
Close the top layer
⌘,
Open settings

Security model

pm can send text to coding agents, kill tmux windows, stop containers and change VMs. Treat access to it like a shell on the host.

One user, one host

  • Runs as your user on one Linux host, never as root.
  • Binds to loopback. Other machines reach it only through a TLS reverse proxy.
  • Log in with a token (created with mode 0600 on first start) or a passkey. Failed logins back off.
  • Optional TOTP; with require_unlock on, every change needs a TOTP or passkey unlock first.
  • Session cookie is Secure, HttpOnly, SameSite=Strict; sessions can be listed and revoked.

Protected by default

  • Every tmux session is protected unless its name matches a glob you allow. pm* sessions always are.
  • Containers and VMs that match your protected globs are never changed.
  • Pane text is stripped and masked for secrets, and never logged, indexed or sent to ntfy.

Every change passes one guard

  1. Logged-in session, else 401.
  2. Origin check against your allowed origins, else 403.
  3. Per-session CSRF token, else 403.
  4. Unlocked session, when require_unlock is on.
  5. Tier check against the tier ceiling.
  6. Audit line written and synced to disk. If that fails, the request is refused.

Tiers

TierAllows
0View: read pages
1Safe: edit backlog and TODO, git remotes, project settings
2Message: send text to agents, fork, exit, quick chat, terminal ticket (the default ceiling)
3Terminal: reserved, not enabled

Found a security problem? Please report it privately with GitHub private vulnerability reporting, not in a public issue. Full model: SECURITY.md.

Quick start

Linux, Python 3.13 or newer through uv, tmux and git. Docker, libvirt, ntfy and the agent CLIs are optional.

$ git clone https://github.com/dungtq/polymux.git
$ cd polymux
$ uv sync
$ uv run pm
  • Open http://127.0.0.1:8093. On first start pm writes a login token to ~/.config/pm/token (mode 0600). Paste it into the login form.
  • Plain http:// works only on 127.0.0.1 and localhost, because the session cookie is Secure. Anywhere else, put pm behind a TLS reverse proxy: docs/INSTALL.md.
  • The git panel fetches, pulls and pushes the remote named gitdev. Add yours under that name in each project.
  • Every pm.toml key and its default: docs/CONFIG.md.

early, about 10 days old

Status and contributing

I have been building polymux for only about 10 days, so it still has bugs. It is a working tool I use every day, but it moves fast: pages change and some parts are unfinished.

Both themes have bugs. classic works but has open UI issues, from a low-contrast label to rows that stretch too wide on big screens and a few iPhone wrapping glitches. dt is newer and still being built: some pages are not ported yet and show their classic version inside the dt shell.

The cool part: polymux is where I work on all my other projects, so I keep fixing polymux along the way. Every rough edge I hit while doing something else turns into the next fix.

Contributions are very welcome: bug reports, ideas, fixes, support for more coding agents, new themes.