Documentation

The complete guide, from download to daily operations. Read the Getting Started part (about 10 minutes) and you'll have your first managed AI coding agent running on a remote server.

What is AgentMux#

AgentMux is a desktop application for operating AI coding agents — Claude Code, Codex, Gemini CLI, OpenCode, Aider, Cursor CLI — that execute on remote hosts and on this computer. Its core mechanism fits in one sentence:

The core mechanism Every agent runs inside a tmux session on its host; AgentMux attaches to that session instead of owning the process. Closing the client, suspending the laptop, or losing the network therefore has no effect on work in progress — persistence is guaranteed by construction.

It ships as a single binary: no server, no daemon, no account. All state is one SQLite file in the application data directory. Each remote host gets one multiplexed SSH connection — terminals, commands, and file transfers are channels on it, so ten terminals against one host is one authentication. Idle connections close after ten minutes.

Requirements#

The computer running AgentMux

PlatformRequirement
macOSmacOS 11 (Big Sur) or later; universal binary for Intel and Apple Silicon
WindowsWindows 10 or later
LinuxGTK3 and WebKitGTK 4.1 at run time — libwebkit2gtk-4.1-0 on Debian/Ubuntu, webkit2gtk4.1 on Fedora
Tablet / phoneAny modern browser — the server runs elsewhere (see Tablet & Phone). Android also has a standalone app with the core embedded: Android 8.0+ · arm64

Managed hosts

  • Remote Unix-like hosts (Linux / macOS): a POSIX shell, tmux, and an SSH account. Missing tmux is fine — the install panel can install it.
  • Remote Windows hosts: just enable OpenSSH Server. There is no tmux there — sessions are hosted by AgentMux's own session daemon, deployed over SFTP on first use, with its protocol riding an SSH port forward, never a remote shell.
  • Screen-only hosts: machines you want to watch rather than work on need nothing but an address with RDP or VNC answering — no SSH, and no credentials stored anywhere (see Host Operations → Screen-only hosts).
  • This computer (Linux / macOS): just a local tmux — no sshd, no credentials.
  • This computer (Windows): the same machine offers two hosts — the default WSL distribution (where tmux lives) and native Windows (PowerShell, Windows paths and toolchains, for MSVC builds, WPF, and running the .exe you just built). Native sessions persist through AgentMux's own session daemon, so closing the window doesn't stop native work either.

Optional: orchestrator and semantic search

Local orchestration and semantic memory search require Ollama plus one chat model and one embedding model. Without Ollama, everything else is fully functional.

Installation#

Each release provides one build per platform, produced by GitHub Actions from the tagged commit, with a .sha256 alongside. Builds are not yet code-signed or notarized, so the first launch takes one extra confirmation per platform.

macOS

  1. Download agentmux-macos-universal.zip, unzip, and drag AgentMux.app into Applications.
  2. Handle the unsigned-build prompt per your macOS version (table below).
  3. After that, it opens normally.
macOS versionProcedure
15 Sequoia or laterOpen once and let it be blocked → System Settings → Privacy & Security → Security → Open Anyway
14 Sonoma or earlierControl-click the app → Open → Open
Any versionRun xattr -dr com.apple.quarantine /Applications/AgentMux.app, then open normally
Skipping the quarantine flow entirely The quarantine attribute is applied by the browser, not by the archive. Downloading with curl -L -O <url> avoids it altogether.

Windows

  1. Download and unzip agentmux-windows-amd64.zip — it contains agentmux.exe and an install script.
  2. Double-click to run; when SmartScreen appears, choose More info → Run anyway.
  3. For a proper install (to %LOCALAPPDATA%\Programs\AgentMux, with desktop and Start menu shortcuts, no administrator rights), run from the unzipped folder:
powershell -ExecutionPolicy Bypass -File install-windows.ps1

The same script with -Uninstall reverses it, without touching the data in %APPDATA%\AgentMux.

