muxplex 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- muxplex-0.1.0/.github/workflows/ci.yml +35 -0
- muxplex-0.1.0/.github/workflows/publish.yml +27 -0
- muxplex-0.1.0/.gitignore +30 -0
- muxplex-0.1.0/PKG-INFO +396 -0
- muxplex-0.1.0/README.md +360 -0
- muxplex-0.1.0/assets/branding/DESIGN-SYSTEM.md +857 -0
- muxplex-0.1.0/assets/branding/README.md +40 -0
- muxplex-0.1.0/assets/branding/favicons/apple-touch-icon.png +0 -0
- muxplex-0.1.0/assets/branding/favicons/favicon-16.png +0 -0
- muxplex-0.1.0/assets/branding/favicons/favicon-32.png +0 -0
- muxplex-0.1.0/assets/branding/favicons/favicon-48.png +0 -0
- muxplex-0.1.0/assets/branding/favicons/favicon.ico +0 -0
- muxplex-0.1.0/assets/branding/icons/muxplex-icon-1024.png +0 -0
- muxplex-0.1.0/assets/branding/icons/muxplex-icon-128.png +0 -0
- muxplex-0.1.0/assets/branding/icons/muxplex-icon-16.png +0 -0
- muxplex-0.1.0/assets/branding/icons/muxplex-icon-192.png +0 -0
- muxplex-0.1.0/assets/branding/icons/muxplex-icon-22.png +0 -0
- muxplex-0.1.0/assets/branding/icons/muxplex-icon-24.png +0 -0
- muxplex-0.1.0/assets/branding/icons/muxplex-icon-256.png +0 -0
- muxplex-0.1.0/assets/branding/icons/muxplex-icon-32.png +0 -0
- muxplex-0.1.0/assets/branding/icons/muxplex-icon-48.png +0 -0
- muxplex-0.1.0/assets/branding/icons/muxplex-icon-512.png +0 -0
- muxplex-0.1.0/assets/branding/icons/muxplex-icon-64.png +0 -0
- muxplex-0.1.0/assets/branding/lockup/lockup-on-dark-32.png +0 -0
- muxplex-0.1.0/assets/branding/lockup/lockup-on-dark-64.png +0 -0
- muxplex-0.1.0/assets/branding/lockup/lockup-on-light-32.png +0 -0
- muxplex-0.1.0/assets/branding/lockup/lockup-on-light-64.png +0 -0
- muxplex-0.1.0/assets/branding/og/og-dark.png +0 -0
- muxplex-0.1.0/assets/branding/og/og-light.png +0 -0
- muxplex-0.1.0/assets/branding/pwa/pwa-192.png +0 -0
- muxplex-0.1.0/assets/branding/pwa/pwa-512.png +0 -0
- muxplex-0.1.0/assets/branding/svg/icon/muxplex-icon-dark.svg +18 -0
- muxplex-0.1.0/assets/branding/svg/icon/muxplex-icon-light.svg +18 -0
- muxplex-0.1.0/assets/branding/svg/lockup/lockup-on-dark.svg +20 -0
- muxplex-0.1.0/assets/branding/svg/lockup/lockup-on-light.svg +21 -0
- muxplex-0.1.0/assets/branding/svg/wordmark/wordmark-on-dark.svg +11 -0
- muxplex-0.1.0/assets/branding/svg/wordmark/wordmark-on-light.svg +11 -0
- muxplex-0.1.0/assets/branding/tokens.css +355 -0
- muxplex-0.1.0/assets/branding/tokens.json +214 -0
- muxplex-0.1.0/assets/branding/wordmark/wordmark-on-dark-32.png +0 -0
- muxplex-0.1.0/assets/branding/wordmark/wordmark-on-dark-64.png +0 -0
- muxplex-0.1.0/assets/branding/wordmark/wordmark-on-light-32.png +0 -0
- muxplex-0.1.0/assets/branding/wordmark/wordmark-on-light-64.png +0 -0
- muxplex-0.1.0/docs/how-we-built-the-muxplex-brand.md +237 -0
- muxplex-0.1.0/docs/plans/2026-03-26-web-tmux-dashboard-design.md +318 -0
- muxplex-0.1.0/docs/plans/2026-03-26-web-tmux-phase1-backend.md +3489 -0
- muxplex-0.1.0/docs/plans/2026-03-26-web-tmux-phase2a-frontend-static.md +1717 -0
- muxplex-0.1.0/docs/plans/2026-03-26-web-tmux-phase2b-javascript.md +1909 -0
- muxplex-0.1.0/docs/plans/2026-03-27-session-sidebar-design.md +139 -0
- muxplex-0.1.0/docs/plans/2026-03-27-session-sidebar-implementation.md +1414 -0
- muxplex-0.1.0/docs/plans/2026-03-28-auth-design.md +254 -0
- muxplex-0.1.0/docs/plans/2026-03-28-auth-phase1-infrastructure.md +1074 -0
- muxplex-0.1.0/docs/plans/2026-03-28-auth-phase2-ui-cli.md +1066 -0
- muxplex-0.1.0/docs/plans/2026-03-28-packaging-for-distribution.md +804 -0
- muxplex-0.1.0/docs/plans/2026-03-29-settings-design.md +211 -0
- muxplex-0.1.0/docs/plans/2026-03-29-settings-phase1.md +1395 -0
- muxplex-0.1.0/docs/plans/2026-03-29-settings-phase2.md +1110 -0
- muxplex-0.1.0/docs/plans/2026-03-30-multi-device-federation-design.md +270 -0
- muxplex-0.1.0/docs/plans/2026-03-30-multi-device-federation-phase1.md +1067 -0
- muxplex-0.1.0/docs/plans/2026-03-30-multi-device-federation-phase2.md +2279 -0
- muxplex-0.1.0/docs/plans/2026-03-30-multi-device-federation-phase3.md +1321 -0
- muxplex-0.1.0/docs/plans/2026-03-31-cli-phase1-config-serve.md +815 -0
- muxplex-0.1.0/docs/plans/2026-03-31-cli-phase2-service-commands.md +1095 -0
- muxplex-0.1.0/docs/plans/2026-03-31-cli-service-refactor-design.md +392 -0
- muxplex-0.1.0/docs/plans/2026-04-03-tls-phase1-foundation.md +1246 -0
- muxplex-0.1.0/docs/plans/2026-04-03-tls-phase2-autodetect.md +1231 -0
- muxplex-0.1.0/docs/plans/2026-04-03-tls-setup-design.md +203 -0
- muxplex-0.1.0/docs/plans/2026-04-04-device-selector.md +751 -0
- muxplex-0.1.0/docs/plans/2026-04-04-tls-nudge-design.md +67 -0
- muxplex-0.1.0/docs/plans/README.md +5 -0
- muxplex-0.1.0/docs/screenshots/settings-commands.png +0 -0
- muxplex-0.1.0/docs/screenshots/settings-display.png +0 -0
- muxplex-0.1.0/docs/screenshots/settings-multidevice.png +0 -0
- muxplex-0.1.0/docs/screenshots/settings-sessions.png +0 -0
- muxplex-0.1.0/muxplex/__init__.py +0 -0
- muxplex-0.1.0/muxplex/__main__.py +5 -0
- muxplex-0.1.0/muxplex/auth.py +232 -0
- muxplex-0.1.0/muxplex/bells.py +177 -0
- muxplex-0.1.0/muxplex/cli.py +1067 -0
- muxplex-0.1.0/muxplex/frontend/app.js +2556 -0
- muxplex-0.1.0/muxplex/frontend/apple-touch-icon.png +0 -0
- muxplex-0.1.0/muxplex/frontend/favicon-32.png +0 -0
- muxplex-0.1.0/muxplex/frontend/favicon.ico +0 -0
- muxplex-0.1.0/muxplex/frontend/index.html +251 -0
- muxplex-0.1.0/muxplex/frontend/login.html +192 -0
- muxplex-0.1.0/muxplex/frontend/manifest.json +15 -0
- muxplex-0.1.0/muxplex/frontend/pwa-192.png +0 -0
- muxplex-0.1.0/muxplex/frontend/pwa-512.png +0 -0
- muxplex-0.1.0/muxplex/frontend/style.css +1862 -0
- muxplex-0.1.0/muxplex/frontend/terminal.js +605 -0
- muxplex-0.1.0/muxplex/frontend/tests/test_app.mjs +4301 -0
- muxplex-0.1.0/muxplex/frontend/tests/test_terminal.mjs +994 -0
- muxplex-0.1.0/muxplex/frontend/vendor/addon-image.js +3 -0
- muxplex-0.1.0/muxplex/frontend/vendor/xterm-addon-fit.js +2 -0
- muxplex-0.1.0/muxplex/frontend/vendor/xterm-addon-search.js +2 -0
- muxplex-0.1.0/muxplex/frontend/vendor/xterm-addon-web-links.js +2 -0
- muxplex-0.1.0/muxplex/frontend/vendor/xterm.css +209 -0
- muxplex-0.1.0/muxplex/frontend/vendor/xterm.js +2 -0
- muxplex-0.1.0/muxplex/frontend/wordmark-on-dark.svg +11 -0
- muxplex-0.1.0/muxplex/main.py +1139 -0
- muxplex-0.1.0/muxplex/service.py +291 -0
- muxplex-0.1.0/muxplex/sessions.py +140 -0
- muxplex-0.1.0/muxplex/settings.py +121 -0
- muxplex-0.1.0/muxplex/state.py +184 -0
- muxplex-0.1.0/muxplex/tests/__init__.py +0 -0
- muxplex-0.1.0/muxplex/tests/test_api.py +2600 -0
- muxplex-0.1.0/muxplex/tests/test_auth.py +527 -0
- muxplex-0.1.0/muxplex/tests/test_bells.py +318 -0
- muxplex-0.1.0/muxplex/tests/test_cli.py +2140 -0
- muxplex-0.1.0/muxplex/tests/test_frontend_css.py +2138 -0
- muxplex-0.1.0/muxplex/tests/test_frontend_html.py +1421 -0
- muxplex-0.1.0/muxplex/tests/test_frontend_js.py +2585 -0
- muxplex-0.1.0/muxplex/tests/test_integration.py +213 -0
- muxplex-0.1.0/muxplex/tests/test_readme.py +274 -0
- muxplex-0.1.0/muxplex/tests/test_service.py +665 -0
- muxplex-0.1.0/muxplex/tests/test_sessions.py +262 -0
- muxplex-0.1.0/muxplex/tests/test_settings.py +731 -0
- muxplex-0.1.0/muxplex/tests/test_state.py +311 -0
- muxplex-0.1.0/muxplex/tests/test_tls.py +577 -0
- muxplex-0.1.0/muxplex/tests/test_ttyd.py +326 -0
- muxplex-0.1.0/muxplex/tests/test_ws_proxy.py +444 -0
- muxplex-0.1.0/muxplex/tls.py +380 -0
- muxplex-0.1.0/muxplex/ttyd.py +224 -0
- muxplex-0.1.0/pyproject.toml +68 -0
- muxplex-0.1.0/pyrightconfig.json +5 -0
- muxplex-0.1.0/scripts/render-brand-assets.py +438 -0
- muxplex-0.1.0/scripts/spike_bell_flag.py +80 -0
- muxplex-0.1.0/uv.lock +912 -0
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
pull_request:
|
|
7
|
+
branches: [main]
|
|
8
|
+
|
|
9
|
+
permissions:
|
|
10
|
+
contents: read
|
|
11
|
+
|
|
12
|
+
jobs:
|
|
13
|
+
test:
|
|
14
|
+
runs-on: ubuntu-latest
|
|
15
|
+
timeout-minutes: 15
|
|
16
|
+
strategy:
|
|
17
|
+
fail-fast: false
|
|
18
|
+
matrix:
|
|
19
|
+
python-version: ["3.11", "3.12", "3.13"]
|
|
20
|
+
steps:
|
|
21
|
+
- uses: actions/checkout@v4 # checks out muxplex repo
|
|
22
|
+
|
|
23
|
+
- name: Install uv
|
|
24
|
+
uses: astral-sh/setup-uv@v4
|
|
25
|
+
with:
|
|
26
|
+
enable-cache: true
|
|
27
|
+
|
|
28
|
+
- name: Set up Python ${{ matrix.python-version }}
|
|
29
|
+
run: uv python install ${{ matrix.python-version }}
|
|
30
|
+
|
|
31
|
+
- name: Install dependencies
|
|
32
|
+
run: uv sync --extra dev
|
|
33
|
+
|
|
34
|
+
- name: Run tests
|
|
35
|
+
run: uv run pytest -v
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
name: Publish to PyPI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
tags:
|
|
6
|
+
- "v*"
|
|
7
|
+
|
|
8
|
+
permissions:
|
|
9
|
+
contents: read # Required for actions/checkout
|
|
10
|
+
id-token: write # Required for OIDC Trusted Publisher
|
|
11
|
+
|
|
12
|
+
jobs:
|
|
13
|
+
publish:
|
|
14
|
+
runs-on: ubuntu-latest
|
|
15
|
+
timeout-minutes: 15
|
|
16
|
+
environment: pypi
|
|
17
|
+
steps:
|
|
18
|
+
- uses: actions/checkout@v4
|
|
19
|
+
|
|
20
|
+
- name: Install uv
|
|
21
|
+
uses: astral-sh/setup-uv@v4
|
|
22
|
+
|
|
23
|
+
- name: Build package
|
|
24
|
+
run: uv build
|
|
25
|
+
|
|
26
|
+
- name: Publish to PyPI
|
|
27
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
muxplex-0.1.0/.gitignore
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# Python bytecode
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.pyc
|
|
4
|
+
*.pyo
|
|
5
|
+
*.pyd
|
|
6
|
+
|
|
7
|
+
# Virtual environment
|
|
8
|
+
.venv/
|
|
9
|
+
venv/
|
|
10
|
+
env/
|
|
11
|
+
|
|
12
|
+
# Distribution / packaging
|
|
13
|
+
dist/
|
|
14
|
+
build/
|
|
15
|
+
*.egg-info/
|
|
16
|
+
|
|
17
|
+
# Test/coverage artifacts
|
|
18
|
+
.coverage
|
|
19
|
+
.pytest_cache/
|
|
20
|
+
htmlcov/
|
|
21
|
+
|
|
22
|
+
# OS artifacts
|
|
23
|
+
.DS_Store
|
|
24
|
+
Thumbs.db
|
|
25
|
+
|
|
26
|
+
# IDE
|
|
27
|
+
.idea/
|
|
28
|
+
.vscode/
|
|
29
|
+
*.swp
|
|
30
|
+
*.swo
|
muxplex-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,396 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: muxplex
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Web-based tmux session dashboard — access all your tmux sessions from any browser
|
|
5
|
+
Project-URL: Repository, https://github.com/bkrabach/muxplex
|
|
6
|
+
Project-URL: Issues, https://github.com/bkrabach/muxplex/issues
|
|
7
|
+
Author-email: Brian Krabach <brian@krabach.com>
|
|
8
|
+
License: MIT
|
|
9
|
+
Keywords: dashboard,session-manager,terminal,tmux,web
|
|
10
|
+
Classifier: Development Status :: 4 - Beta
|
|
11
|
+
Classifier: Environment :: Web Environment
|
|
12
|
+
Classifier: Framework :: FastAPI
|
|
13
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
18
|
+
Classifier: Topic :: System :: Systems Administration
|
|
19
|
+
Classifier: Topic :: Terminals :: Terminal Emulators/X Terminals
|
|
20
|
+
Requires-Python: >=3.11
|
|
21
|
+
Requires-Dist: aiofiles>=23.0
|
|
22
|
+
Requires-Dist: cryptography
|
|
23
|
+
Requires-Dist: fastapi>=0.115.0
|
|
24
|
+
Requires-Dist: httpx>=0.27.0
|
|
25
|
+
Requires-Dist: itsdangerous>=2.1.0
|
|
26
|
+
Requires-Dist: python-multipart>=0.0.9
|
|
27
|
+
Requires-Dist: python-pam>=1.8.4
|
|
28
|
+
Requires-Dist: six>=1.16.0
|
|
29
|
+
Requires-Dist: uvicorn[standard]>=0.30.0
|
|
30
|
+
Requires-Dist: websockets>=11.0
|
|
31
|
+
Provides-Extra: dev
|
|
32
|
+
Requires-Dist: beautifulsoup4>=4.12; extra == 'dev'
|
|
33
|
+
Requires-Dist: pytest-asyncio>=0.23.0; extra == 'dev'
|
|
34
|
+
Requires-Dist: pytest>=8.0.0; extra == 'dev'
|
|
35
|
+
Description-Content-Type: text/markdown
|
|
36
|
+
|
|
37
|
+
# muxplex
|
|
38
|
+
|
|
39
|
+
**Web-based tmux session dashboard — access, monitor, and manage all your tmux sessions from any browser on any device.**
|
|
40
|
+
|
|
41
|
+

