docs: comprehensive README rewrite + plans archive note

README now documents all features, 14 config keys, full CLI reference,
keyboard shortcuts, platform support, and project structure. Previous
README covered ~40% of actual functionality. Added docs/plans/README.md
noting these are historical ADRs from the initial build.

Added 9 new README tests verifying all settings keys are documented,
clipboard features, keyboard shortcuts, auth modes, platform support,
ANSI previews, hover preview, and view modes.
This commit is contained in:
Brian Krabach
2026-04-01 10:57:17 -07:00
parent 2001b3cba3
commit 66f58a6f4b
3 changed files with 242 additions and 83 deletions
+163 -83
View File
@@ -1,6 +1,6 @@
# muxplex
**Web-based tmux session dashboard — access and manage all your tmux sessions from any browser or mobile device.**
**Web-based tmux session dashboard — access, monitor, and manage all your tmux sessions from any browser on any device.**
![muxplex dashboard](assets/branding/og/og-dark.png)
@@ -8,12 +8,51 @@
## Features
- **Live session grid** — thumbnail snapshots of every running tmux session, auto-refreshed
- **Full interactive terminal** — click any session to open a real terminal (powered by ttyd + xterm.js)
- **Collapsible session sidebar** — quick-switch between sessions without leaving the terminal view
- **Bell & activity notifications** — visual alerts when any session rings a bell or has new output
- **Mobile-friendly responsive layout** — works on phones and tablets; PWA-capable for home-screen install
- **Works over Tailscale / private network** — serve to any device on your network without exposing to the internet
### 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, amber favicon dot for browser tab visibility
- **Session creation** — `+` button with 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, Ctrl+Shift+V 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
- **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`
### 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_PASSWORD` env 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 check
- `muxplex upgrade` — smart version check + auto-update + service restart
- `muxplex config` — CLI settings management
---
@@ -28,7 +67,7 @@
- Ubuntu/WSL: `sudo apt install ttyd` or `sudo snap install ttyd`
- Other: https://github.com/tsl0922/ttyd#installation
> **Tip:** muxplex checks for `tmux` and `ttyd` at startup and prints install instructions if either is missing.
> **Tip:** Run `muxplex doctor` to check all dependencies and system status.
---
@@ -48,10 +87,9 @@ Then open **http://localhost:8088** in your browser.
## Install Permanently
Install muxplex as a persistent CLI tool using `uv tool`:
```bash
uv tool install git+https://github.com/bkrabach/muxplex
muxplex doctor # verify dependencies
```
Then run it any time with:
@@ -66,49 +104,43 @@ muxplex
```bash
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.
```bash
# Open in browser
open http://localhost:8088
```
To stop and remove:
```bash
muxplex service uninstall
```
> **Note:** All service commands use the `muxplex service` subcommand — see [Service management](#service-management) below.
---
## Usage
## CLI Reference
```bash
muxplex [OPTIONS]
muxplex serve [OPTIONS] # explicit form
```
All serve options read from `~/.config/muxplex/settings.json` by default. CLI flags override for that run only.
| Option | settings.json key | Default | Description |
|---|---|---|---|
| `--host HOST` | `host` | `127.0.0.1` | Interface to bind (`0.0.0.0` for network access) |
| `--port PORT` | `port` | `8088` | Port to listen on |
| `--auth MODE` | `auth` | `pam` | Auth method: `pam` or `password` |
| `--session-ttl SEC` | `session_ttl` | `604800` | Session TTL in seconds (7 days; 0 = browser session) |
### Other commands
| Command | Description |
|---|---|
| `muxplex doctor` | Check dependencies and system status |
| `muxplex upgrade` | Upgrade to latest version and restart service |
| `muxplex show-password` | Show the current muxplex password |
| `muxplex reset-secret` | Regenerate signing secret (invalidates sessions) |
| `muxplex config` | Show all settings with current values |
| `muxplex config list` | Show all settings with current values |
| `muxplex config get <key>` | Show one setting |
| `muxplex config set <key> <value>` | Set a setting (auto-detects type) |
| `muxplex config reset [key]` | Reset one or all settings to defaults |
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
```
### Service management
@@ -122,11 +154,10 @@ 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 and restart:
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:
```bash
# Edit settings to bind to all interfaces
# (or use the Settings UI in the browser)
muxplex config set host 0.0.0.0
muxplex service restart
```
@@ -145,6 +176,89 @@ muxplex serve --host 0.0.0.0
---
## 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 |
| `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 |
| `remote_instances` | `[]` | Remote muxplex instances to aggregate |
| `multi_device_enabled` | `false` | Enable multi-instance federation |
**Priority:** CLI flags > `settings.json` > defaults.
---
## Keyboard Shortcuts
| Shortcut | Action |
|---|---|
| Ctrl+Shift+C | Copy terminal selection to system clipboard |
| Ctrl+Shift+V | Paste from system clipboard into terminal |
| `,` (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
@@ -169,7 +283,7 @@ python -m muxplex
```bash
# Python tests (pytest)
pytest
python -m pytest muxplex/tests/ --ignore=muxplex/tests/test_integration.py
# JavaScript tests (node:test)
node --test muxplex/frontend/tests/test_terminal.mjs
@@ -178,46 +292,6 @@ node --test muxplex/frontend/tests/test_app.mjs
---
## Architecture
```
muxplex/
├── pyproject.toml # Package metadata, entry points, dependencies
├── README.md # This file
├── scripts/ # Utility scripts (asset generation, etc.)
│ └── render-brand-assets.py
├── assets/
│ └── branding/ # Brand design system and generated assets
│ ├── DESIGN-SYSTEM.md
│ ├── tokens.json / tokens.css
│ ├── svg/ # Source SVG files
│ ├── og/ # Open Graph images (og-dark.png, og-light.png)
│ ├── icons/ # App icons
│ ├── favicons/ # Favicon variants
│ ├── pwa/ # PWA manifest icons
│ ├── lockup/ # Wordmark + icon lockup
│ └── wordmark/ # Text-only wordmark
└── muxplex/ # Python package
├── __init__.py
├── __main__.py # `python -m muxplex` entry point
├── cli.py # CLI entry point and subcommand dispatch
├── main.py # FastAPI app: session API, bell hooks, WebSocket proxy to ttyd, static frontend
├── sessions.py # tmux session discovery and snapshot capture
├── bells.py # Bell/activity notification tracking
├── ttyd.py # ttyd process lifecycle management (spawn, kill, PID tracking)
├── state.py # Shared in-process state (sessions, bells, ttyd)
├── frontend/ # Static frontend assets (served as package data)
│ ├── index.html
│ ├── app.js
│ ├── terminal.js # xterm.js + WebSocket terminal init
│ ├── style.css
│ ├── manifest.json # PWA manifest
│ └── tests/ # JavaScript unit tests
└── tests/ # Python tests (pytest)
```
---
## Brand Assets
Design language, color tokens, and brand assets live in `assets/branding/`. See [`assets/branding/DESIGN-SYSTEM.md`](assets/branding/DESIGN-SYSTEM.md) for the full design reference.
@@ -227,3 +301,9 @@ To regenerate PNG/favicon assets from SVG sources:
```bash
python3 scripts/render-brand-assets.py
```
---
## License
MIT
+5
View File
@@ -0,0 +1,5 @@
# Implementation Plans (Historical)
These are historical design and implementation plan documents from the initial build of muxplex. All plans have been fully implemented. They are retained as architectural decision records (ADRs) and build logs.
See the main [README.md](../../README.md) for current documentation.
+74
View File
@@ -43,3 +43,77 @@ def test_readme_shows_restart_workflow():
assert "muxplex service restart" in README, (
"README must include 'muxplex service restart' in the example"
)
# ── Comprehensive documentation tests ─────────────────────────────────────
def test_readme_documents_all_settings_keys():
"""README must document every key from DEFAULT_SETTINGS."""
from muxplex.settings import DEFAULT_SETTINGS
for key in DEFAULT_SETTINGS:
assert f"`{key}`" in README, f"README must document setting key '{key}'"
def test_readme_has_keyboard_shortcuts_section():
"""README must have a keyboard shortcuts section."""
assert "Ctrl+Shift+C" in README, "README must document Ctrl+Shift+C"
assert "Ctrl+Shift+V" in README, "README must document Ctrl+Shift+V"
def test_readme_documents_clipboard_features():
"""README must mention clipboard and mouse select features."""
assert "clipboard" in README.lower(), "README must mention clipboard"
assert "mouse" in README.lower() or "select" in README.lower(), (
"README must mention mouse selection"
)
def test_readme_documents_all_cli_commands():
"""README must list all top-level CLI commands."""
commands = [
"muxplex doctor",
"muxplex upgrade",
"muxplex show-password",
"muxplex reset-secret",
"muxplex config",
]
for cmd in commands:
assert cmd in README, f"README must mention CLI command '{cmd}'"
def test_readme_has_platform_support_section():
"""README must document platform support."""
assert "systemd" in README, "README must mention systemd"
assert "launchd" in README, "README must mention launchd"
def test_readme_documents_auth_modes():
"""README must document both PAM and password auth."""
assert "PAM" in README, "README must mention PAM auth"
assert "password" in README.lower(), "README must mention password auth"
assert "localhost" in README.lower() or "127.0.0.1" in README, (
"README must mention localhost bypass"
)
def test_readme_documents_view_modes():
"""README must document Auto and Fit view modes."""
readme_lower = README.lower()
assert "view mode" in readme_lower or "view modes" in readme_lower, (
"README must mention view modes"
)
def test_readme_documents_ansi_color_previews():
"""README must document ANSI color previews in tiles."""
assert "ANSI" in README, "README must mention ANSI color previews"
def test_readme_documents_hover_preview():
"""README must document hover preview feature."""
readme_lower = README.lower()
assert "hover" in readme_lower and "preview" in readme_lower, (
"README must mention hover preview"
)