Linux

  1. Install the runtime dependency first: sudo apt install libwebkit2gtk-4.1-0 on Debian/Ubuntu, sudo dnf install webkit2gtk4.1 on Fedora.
  2. Download and extract agentmux-linux-amd64.tar.gz — binary, icon, .desktop entry, and install.sh.
  3. Run ./install.sh, or execute the binary directly.

Verifying downloads

# every file ships with a .sha256:
shasum -a 256 -c agentmux-macos-universal.zip.sha256   # macOS
sha256sum -c agentmux-linux-amd64.tar.gz.sha256        # Linux

Server build (headless)

The same application also ships as a fully static headless build: agentmux-server-linux-amd64.tar.gz and agentmux-server-linux-arm64.tar.gz. It links no GTK and no webview and needs no display — run it on any Linux server and it serves the complete web application. The recommended way to deploy it is the one-line install script, which also sets up a systemd service and self-updates — see The Headless Server.

Android

  1. Download agentmux-android.apk (Android 8.0+ · arm64) and install it on the phone or tablet — you will need to allow installation from unknown sources.
  2. On first launch a foreground service starts the embedded core and the WebView connects to 127.0.0.1. No server is involved.
  3. When the repository has signing keys configured the APK is properly signed and upgrades in place; otherwise it carries a debug signature — installable all the same, but uninstall the old one before switching signatures.

Quick Start#

Four steps to your first managed agent. Everything here is also reachable through the Ctrl/⌘ K command palette — the fastest route to any action.

Step 1: Add a host

A remote host needs three things:

  • Address and user — the same ones you'd use with ssh user@host.
  • One of three auth methods: ssh-agent (recommended — nothing to fill in), a key file (passphrase supported), or a password.
  • Jump hosts (optional) for environments behind a bastion.
Host keys are pinned on first connection The host key is recorded the first time you connect. A later mismatch aborts the connection with an explanation — that's man-in-the-middle protection, not a bug. If the host genuinely got reinstalled, delete the host record and add it again.

This computer asks for nothing but a name — no sshd, no credentials. On Windows you'll see two local hosts: the WSL distribution and native Windows. Pick per workload — Unix toolchains go to WSL; MSVC/WPF go native.

Step 2: Add a project and workspace

A workspace is a working directory on the host (usually a repository root). Two ways to add one:

  • The form: pick a host, enter a path.
  • The file browser (faster): browse the host's files, find the directory, and "add as project" in place — its name, path, and host are already known.

Step 3: Add an agent and start it

An agent is a name plus the command that starts it — the same command you'd type in a terminal:

# typical start commands, adjust to taste
claude                    # Claude Code
codex                     # OpenAI Codex CLI
gemini                    # Gemini CLI
aider --model sonnet      # Aider
opencode                  # OpenCode

Hit Start and it's running inside tmux on the host. Agent API keys are configured on the host side (the agent's own config or environment) — AgentMux neither reads nor proxies them.

Step 4: Attach and work

Click the agent, or search its name via Ctrl/⌘ K. What you get is a real terminal — colour, mouse, selection, search. Step in and type at any time, correct the agent's course, hand control back — no restart needed. The side panel provides Start / Stop / Restart / Attach, process state, and recent output.

Verify the persistence claim Attach to a running agent, quit AgentMux entirely, reopen it — you're back in the same pane with scrollback intact. The agent never noticed you left.

The Terminal Wall#

The terminal area divides into up to nine panes (3×3), each holding its own session — on one host or several, each independently interactive:

  • Add a pane: Ctrl/⌘ \. With an open tab spare it splits instantly; otherwise a dialog offers hosts, workspace directories, running agents, and open tabs.
  • The layout adapts: panes divide the area in proportions, not pixels. A column too narrow to read is dropped, so a narrowed window wraps the 3×3 wall into a taller grid instead of nine slivers.
  • Drag the seams to resize panes.
  • Temporary zoom: double-click a pane's tab (or Ctrl/⌘ ⇧ ↵) to fill the area; again to restore. The split underneath is untouched.
  • A pane is a view, not a session: closing one (Ctrl/⌘ ⇧ \) hides the terminal while the tab and its shell stay attached. The pane count is restored on next start.