|
|
42
|
+
|
|
43
|
+
---
|
|
44
|
+
|
|
45
|
+
## Features
|
|
46
|
+
|
|
47
|
+
### Dashboard
|
|
48
|
+
|
|
49
|
+
- **Live session grid** — preview tiles with ANSI-colored terminal snapshots, auto-refreshed
|
|
50
|
+
- **Two view modes** — Auto (scrollable grid) and Fit (all sessions fill the viewport)
|
|
51
|
+
- **Hover preview** — full-size overlay of session content on tile hover
|
|
52
|
+
- **Activity indicators** — bell notification badges on tiles; amber favicon dot + `(N)` count in browser tab title when sessions have unseen activity
|
|
53
|
+
- **Session creation** — `+` button with device selector dropdown when multi-device is enabled; custom command template support
|
|
54
|
+
- **Session deletion** — `×` button with custom command template support
|
|
55
|
+
- **Mobile-friendly** — responsive layout, PWA-capable for home-screen install
|
|
56
|
+
|
|
57
|
+
### Terminal
|
|
58
|
+
|
|
59
|
+
- **Full interactive terminal** — powered by xterm.js + ttyd
|
|
60
|
+
- **Native clipboard** — Ctrl+Shift+C to copy, Ctrl+Shift+V to paste
|
|
61
|
+
- **Mouse select auto-copy** — selecting text copies to system clipboard on release
|
|
62
|
+
- **OSC 52 tmux clipboard bridge** — tmux copy mode selections go to system clipboard
|
|
63
|
+
- **Search** — Ctrl+F opens a search bar to find text in terminal scrollback (xterm-addon-search)
|
|
64
|
+
- **Clickable URLs** — Ctrl+Click (Cmd+Click on macOS) opens URLs in terminal output in a new tab (xterm-addon-web-links)
|
|
65
|
+
- **Inline image rendering** — Sixel and iTerm2 graphic protocols for tools like yazi file manager (xterm-addon-image)
|
|
66
|
+
- **Sidebar session switcher** — quick-switch between sessions with live previews
|
|
67
|
+
|
|
68
|
+
### Settings
|
|
69
|
+
|
|
70
|
+
- **In-browser settings panel** — gear icon or `,` shortcut
|
|
71
|
+
- **Display** — font size, grid columns, hover delay, view mode, device badges, activity indicator
|
|
72
|
+
- **Sessions** — default session, sort order, hidden sessions, auto-open, bell sound, notifications
|
|
73
|
+
- **Commands** — custom create/delete session templates
|
|
74
|
+
- **Multi-Device** — remote instance federation
|
|
75
|
+
- **CLI** — `muxplex config list/get/set/reset`
|
|
76
|
+
|
|
77
|
+
### Multi-Device
|
|
78
|
+
|
|
79
|
+
- **Remote session aggregation** — federate multiple muxplex instances into a unified dashboard view
|
|
80
|
+
- **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
|
|
81
|
+
- **Remote bell-clear** — opening a session on a remote device automatically clears its activity notification via federation API (`POST /api/bell/clear`)
|
|
82
|
+
- **Unique session keys** — sessions identified by `remoteId:name` across devices, preventing bell-state collisions for identically-named sessions on different machines
|
|
83
|
+
|
|
84
|
+
### Service Management
|
|
85
|
+
|
|
86
|
+
- `muxplex service install/start/stop/restart/status/logs/uninstall`
|
|
87
|
+
- **Platform-aware** — systemd user service on Linux/WSL, launchd agent on macOS
|
|
88
|
+
- **Config-driven** — service reads all options from `~/.config/muxplex/settings.json` (no flags in the service file)
|
|
89
|
+
|
|
90
|
+
### Authentication
|
|
91
|
+
|
|
92
|
+
- **PAM authentication** — Linux/macOS system credentials
|
|
93
|
+
- **Password mode** — auto-generated or set via `MUXPLEX_PASSWORD` env var
|
|
94
|
+
- **Localhost bypass** — no auth needed on 127.0.0.1
|
|
95
|
+
- **Secure session cookies** — signed with configurable TTL
|
|
96
|
+
|
|
97
|
+
### Developer Tools
|
|
98
|
+
|
|
99
|
+
- `muxplex doctor` — dependency + config diagnostics with update check
|
|
100
|
+
- `muxplex upgrade` — smart version check + auto-update + service restart
|
|
101
|
+
- `muxplex config` — CLI settings management
|
|
102
|
+
|
|
103
|
+
### HTTPS / TLS
|
|
104
|
+
|
|
105
|
+
- `muxplex setup-tls` — auto-detect and set up TLS certificates
|
|
106
|
+
- **Tailscale** — real Let's Encrypt certs via `tailscale cert` (recommended)
|
|
107
|
+
- **mkcert** — locally-trusted certs, zero browser warnings
|
|
108
|
+
- **Self-signed** — fallback for immediate HTTPS (browser shows warning)
|
|
109
|
+
- Required for browser clipboard API on non-localhost
|
|
110
|
+
|
|
111
|
+
---
|
|
112
|
+
|
|
113
|
+
## Prerequisites
|
|
114
|
+
|
|
115
|
+
- **Python 3.11+** — installed via `uv` or system Python
|
|
116
|
+
- **tmux** — terminal multiplexer
|
|
117
|
+
- macOS: `brew install tmux`
|
|
118
|
+
- Ubuntu/WSL: `sudo apt install tmux`
|
|
119
|
+
- **ttyd** — terminal sharing over HTTP (required for interactive terminal access)
|
|
120
|
+
- macOS: `brew install ttyd`
|
|
121
|
+
- Ubuntu/WSL: `sudo apt install ttyd` or `sudo snap install ttyd`
|
|
122
|
+
- Other: https://github.com/tsl0922/ttyd#installation
|
|
123
|
+
|
|
124
|
+
> **Tip:** Run `muxplex doctor` to check all dependencies and system status.
|
|
125
|
+
|
|
126
|
+
---
|
|
127
|
+
|
|
128
|
+
## Quick Start (uvx — no install)
|
|
129
|
+
|
|
130
|
+
Run muxplex directly without installing anything permanently:
|
|
131
|
+
|
|
132
|
+
```bash
|
|
133
|
+
uvx --from git+https://github.com/bkrabach/muxplex muxplex
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
Then open **http://localhost:8088** in your browser.
|
|
137
|
+
|
|
138
|
+
> **Note:** `uvx` is part of [uv](https://docs.astral.sh/uv/). Install uv with `curl -LsSf https://astral.sh/uv/install.sh | sh`.
|
|
139
|
+
|
|
140
|
+
---
|
|
141
|
+
|
|
142
|
+
## Install Permanently
|
|
143
|
+
|
|
144
|
+
```bash
|
|
145
|
+
uv tool install git+https://github.com/bkrabach/muxplex
|
|
146
|
+
muxplex doctor # verify dependencies
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
Then run it any time with:
|
|
150
|
+
|
|
151
|
+
```bash
|
|
152
|
+
muxplex
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
---
|
|
156
|
+
|
|
157
|
+
## Install as a Service
|
|
158
|
+
|
|
159
|
+
```bash
|
|
160
|
+
muxplex service install
|
|
161
|
+
# → prompts to set host to 0.0.0.0 for network access
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
The service starts automatically on login (macOS) or at boot (Linux) and restarts on failure.
|
|
165
|
+
|
|
166
|
+
```bash
|
|
167
|
+
# Open in browser
|
|
168
|
+
open http://localhost:8088
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
To stop and remove:
|
|
172
|
+
|
|
173
|
+
```bash
|
|
174
|
+
muxplex service uninstall
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
---
|
|
178
|
+
|
|
179
|
+
## CLI Reference
|
|
180
|
+
|
|
181
|
+
```
|
|
182
|
+
muxplex Start server (default)
|
|
183
|
+
muxplex serve [flags] Start with CLI flag overrides
|
|
184
|
+
muxplex service install Install + enable + start as OS service
|
|
185
|
+
muxplex service uninstall Stop + disable + remove
|
|
186
|
+
muxplex service start|stop|restart Manage running service
|
|
187
|
+
muxplex service status Show service status
|
|
188
|
+
muxplex service logs Tail service logs
|
|
189
|
+
muxplex config Show all settings
|
|
190
|
+
muxplex config get <key> Show one setting
|
|
191
|
+
muxplex config set <key> <value> Set a setting
|
|
192
|
+
muxplex config reset [key] Reset one or all to defaults
|
|
193
|
+
muxplex upgrade [--force] Smart update with version check
|
|
194
|
+
muxplex doctor Check dependencies + config
|
|
195
|
+
muxplex show-password Show current auth password
|
|
196
|
+
muxplex reset-secret Regenerate signing secret
|
|
197
|
+
muxplex setup-tls [--method auto] Set up TLS certs (Tailscale/mkcert/self-signed)
|
|
198
|
+
muxplex setup-tls --status Show current TLS configuration
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
### Service management
|
|
202
|
+
|
|
203
|
+
```bash
|
|
204
|
+
muxplex service install # Write service file + enable + start
|
|
205
|
+
muxplex service uninstall # Stop + disable + remove service file
|
|
206
|
+
muxplex service start # Start the service
|
|
207
|
+
muxplex service stop # Stop the service
|
|
208
|
+
muxplex service restart # Stop + start
|
|
209
|
+
muxplex service status # Show running/stopped + PID
|
|
210
|
+
muxplex service logs # Tail service logs
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
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:
|
|
214
|
+
|
|
215
|
+
```bash
|
|
216
|
+
muxplex config set host 0.0.0.0
|
|
217
|
+
muxplex service restart
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
### Examples
|
|
221
|
+
|
|
222
|
+
```bash
|
|
223
|
+
# Start with defaults from settings.json
|
|
224
|
+
muxplex
|
|
225
|
+
|
|
226
|
+
# Override port for this run only
|
|
227
|
+
muxplex --port 9000
|
|
228
|
+
|
|
229
|
+
# Override host for this run only
|
|
230
|
+
muxplex serve --host 0.0.0.0
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
### HTTPS / TLS setup
|
|
234
|
+
|
|
235
|
+
```bash
|
|
236
|
+
# Auto-detect the best TLS method and set up certificates
|
|
237
|
+
muxplex setup-tls
|
|
238
|
+
|
|
239
|
+
# Use a specific TLS method
|
|
240
|
+
muxplex setup-tls --method tailscale
|
|
241
|
+
muxplex setup-tls --method mkcert
|
|
242
|
+
muxplex setup-tls --method selfsigned
|
|
243
|
+
|
|
244
|
+
# Show current TLS status and configuration
|
|
245
|
+
muxplex setup-tls --status
|
|
246
|
+
|
|
247
|
+
# Override TLS cert/key for a single run (without saving to config)
|
|
248
|
+
muxplex serve --tls-cert /path/cert.pem --tls-key /path/key.pem
|
|
249
|
+
|
|
250
|
+
# Check TLS configuration and dependencies
|
|
251
|
+
muxplex doctor
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
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.
|
|
255
|
+
|
|
256
|
+
> **Note:** Tailscale certs have a 90-day expiry. Run `muxplex setup-tls --method tailscale` to renew when needed.
|
|
257
|
+
|
|
258
|
+
---
|
|
259
|
+
|
|
260
|
+
## Configuration
|
|
261
|
+
|
|
262
|
+
All settings are stored in `~/.config/muxplex/settings.json`.
|
|
263
|
+
|
|
264
|
+
| Key | Default | Description |
|
|
265
|
+
|---|---|---|
|
|
266
|
+
| `host` | `127.0.0.1` | Bind address (set to `0.0.0.0` for network access) |
|
|
267
|
+
| `port` | `8088` | Server port |
|
|
268
|
+
| `auth` | `pam` | Authentication mode: `pam` or `password` |
|
|
269
|
+
| `session_ttl` | `604800` | Session cookie TTL in seconds (7 days; 0 = browser session) |
|
|
270
|
+
| `default_session` | `null` | Session to auto-open on load |
|
|
271
|
+
| `sort_order` | `manual` | Session ordering: `manual`, `alphabetical`, `recent` |
|
|
272
|
+
| `hidden_sessions` | `[]` | Sessions hidden from the dashboard |
|
|
273
|
+
| `window_size_largest` | `false` | Auto-set tmux `window-size largest` on connect |
|
|
274
|
+
| `auto_open_created` | `true` | Auto-open newly created sessions |
|
|
275
|
+
| `new_session_template` | `tmux new-session -d -s {name}` | Command template for creating sessions |
|
|
276
|
+
| `delete_session_template` | `tmux kill-session -t {name}` | Command template for deleting sessions |
|
|
277
|
+
| `device_name` | `""` (hostname) | Display name for this device |
|
|
278
|
+
| `federation_key` | `""` | Server-to-server authentication key for federation |
|
|
279
|
+
| `remote_instances` | `[]` | Remote muxplex instances to aggregate |
|
|
280
|
+
| `multi_device_enabled` | `false` | Enable multi-instance federation |
|
|
281
|
+
| `tls_cert` | `""` | Path to TLS certificate file (empty = HTTP) |
|
|
282
|
+
| `tls_key` | `""` | Path to TLS private key file (empty = HTTP) |
|
|
283
|
+
|
|
284
|
+
**Priority:** CLI flags > `settings.json` > defaults.
|
|
285
|
+
|
|
286
|
+
---
|
|
287
|
+
|
|
288
|
+
## Keyboard Shortcuts
|
|
289
|
+
|
|
290
|
+
| Shortcut | Action |
|
|
291
|
+
|---|---|
|
|
292
|
+
| Ctrl+Shift+C | Copy terminal selection to system clipboard |
|
|
293
|
+
| Ctrl+Shift+V | Paste from system clipboard into terminal |
|
|
294
|
+
| Ctrl+F | Open terminal search bar |
|
|
295
|
+
| Enter / Shift+Enter | Next / previous search match |
|
|
296
|
+
| Ctrl+Click (Cmd+Click) | Open URL in new tab |
|
|
297
|
+
| `,` (comma) | Open settings |
|
|
298
|
+
| Escape | Close settings / return to dashboard |
|
|
299
|
+
|
|
300
|
+
Mouse select in the terminal auto-copies to the system clipboard on release.
|
|
301
|
+
|
|
302
|
+
---
|
|
303
|
+
|
|
304
|
+
## Platform Support
|
|
305
|
+
|
|
306
|
+
| Platform | Service | Auth |
|
|
307
|
+
|---|---|---|
|
|
308
|
+
| Linux (Ubuntu/Debian) | systemd user service | PAM |
|
|
309
|
+
| macOS | launchd agent | PAM |
|
|
310
|
+
| WSL | systemd user service | PAM |
|
|
311
|
+
|
|
312
|
+
---
|
|
313
|
+
|
|
314
|
+
## Project Structure
|
|
315
|
+
|
|
316
|
+
```
|
|
317
|
+
muxplex/
|
|
318
|
+
├── muxplex/
|
|
319
|
+
│ ├── __init__.py
|
|
320
|
+
│ ├── __main__.py # python -m muxplex entry
|
|
321
|
+
│ ├── cli.py # CLI entry point and subcommand dispatch
|
|
322
|
+
│ ├── main.py # FastAPI app, routes, WebSocket proxy
|
|
323
|
+
│ ├── auth.py # PAM/password auth middleware
|
|
324
|
+
│ ├── sessions.py # tmux session enumeration + snapshots
|
|
325
|
+
│ ├── bells.py # Bell flag detection + clear rules
|
|
326
|
+
│ ├── state.py # Persistent state (JSON)
|
|
327
|
+
│ ├── settings.py # User settings management
|
|
328
|
+
│ ├── service.py # Service install/start/stop (systemd + launchd)
|
|
329
|
+
│ ├── ttyd.py # ttyd process lifecycle
|
|
330
|
+
│ ├── frontend/
|
|
331
|
+
│ │ ├── index.html # Main SPA
|
|
332
|
+
│ │ ├── login.html # Login page
|
|
333
|
+
│ │ ├── app.js # Dashboard, sidebar, settings, previews
|
|
334
|
+
│ │ ├── terminal.js # xterm.js terminal + clipboard
|
|
335
|
+
│ │ ├── style.css # All styles (dark theme)
|
|
336
|
+
│ │ ├── manifest.json # PWA manifest
|
|
337
|
+
│ │ ├── wordmark-on-dark.svg
|
|
338
|
+
│ │ └── tests/ # JavaScript unit tests
|
|
339
|
+
│ └── tests/ # Python tests (pytest)
|
|
340
|
+
├── assets/branding/ # Logos, icons, design system
|
|
341
|
+
├── docs/plans/ # Historical design + implementation plans
|
|
342
|
+
├── scripts/ # Utility scripts (asset generation)
|
|
343
|
+
├── pyproject.toml
|
|
344
|
+
└── README.md
|
|
345
|
+
```
|
|
346
|
+
|
|
347
|
+
---
|
|
348
|
+
|
|
349
|
+
## Development
|
|
350
|
+
|
|
351
|
+
### Setup
|
|
352
|
+
|
|
353
|
+
```bash
|
|
354
|
+
git clone https://github.com/bkrabach/muxplex
|
|
355
|
+
cd muxplex
|
|
356
|
+
|
|
357
|
+
# Install with dev dependencies
|
|
358
|
+
uv pip install -e ".[dev]"
|
|
359
|
+
```
|
|
360
|
+
|
|
361
|
+
### Run the server
|
|
362
|
+
|
|
363
|
+
```bash
|
|
364
|
+
muxplex
|
|
365
|
+
# or directly:
|
|
366
|
+
python -m muxplex
|
|
367
|
+
```
|
|
368
|
+
|
|
369
|
+
### Run tests
|
|
370
|
+
|
|
371
|
+
```bash
|
|
372
|
+
# Python tests (pytest)
|
|
373
|
+
python -m pytest muxplex/tests/ --ignore=muxplex/tests/test_integration.py
|
|
374
|
+
|
|
375
|
+
# JavaScript tests (node:test)
|
|
376
|
+
node --test muxplex/frontend/tests/test_terminal.mjs
|
|
377
|
+
node --test muxplex/frontend/tests/test_app.mjs
|
|
378
|
+
```
|
|
379
|
+
|
|
380
|
+
---
|
|
381
|
+
|
|
382
|
+
## Brand Assets
|
|
383
|
+
|
|
384
|
+
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.
|
|
385
|
+
|
|
386
|
+
To regenerate PNG/favicon assets from SVG sources:
|
|
387
|
+
|
|
388
|
+
```bash
|
|
389
|
+
python3 scripts/render-brand-assets.py
|
|
390
|
+
```
|
|
391
|
+
|
|
392
|
+
---
|
|
393
|
+
|
|
394
|
+
## License
|
|
395
|
+
|
|
396
|
+
MIT
|