Fix 1: Wire rename click handler in Manage View panel - openManageViewPanel() now adds click handler on #manage-view-name - Replaces h2 with inline manage-view-panel__name-input on click - On Enter: validates (non-empty, max 30, not reserved, not duplicate) then PATCHes /api/settings, updates _activeView, re-renders panel - On Escape / blur: reverts to text display - Add CSS for .manage-view-panel__delete-btn and .manage-view-panel__confirm-text Fix 2: Add delete button in Manage View panel header - Adds trash button (id=manage-view-delete-btn) next to view name - Clicking shows inline 'Delete this view? [Yes] [No]' confirmation - On confirm: PATCH /api/settings to remove view, close panel, switch to 'all' view, show toast confirming deletion Fix 3: Remove rename affordance from settings tab - Remove cursor:pointer from .views-settings-name - Remove .views-settings-name:hover hover/underline styles - Remove .views-settings-rename-input CSS class (dead code) Fix 4: Merge Add to View + Remove from View into unified Views submenu - Remove 'remove-from-view' item from FLYOUT_MENU_MAP 'user' entry - _openFlyoutSubmenu now shows ALL user views (no longer skips the current active view) — unified toggle-checkmark submenu - Submenu already stays open during toggling (existing behavior) - Update old test to match new correct behavior Fix 5: Fix checkbox re-render layout thrash in Manage View panel - renderManageViewList onChange .then() no longer calls renderManageViewList() - Instead updates summaryEl.textContent in-place with current counts - Prevents position jumps when toggling checkboxes in long lists Fix 6: Clean up dead CSS - Remove .add-sessions-tile + __icon + __label (old affordance tile) - Remove .manage-view-panel__close (HTML uses __close-btn) - Remove .manage-view-panel__title (HTML uses __name) - Update CSS comment 'Add Sessions Panel' -> 'Manage View Panel' - Keep .manage-view-panel__name-input (now used by Fix 1 rename input)
muxplex
Web-based tmux session dashboard — access, monitor, and manage all your tmux sessions from any browser on any device.
Features
Dashboard
- Live session grid — preview tiles with ANSI-colored terminal snapshots, auto-refreshed
- Two view modes — Auto (scrollable grid) and Fit (all sessions fill the viewport)
- Hover preview — full-size overlay of session content on tile hover
- Activity indicators — bell notification badges on tiles; amber favicon dot +
(N)count in browser tab title when sessions have unseen activity - Session creation —
+button with device selector dropdown when multi-device is enabled; custom command template support - Session deletion —
×button with custom command template support - Mobile-friendly — responsive layout, PWA-capable for home-screen install
Terminal
- Full interactive terminal — powered by xterm.js + ttyd
- Native clipboard — Ctrl+Shift+C to copy, Cmd+V (macOS) / Ctrl+Shift+V (Linux) to paste
- Mouse select auto-copy — selecting text copies to system clipboard on release
- OSC 52 tmux clipboard bridge — tmux copy mode selections go to system clipboard
- Search — Ctrl+F opens a search bar to find text in terminal scrollback (xterm-addon-search)
- Clickable URLs — Ctrl+Click (Cmd+Click on macOS) opens URLs in terminal output in a new tab (xterm-addon-web-links)
- Inline image rendering — Sixel and iTerm2 graphic protocols for tools like yazi file manager (xterm-addon-image)
- Sidebar session switcher — quick-switch between sessions with live previews
Settings
- In-browser settings panel — gear icon or
,shortcut - Display — font size, grid columns, hover delay, view mode, device badges, activity indicator
- Sessions — default session, sort order, hidden sessions, auto-open, bell sound, notifications
- Commands — custom create/delete session templates
- Multi-Device — remote instance federation
- CLI —
muxplex config list/get/set/reset
Multi-Device
- Remote session aggregation — federate multiple muxplex instances into a unified dashboard view
- Device selector in new session —
+button shows a device dropdown when multi-device is enabled; create sessions on any connected instance directly from the dashboard - Remote bell-clear — opening a session on a remote device automatically clears its activity notification via federation API (
POST /api/bell/clear) - Unique session keys — sessions identified by
remoteId:nameacross devices, preventing bell-state collisions for identically-named sessions on different machines
Service Management
muxplex service install/start/stop/restart/status/logs/uninstall- Platform-aware — systemd user service on Linux/WSL, launchd agent on macOS
- Config-driven — service reads all options from
~/.config/muxplex/settings.json(no flags in the service file)
Authentication
- PAM authentication — Linux/macOS system credentials
- Password mode — auto-generated or set via
MUXPLEX_PASSWORDenv var - Localhost bypass — no auth needed on 127.0.0.1
- Secure session cookies — signed with configurable TTL
Developer Tools
muxplex doctor— dependency + config diagnostics with update checkmuxplex upgrade— smart version check + auto-update + service restartmuxplex config— CLI settings management
HTTPS / TLS
muxplex setup-tls— auto-detect and set up TLS certificates- Tailscale — real Let's Encrypt certs via
tailscale cert(recommended) - mkcert — locally-trusted certs, zero browser warnings
- Self-signed — fallback for immediate HTTPS (browser shows warning)
- Required for browser clipboard API on non-localhost
Prerequisites
- Python 3.11+ — installed via
uvor system Python - tmux — terminal multiplexer
- macOS:
brew install tmux - Ubuntu/WSL:
sudo apt install tmux
- macOS:
- ttyd — terminal sharing over HTTP (required for interactive terminal access)
- macOS:
brew install ttyd - Ubuntu/WSL:
sudo apt install ttydorsudo snap install ttyd - Other: https://github.com/tsl0922/ttyd#installation
- macOS:
Tip: Run
muxplex doctorto check all dependencies and system status.
Quick Start (uvx — no install)
Run muxplex directly without installing anything permanently:
uvx --from git+https://github.com/bkrabach/muxplex muxplex
Then open http://localhost:8088 in your browser.
Note:
uvxis part of uv. Install uv withcurl -LsSf https://astral.sh/uv/install.sh | sh.
Install Permanently
uv tool install git+https://github.com/bkrabach/muxplex
muxplex doctor # verify dependencies
Then run it any time with:
muxplex
Install as a Service
muxplex service install
# → prompts to set host to 0.0.0.0 for network access
The service starts automatically on login (macOS) or at boot (Linux) and restarts on failure.
# Open in browser
open http://localhost:8088
To stop and remove:
muxplex service uninstall
CLI Reference
muxplex Start server (default)
muxplex serve [flags] Start with CLI flag overrides
muxplex service install Install + enable + start as OS service
muxplex service uninstall Stop + disable + remove
muxplex service start|stop|restart Manage running service
muxplex service status Show service status
muxplex service logs Tail service logs
muxplex config Show all settings
muxplex config get <key> Show one setting
muxplex config set <key> <value> Set a setting
muxplex config reset [key] Reset one or all to defaults
muxplex upgrade [--force] Smart update with version check
muxplex doctor Check dependencies + config
muxplex show-password Show current auth password
muxplex reset-secret Regenerate signing secret
muxplex setup-tls [--method auto] Set up TLS certs (Tailscale/mkcert/self-signed)
muxplex setup-tls --status Show current TLS configuration
Service management
muxplex service install # Write service file + enable + start
muxplex service uninstall # Stop + disable + remove service file
muxplex service start # Start the service
muxplex service stop # Stop the service
muxplex service restart # Stop + start
muxplex service status # Show running/stopped + PID
muxplex service logs # Tail service logs
The service runs muxplex serve with no flags — it reads all options from ~/.config/muxplex/settings.json. To change host/port, edit the config (or use the Settings UI in the browser) and restart:
muxplex config set host 0.0.0.0
muxplex service restart
Examples
# Start with defaults from settings.json
muxplex
# Override port for this run only
muxplex --port 9000
# Override host for this run only
muxplex serve --host 0.0.0.0
HTTPS / TLS setup
# Auto-detect the best TLS method and set up certificates
muxplex setup-tls
# Use a specific TLS method
muxplex setup-tls --method tailscale
muxplex setup-tls --method mkcert
muxplex setup-tls --method selfsigned
# Show current TLS status and configuration
muxplex setup-tls --status
# Override TLS cert/key for a single run (without saving to config)
muxplex serve --tls-cert /path/cert.pem --tls-key /path/key.pem
# Check TLS configuration and dependencies
muxplex doctor
Auto-detection priority: Tailscale (if tailscale is installed and a cert is available) → mkcert (if mkcert is installed) → self-signed (always available as a fallback). Use --method to override.
Note: Tailscale certs have a 90-day expiry. Run
muxplex setup-tls --method tailscaleto renew when needed.
Configuration
All settings are stored in ~/.config/muxplex/settings.json.
| Key | Default | Description |
|---|---|---|
host |
127.0.0.1 |
Bind address (set to 0.0.0.0 for network access) |
port |
8088 |
Server port |
auth |
pam |
Authentication mode: pam or password |
session_ttl |
604800 |
Session cookie TTL in seconds (7 days; 0 = browser session) |
default_session |
null |
Session to auto-open on load |
sort_order |
manual |
Session ordering: manual, alphabetical, recent |
hidden_sessions |
[] |
Sessions hidden from the dashboard |
views |
[] |
Named session views for grouping and filtering sessions |
window_size_largest |
false |
Auto-set tmux window-size largest on connect |
auto_open_created |
true |
Auto-open newly created sessions |
new_session_template |
tmux new-session -d -s {name} |
Command template for creating sessions |
delete_session_template |
tmux kill-session -t {name} |
Command template for deleting sessions |
device_name |
"" (hostname) |
Display name for this device |
federation_key |
"" |
Server-to-server authentication key for federation |
remote_instances |
[] |
Remote muxplex instances to aggregate |
multi_device_enabled |
false |
Enable multi-instance federation |
tls_cert |
"" |
Path to TLS certificate file (empty = HTTP) |
tls_key |
"" |
Path to TLS private key file (empty = HTTP) |
fontSize |
14 |
Terminal and tile preview font size (px) |
hoverPreviewDelay |
1500 |
Hover preview popup delay (ms) |
gridColumns |
"auto" |
Number of grid columns ("auto" or integer) |
bellSound |
false |
Play audio sound on terminal bell |
viewMode |
"auto" |
Grid tile sizing: auto or fit |
showDeviceBadges |
true |
Show device name labels on tiles |
showHoverPreview |
true |
Show hover preview popover on tile hover |
activityIndicator |
"both" |
Activity style: none, glow, dot, both |
gridViewMode |
"flat" |
Multi-device grid layout: flat, grouped, filtered |
sidebarOpen |
null |
Sidebar state: true, false, or null (auto-detect from screen width) |
settings_updated_at |
0.0 |
Unix timestamp of last settings write (used for federation sync) |
Priority: CLI flags > settings.json > defaults.
Keyboard Shortcuts
| Shortcut | Action |
|---|---|
| Ctrl+Shift+C | Copy terminal selection to system clipboard |
| Cmd+V / Ctrl+Shift+V | Paste from system clipboard (native browser paste) |
| Ctrl+F | Open terminal search bar |
| Enter / Shift+Enter | Next / previous search match |
| Ctrl+Click (Cmd+Click) | Open URL in new tab |
, (comma) |
Open settings |
| Escape | Close settings / return to dashboard |
Mouse select in the terminal auto-copies to the system clipboard on release.
Platform Support
| Platform | Service | Auth |
|---|---|---|
| Linux (Ubuntu/Debian) | systemd user service | PAM |
| macOS | launchd agent | PAM |
| WSL | systemd user service | PAM |
Project Structure
muxplex/
├── muxplex/
│ ├── __init__.py
│ ├── __main__.py # python -m muxplex entry
│ ├── cli.py # CLI entry point and subcommand dispatch
│ ├── main.py # FastAPI app, routes, WebSocket proxy
│ ├── auth.py # PAM/password auth middleware
│ ├── sessions.py # tmux session enumeration + snapshots
│ ├── bells.py # Bell flag detection + clear rules
│ ├── state.py # Persistent state (JSON)
│ ├── settings.py # User settings management
│ ├── service.py # Service install/start/stop (systemd + launchd)
│ ├── ttyd.py # ttyd process lifecycle
│ ├── frontend/
│ │ ├── index.html # Main SPA
│ │ ├── login.html # Login page
│ │ ├── app.js # Dashboard, sidebar, settings, previews
│ │ ├── terminal.js # xterm.js terminal + clipboard
│ │ ├── style.css # All styles (dark theme)
│ │ ├── manifest.json # PWA manifest
│ │ ├── wordmark-on-dark.svg
│ │ └── tests/ # JavaScript unit tests
│ └── tests/ # Python tests (pytest)
├── assets/branding/ # Logos, icons, design system
├── docs/plans/ # Historical design + implementation plans
├── scripts/ # Utility scripts (asset generation)
├── pyproject.toml
└── README.md
Development
Setup
git clone https://github.com/bkrabach/muxplex
cd muxplex
# Install with dev dependencies
uv pip install -e ".[dev]"
Run the server
muxplex
# or directly:
python -m muxplex
Run tests
# Python tests (pytest)
python -m pytest muxplex/tests/ --ignore=muxplex/tests/test_integration.py
# JavaScript tests (node:test)
node --test muxplex/frontend/tests/test_terminal.mjs
node --test muxplex/frontend/tests/test_app.mjs
Brand Assets
Design language, color tokens, and brand assets live in assets/branding/. See assets/branding/DESIGN-SYSTEM.md for the full design reference.
To regenerate PNG/favicon assets from SVG sources:
python3 scripts/render-brand-assets.py
License
MIT