Keyboard Shortcuts#

ShortcutAction
Ctrl/⌘ KCommand palette — the fastest route to attaching, opening shells, installing CLIs, changing theme
Ctrl/⌘ BShow or hide the tree
Ctrl/⌘ \Add a pane — instantly with the next open tab, otherwise asking what to attach
Ctrl/⌘ ⇧ \Close the pane, leaving the tab and its shell open
Ctrl/⌘ ⇧ ↵Fill the area with the focused pane, and back again
Ctrl/⌘ ⌥ ← →Move between panes — zoomed, this reads them one at a time

Broadcast & Receipts#

The Broadcast panel sends one instruction to any selection of agents — across projects and hosts. Unlike pasting into each terminal, every agent returns a delivery receipt telling you whether the instruction actually arrived.

  • Target by project, by host, or tick agents individually.
  • Per-agent delivery status; failed deliveries stand out and can be retried individually.
  • Typical uses: pausing the whole fleet, issuing a new constraint ("all commit messages in English from now on"), polling progress across agents.

Host Operations#

The install panel: provisioning a new host

The install panel inspects the host first and offers only the agent CLIs and runtimes it can actually support, stating why others are unavailable. Installation runs inside tmux, so an interrupted connection cannot leave a partial package tree. tmux itself can be installed from here when missing.

One-click install covers the agent CLIs — Claude Code, Codex, Gemini CLI, Grok CLI, OpenCode, Aider, Cursor CLI — and runtimes including Node, Python, tmux, Docker and Ollama. Docker offers six methods (the official script first, then the distributions' own packages, then Docker Desktop through Homebrew), retrying against a mirror where the network needs one. Every engine install ends by starting the daemon and adding the user to the docker group, and says out loud that the group needs a fresh login.

Host telemetry

Per-host metrics are collected in a single command:

  • CPU by mode and by core, memory, load
  • Disk usage and throughput, network, file descriptors
  • NVIDIA GPU utilisation where present

SFTP browser and editor

File access rides the same SSH connection. Writes are atomic and carry a modification check: if an agent working in the same directory changed the file, the save is refused rather than silently overwriting — look at what changed first, then decide.

Remote desktop (built-in RDP / VNC viewer)

Some work is a screen: an installer that insists on a window, a GUI test, a machine somebody has to look at. Right-click a host and pick Open desktop — the three usual ports, 3389 (RDP) and 5900 / 5901 (VNC), are dialled concurrently, and deliberately nothing beyond them: a tool that port-scans other people's machines on its own initiative is not a reasonable tool. On an SSH host the dial rides the connection that host already has, so a desktop listening on its own loopback needs nothing opened to the network and no second set of credentials.

  • The viewer lives inside the application: the desktop opens as a tab in the terminal area, right next to your terminal panes. It is a real protocol client, not a picture of one — noVNC for VNC, IronRDP compiled to WebAssembly for RDP — loaded on demand, so people who never open a desktop never pay a byte for it. The remote resolution follows the pane as you resize it.
  • Because the viewer is in the application, the capability exists on every client — the desktop app, a browser, a tablet, a phone — no longer depending on what happens to be installed locally.
  • Login credentials are entered when the session opens, sent to the host over its existing channel, and kept nowhere.
  • When Windows refuses a login you are told what it actually refused, not an NT status code: account locked out (and for how long), password expired, account disabled, not in the Remote Desktop Users group, logon-hours restrictions, a missing domain prefix — the common causes are translated, each with its remedy.
  • The desktop app still offers a System client option: the answering port is forwarded to loopback on this computer and handed to whichever viewer it has — mstsc on Windows, Screen Sharing on macOS, Remmina or FreeRDP on Linux. The forward closes itself five minutes after the last client leaves, releasing the SSH lease; if no viewer is installed, it stays up and reports its address.
  • Which desktop a host serves is remembered — only endpoints that actually answered, never a misdialled port — so the second opening asks nothing. That memory belongs to the host rather than to this installation, so it travels with a configuration export.

Screen-only hosts

Wanting to watch a machine and wanting to work on one are different needs. The Remote desktop host kind serves the first: a name, an address, and the operating system — which decides the protocol (RDP for Windows, VNC for macOS / Linux) and suggests the port, both editable. There is no credentials field at all: whatever the desktop asks for is entered when a session opens and kept nowhere.

  • In the tree it is exactly a screen: no terminal, no agents, no workspaces, never a jump-host candidate, and no seat in the SSH connection pool — nothing that needs a shell will offer it as one.
  • It is dialled directly on its desktop port, like any ordinary remote desktop client would; Test connection dials that port and reports the latency.
  • Promoting it to a machine you can work on: its detail panel quietly probes port 22. If SSH answers, an Add as SSH host button opens the host dialog with the address pre-filled — a new, full host is created and the screen-only row stays as it was. If SSH does not answer and the system is Windows, the panel lays out the exact PowerShell command that enables OpenSSH Server, with one-click copy — paste it into the desktop pane you already have open, run it there, and hit refresh.
  • With OpenSSH enabled, add the machine as a Remote Windows host and agents run natively — PowerShell, MSVC, WPF — kept alive by AgentMux's session daemon, so closing the window stops nothing. From then on the machine is both a screen and a place to work.

Make and model

The metrics panel now answers what a machine is, not only what it is doing: CPU model, DIMM specs, physical drives and graphics adapters. Those are static, so they ride a separate one-shot read cached for the session rather than the three-second ticker.

The Headless Server#

AgentMux's core can run without a window: a fully static headless build that links no GTK and no webview, and serves the complete web application from any Linux server — terminals, agents, broadcast, file browsing, remote desktop, the same feature set as the desktop build, not a reduced view. The desktop app, phones, tablets and any browser can connect to it and see one set of hosts and one set of running sessions.

The one-line install (recommended)

curl -fsSL https://raw.githubusercontent.com/tan-zhuo/AgentMux/main/scripts/install-server.sh | bash

The script does everything on a Linux server (amd64 / arm64), entirely as the calling user — no root required:

  • Downloads the server build for the current architecture, verifies the .sha256, and installs to ~/.local/bin — new file first, then an atomic rename, so a half-written binary can never exist.
  • Registers a systemd user service (~/.config/systemd/user/agentmux.service, restarted on failure) and enables lingering — the service keeps running after you disconnect or log out. Machines without systemd fall back to nohup plus an @reboot crontab.
  • Enables HTTPS by default (self-signed certificate), listening on :8642.
  • Probes the server and only reports success once it actually answers; if it does not start, the relevant lines of the service log are printed for you, along with the most common cause (a taken port — pick another with --addr).
  • On success it prints the three things a client needs: the address, the access token, and the certificate fingerprint.

Common options (after bash -s -- when piping):

OptionDefaultEffect
--addr ADDR:8642Listen address; 127.0.0.1:8642 restricts to this machine (for a reverse proxy)
--no-tlsTLS on by defaultPlain HTTP instead of self-signed HTTPS (trusted LANs only)
--mirror URL—GitHub downloads through a mirror prefix (e.g. https://ghfast.top); same convention as the in-app update mirror
--version vX.Y.ZlatestInstall a specific version
--prefix DIR~/.local/binWhere the binary goes
--no-service—Install the binary only; register and start nothing
Rerunning it is upgrading it Run the same line again and you have upgraded: your existing listen address and TLS choice are kept, the binary is replaced, the service restarted. The headless build also carries its own updater — when the web interface shows a new-version banner, one click replaces the binary in place with the same PID; systemd never notices.

Running it by hand

# server build (agentmux-server-linux-*): running it is serving; :8642, plain HTTP by default
./agentmux

# with flags: all interfaces, self-signed HTTPS
./agentmux --addr 0.0.0.0:8642 --tls

# the desktop binary enters the same mode
agentmux --serve --addr 0.0.0.0:8642 --tls
FlagEnvironment variableMeaning
--addrAGENTMUX_ADDRListen address, default :8642
--tlsAGENTMUX_TLS=1Self-signed HTTPS; the certificate is generated once and reused from the data directory
--tls-cert / --tls-keyAGENTMUX_TLS_CERT / AGENTMUX_TLS_KEYBring your own PEM certificate and key (a CA-issued one, say)
—AGENTMUX_TOKENChoose the access token yourself
—AGENTMUX_DATA_DIROverride the data directory

The first start prints the access token (48 hex characters, persisted as serve-token in the data directory, mode 0600) and, with TLS on, a certificate SHA-256 fingerprint — the line every client pairs against.

Encryption and trust: a self-signed certificate, pinned by fingerprint

A self-signed certificate has no CA to vouch for it, so each device decides whom to believe: on first connection the client fetches the certificate, shows its SHA-256 fingerprint, and you compare it against the line in the server's log before confirming. From then on that device accepts exactly that certificate — no names, no expiry dates; a changed fingerprint is a refused connection. Switch the address to a proper CA certificate and the pin retires itself in favour of normal verification. Every value meant to be carried — token, address, fingerprint — comes with one-click copy: they are for clipboards, not for eyes.

Extended use: the public internet For anything permanently exposed, put a reverse proxy with a real certificate in front and keep serve on loopback: ./agentmux --addr 127.0.0.1:8642, then e.g. caddy reverse-proxy --from mux.example.com --to 127.0.0.1:8642. Or hand serve a real certificate directly with --tls-cert / --tls-key.

Limits: the server build is published for Linux only (amd64 / arm64). To serve from macOS or Windows, use the desktop app's server mode, or build your own with go build -tags headless.

Core Switching & Server Mode#

Behind every AgentMux window there is a core — the part that holds host configuration, SSH connections, keys and all state. By default the window looks at the core on this device, but the two decouple: the window can look at a core on another machine, and this device's core can be opened up for other devices to look at. Those two directions are two adjacent pages in Settings.

Pointing the window at a remote core (Settings → Connection)

  1. Pick Remote server and enter the address of a serve instance, e.g. https://192.168.1.10:8642.
  2. Against self-signed HTTPS a fingerprint card appears: compare it with the server log (or with the other machine's Server mode page) and confirm with “trust and connect”.
  3. Enter that machine's access token once, and the window switches over.

The window is then a screen onto that machine: host configuration, SSH keys, connections, all state live on the remote end, and this device remembers only the address and the fingerprint. Switch back to This device and you see the local data again — the two sides are independent and never synchronise.

  • The recommended shape: one desktop or LAN server runs the core (the headless build, or server mode), and the laptop, phone and tablet all point at it — SSH keys and jump hosts are configured once, on that one machine, and every device sees the same hosts and the same running terminals.
  • You can always get home: when the remote end is unreachable there is no blank window — an error page explains what failed, with a Retry button and a “back to this device” button.
  • The Android app has the same Settings → Connection page: it defaults to the core embedded in the device, and can point at a remote instance instead.

Letting this computer be the server (Settings → Server mode)

The other direction: the desktop app itself can accept connections from other devices, with nothing extra installed:

  1. Settings → Server mode; confirm the listen address — the default :8642 listens on all interfaces, 127.0.0.1:8642 restricts to this machine.
  2. “Encrypt (HTTPS, self-signed certificate)” is checked by default; press Enable.
  3. The page then lists the connection addresses, the access token, and the certificate fingerprint, each with one-click copy — enter the address in the phone app's Settings → Connection, paste the token, compare the fingerprint.

The window and the web are two faces of one core: what the phone shows is exactly the hosts and terminals on your desktop, live in both directions. The switch is remembered and restored on the next start.

Choosing between this and the server build Desktop server mode lives and dies with the window's process — quit the app or shut the machine down and it is gone — and it only announces new versions rather than applying them from the web UI. It is the right tool for handing a running session to your phone for the evening; for anything permanently on, install the headless server.

Tablet & Phone#

Any modern browser opens the full application — an Android tablet, an iPad, a phone. Terminals, agents, the toolkit, file browsing and remote desktop all work; it is not a read-only view.

Getting a server to connect to

Stand one up as described in The Headless Server (one line on a Linux box), or flip on server mode in the desktop app. Either road hands you the same three things: an address, an access token, and a certificate fingerprint.

Opening it on a tablet

  1. Browse to https://host:8642 (with a self-signed certificate the browser asks once on its warning page; a plain-HTTP deployment is http://).
  2. Enter the token once; the browser keeps it from then on.
  3. iPad: Safari's “Share → Add to Home Screen”. Android: Chrome's “Add to Home Screen”. It then runs as a standalone app with no address bar.

Closing the browser stops nothing — exactly like closing the desktop window, because the agents live in remote tmux.

The native Android app

Every release attaches agentmux-android.apk (Android 8.0+ · arm64). It goes one step beyond the route above: it embeds the same core the server build ships, started on the device by a foreground service, with the WebView joining it on 127.0.0.1. SSH runs from the phone or tablet itself and configuration and keys stay on the device — no always-on machine is needed.

  • The foreground service is deliberate: without it Android freezes the process at screen lock and cuts every SSH connection. That is why a persistent notification is shown.
  • The agents live in remote tmux, so they are unaffected even if the system kills the app — reopening it reconnects.
  • Remote mode: the app's Settings → Connection page can point it at a serve instance instead of the embedded core. Against self-signed HTTPS the app fetches the certificate and shows a fingerprint card — compare it with the server log and confirm; from then on this device accepts exactly that certificate.
  • Known limit: against a self-signed, fingerprint-pinned server, the remote desktop viewer is unavailable (Android's WebView does not hand WebSocket certificate errors to the app to adjudicate). Terminals and everything else are unaffected; a real CA certificate lifts the limit.

A layout redone for thumbs

  • Under 768px the side panels become overlay drawers — one at a time, closing when a tab is picked.
  • The status bar's slot holds a bottom navigation bar: tree, command palette, detail panel and settings as labelled thumb-height buttons, with the safe-area inset respected.
  • Dialogs and the command palette stop insisting on desktop margins where there is no room for any.

Orchestrator & Ollama#

The orchestrator is an operations assistant driven by a local model: give it an objective (say, "work out why agent-3 stopped progressing") and it inspects fleet state, retrieves prior context, and proceeds one tool call at a time. It is disabled until you enable it.

Prerequisites

  1. Install Ollama and keep it running.
  2. Pull one chat model and one embedding model, for example:
ollama pull qwen3             # chat model (example — pick for your hardware)
ollama pull nomic-embed-text  # embedding model, used for semantic search

The approval flow

  • Every operation that modifies a host is held for your explicit approval. The approval card shows: the tool, its full arguments, the target host, and the model's stated justification.
  • Destructive operations are confirmed on every host, regardless of its trust level.
  • Tools are a fixed whitelist, each carrying a risk tier fixed at declaration. Execution passes a single gate combining tier × host trust level × the run's trigger.
  • Remote output enters the model marked as data; instruction-shaped text raises a flag on the approval card and in the decision log (prompt-injection defence).
  • Every step of every run is recorded — including proposals refused, rejected, or left unanswered.

Scheduled patrols

The orchestrator can patrol the fleet on a schedule and report stalled agents. Scheduled runs are refused every non-read tool unconditionally — the restriction is not configurable. Patrols can find problems; acting on them always waits for you.

Skills and memory

  • Skills: reusable procedures — the conditions under which one applies, the steps, the tools, the constraints — matched automatically when those conditions recur. Skills proposed by the orchestrator enter a review queue and have no effect until approved.
  • Memory: project facts, stated preferences, and agent activity are indexed for retrieval by wording or by meaning. Embeddings are computed locally; nothing leaves the machine. Credentials matching known patterns are redacted before storage.

Lifecycle Semantics#

Internalise these and you'll never have a "did I just lose my task?" moment:

ActionWhat actually happens
Quitting AgentMuxNothing stops. All agents keep running in tmux on their hosts.
Closing a paneHides the terminal view; the tab and its shell stay attached.
Deleting a workspace / agent recordRemoves the local record only — the tmux session keeps running.
The agent process exitsLeaves a usable shell in the correct directory — the session isn't destroyed; investigate or restart in place.
StopStops the agent process; session and shell remain.
KillThe one control that destroys a running tmux session. It always confirms first, stating what is lost.
Network drop / lid closeAgents unaffected; the terminal reattaches itself to the same pane once the connection is back, scrollback intact.
Ten idle minutesAn SSH connection with nothing holding it closes; it's rebuilt automatically on next use.

Agents that are waiting on a person

An agent asking a question, one that finished with results to review, and one sitting at its prompt with no task all read as “running” in the tree before. The poll now reads each pane and classifies it, raising a sticky mark on the transitions a human needs to see, and taking the mark down when someone actually looks — opens the terminal, answers, or dismisses it.

  • The marks ride on the tree rows and bubble up to collapsed workspaces and projects, so a folded tree still shows where you are needed.
  • They appear on the terminal tabs and on the detail panel as well.

Reconnecting after a drop

A terminal that lost its transport is not over: the tmux session on the far side is still running, the agent inside it is still working, and the only thing that broke was the pipe. So the pipe is rebuilt — same shell id, same scrollback, same pane — backing off from a second to fifteen and giving up after about five minutes, at which point the manual reattach button is still there.

  • A session that ended on its own terms is left alone: an exit status is a decision, not a failure.
  • Two keepalives, because they answer different questions. TCP keepalive stops the boxes in between from forgetting an idle flow; the SSH one proves the far end is still answering, and gives up on a ping after ten seconds.
  • One-shot command terminals are exempt. Dialling back would mean running the command again, and re-running an install because the wifi blinked is a side effect nobody asked for.

Updates & Migration#

Update checks and one-click upgrades

The app checks the release feed shortly after launch and every six hours after. A newer version raises a one-line banner under the title bar: upgrade and restart, release notes, or later.

  • Upgrading downloads the platform's asset with a live progress bar, verifies the published sha256, swaps the running executable (the bundle on macOS; rename-aside on Windows, where a running program cannot be deleted), relaunches, and sweeps up the leftovers on the next start.
  • A failed swap rolls back to the build that was running.
  • A dev build is never overwritten — it updates through git, and the settings dialog says so when asked to check.

Carrying an installation to another machine

Settings can write the whole configuration — hosts, folders, projects, workspaces and agent definitions, with the skill library and the preferences if you want them — into a single file, and open it on the other side.

  • Encryption. The file is sealed with a passphrase rather than with this machine's master key, because that key lives in this computer's keychain and cannot travel: a copy of the database would be unreadable at the other end. Argon2id turns the passphrase into a key and AES-256-GCM seals the contents. The cost parameters have to travel in the clear to be usable at all, so they are authenticated rather than hidden — a header rewritten to something cheap stops the file opening instead of weakening it.
  • SSH passwords and key passphrases travel only when asked for, exist in the clear for exactly as long as it takes to seal them, and are re-sealed under the new machine's own master key on arrival.
  • An import never overwrites. A host at the same address, a project with the same name, a path on the same machine: each is left exactly as it is, and whatever pointed at it in the file is pointed at the copy that was already here. So importing the same file twice adds nothing, and trying an import costs nothing. What cannot be carried is said instead — a key file that is not on this machine, a jump host that did not travel, a session name already taken here.
  • Two things deliberately stay behind. Terminal layout and agent runtime state describe this installation rather than the configuration, and whether the orchestrator may act is decided at each machine — a file arriving from somewhere else is not that decision.

Building from Source#

Go 1.25+ and Node 20+. The frontend builds first (it's embedded in the binary), then Go:

git clone git@github.com:tan-zhuo/AgentMux.git
cd AgentMux
cd frontend && npm install && npm run build && cd ..
go build -o agentmux .
./agentmux

Linux needs the WebKitGTK headers and the gtk3 build tag:

sudo apt-get install -y build-essential pkg-config libgtk-3-dev libwebkit2gtk-4.1-dev
go build -tags gtk3 -o agentmux .

Windows, for a double-clickable GUI binary with no console window:

go build -ldflags "-H windowsgui" -o agentmux.exe .

More detail (testing, cutting a release) in docs/development.md.

Troubleshooting#

macOS says the app "is damaged" or won't open

That's the normal gate for unsigned builds, not corruption. Follow the table in Installation, or fix it in one command: xattr -dr com.apple.quarantine /Applications/AgentMux.app.

Linux fails to start / missing library

Almost always the WebKitGTK runtime. Debian/Ubuntu: sudo apt install libwebkit2gtk-4.1-0; Fedora: sudo dnf install webkit2gtk4.1.

Windows: no window appears at all

GUI builds have no console for errors. Check startup-error.log in the data directory (%APPDATA%\AgentMux) — the actual failure reason is written there.

"Host key mismatch" when connecting

The host's key differs from the one pinned on first connection. Establish why first: a reinstalled host or a re-assigned IP is normal — delete the host record and re-add it. If nothing should have changed, treat it as a possible man-in-the-middle and verify the fingerprint out of band.

Status bar reports the keychain is unavailable

The encryption master key normally lives in the OS keychain (Keychain / Credential Manager / Secret Service). Where no keychain is available (common on minimal Linux desktops), AgentMux falls back to a 0600 file and says so in the status bar. Nothing breaks; to restore keychain storage on Linux, install and enable gnome-keyring or another Secret Service implementation.

The target host has no tmux

Open that host's install panel — tmux is on the list, and AgentMux installs it with the right package manager.

Orchestrator / semantic search unavailable

Check that Ollama is running (ollama list shows your models) and that both a chat model and an embedding model are pulled. Without Ollama these two features stay disabled; everything else is unaffected.

Where is my data?

All state is one SQLite file in the application data directory (%APPDATA%\AgentMux on Windows). Back up that directory to back up everything; delete it for a full reset. Credentials are stored AES-256-GCM-encrypted, with the key in the OS keychain.

The tablet cannot reach host:8642

  • Check the scheme: the install script enables TLS by default, so the address is https://; only a hand-started server without --tls is http://. A self-signed certificate asks once on the browser's warning page.
  • Check the listen address is not bound to 127.0.0.1 — that is unreachable from the network (the default :8642 listens on all interfaces).
  • Check the server's firewall allows 8642 (and the security group, on a cloud host).
  • Check the tablet is on the same network, or on the same VPN.

Switched to a remote core and all I get is an error page

The error page is itself part of the design: a serve instance that is down, a VPN that is not connected, a mistyped address all land on it, and it names what failed. Press Retry, or “back to this device” and then check systemctl --user status agentmux on the server. Switching always has a way home — you cannot be stranded in remote mode.

Lost the serve-mode access token

The token is kept as serve-token in the data directory, and printed in the log on first start. To change it, delete that file and restart, or set AGENTMUX_TOKEN before starting.

The Android app will not install or upgrade

Allow installation from unknown sources first. A signature conflict means the installed build carries a debug signature (what the repository produces when no signing key is configured) — uninstall the old app and install the new one. The agents live in remote tmux and are unaffected.

Getting Help#

  • File a GitHub issue — including platform, version, and startup-error.log (if any) speeds things up considerably.
  • Orchestrator internals (the tool gate, trust levels, memory and skill layers) are documented in the orchestrator design doc.
  • Author's blog: tanzhuo.xyz
Didn't find your answer? Open an issue — usually answered same-day. ← Back to home