clustermux 0.2.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.
- clustermux-0.2.0/.gitignore +7 -0
- clustermux-0.2.0/LICENSE +21 -0
- clustermux-0.2.0/PKG-INFO +155 -0
- clustermux-0.2.0/README.md +131 -0
- clustermux-0.2.0/clustermux.py +2448 -0
- clustermux-0.2.0/examples/hosts.json +18 -0
- clustermux-0.2.0/pyproject.toml +40 -0
clustermux-0.2.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Yitong Li
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: clustermux
|
|
3
|
+
Version: 0.2.0
|
|
4
|
+
Summary: A dependency-free TUI for tmux sessions spread across SSH hosts
|
|
5
|
+
Project-URL: Homepage, https://github.com/lyttttt3333/clustermux
|
|
6
|
+
Project-URL: Repository, https://github.com/lyttttt3333/clustermux
|
|
7
|
+
Project-URL: Issues, https://github.com/lyttttt3333/clustermux/issues
|
|
8
|
+
Author: Yitong Li
|
|
9
|
+
License: MIT
|
|
10
|
+
License-File: LICENSE
|
|
11
|
+
Keywords: cluster,hpc,ssh,terminal,tmux,tui
|
|
12
|
+
Classifier: Development Status :: 4 - Beta
|
|
13
|
+
Classifier: Environment :: Console :: Curses
|
|
14
|
+
Classifier: Intended Audience :: Developers
|
|
15
|
+
Classifier: Intended Audience :: System Administrators
|
|
16
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
17
|
+
Classifier: Operating System :: MacOS
|
|
18
|
+
Classifier: Operating System :: POSIX :: Linux
|
|
19
|
+
Classifier: Programming Language :: Python :: 3
|
|
20
|
+
Classifier: Topic :: System :: Systems Administration
|
|
21
|
+
Classifier: Topic :: Terminals
|
|
22
|
+
Requires-Python: >=3.9
|
|
23
|
+
Description-Content-Type: text/markdown
|
|
24
|
+
|
|
25
|
+
# clustermux
|
|
26
|
+
|
|
27
|
+
A small, dependency-free TUI for managing **tmux sessions spread across SSH hosts** — HPC login nodes, cloud dev boxes, GPU clusters — from a single terminal window.
|
|
28
|
+
|
|
29
|
+
clustermux discovers every remote tmux session in parallel, shows you what's running where, and lets you attach, create, rename, kill, or hand off sessions without juggling terminal tabs or remembering which machine hosts which session.
|
|
30
|
+
|
|
31
|
+
## Features
|
|
32
|
+
|
|
33
|
+
- **One dashboard for every host** — parallel SSH discovery of all remote tmux sessions, with reachability, latency, running command, and working directory
|
|
34
|
+
- **Persistent connections** — each attached session lives in a hidden local tmux window; detach and re-attach without disturbing the remote work
|
|
35
|
+
- **Split workspace** — a navigator sidebar plus a remote terminal pane, inside one local tmux session
|
|
36
|
+
- **iTerm2 integration (macOS)** — opens the manager, or any single session, in a new tab without disturbing your current one; standalone tabs auto-reconnect after transient SSH drops
|
|
37
|
+
- **Session management** — create empty sessions, rename, and kill remote tmux sessions from the TUI
|
|
38
|
+
- **Codex fork** — fork a running [Codex CLI](https://github.com/openai/codex) session into a new tmux session (finds the live rollout thread via `/proc` and runs `codex fork <thread-id>`)
|
|
39
|
+
- **One-command setup** — `clustermux --init` scans your SSH config, installs your key, and writes the hosts file; `clustermux --check` verifies the whole setup
|
|
40
|
+
- **Plain output mode** — `clustermux --list` for scripts and quick checks
|
|
41
|
+
- **Zero dependencies** — a single Python file using only the standard library
|
|
42
|
+
|
|
43
|
+
## Requirements
|
|
44
|
+
|
|
45
|
+
- Local: Python ≥ 3.9, tmux, and (for tab features) macOS with iTerm2
|
|
46
|
+
- Remote hosts: SSH access (key-based, non-interactive) and tmux
|
|
47
|
+
- The full-screen dashboard (`--here`) and `--list` work on any terminal; the default tab-based flow requires iTerm2
|
|
48
|
+
|
|
49
|
+
## Install
|
|
50
|
+
|
|
51
|
+
### pipx / pip
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
pipx install clustermux
|
|
55
|
+
# or
|
|
56
|
+
pip install clustermux
|
|
57
|
+
# or straight from the repo
|
|
58
|
+
pipx install git+https://github.com/lyttttt3333/clustermux.git
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
### Single-file script
|
|
62
|
+
|
|
63
|
+
clustermux is self-contained — download the file anywhere on your `PATH`:
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
curl -L -o ~/.local/bin/clustermux \
|
|
67
|
+
https://raw.githubusercontent.com/lyttttt3333/clustermux/main/clustermux.py
|
|
68
|
+
chmod +x ~/.local/bin/clustermux
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
## First-time setup
|
|
72
|
+
|
|
73
|
+
On a fresh machine, one command walks you through everything:
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
clustermux --init
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
The wizard will:
|
|
80
|
+
|
|
81
|
+
1. **SSH key** — use your existing `~/.ssh` key, or offer to generate an ed25519 one
|
|
82
|
+
2. **Discover hosts** — scan `~/.ssh/config` (`Host` aliases, including `Include`d files) and any unhashed entries in `~/.ssh/known_hosts`
|
|
83
|
+
3. **Probe connectivity** — test every candidate in parallel with `BatchMode` SSH, classifying each as reachable / key-rejected / unreachable
|
|
84
|
+
4. **Install your key** — for hosts that reject key auth, offer to run `ssh-copy-id` (you type the password once per host)
|
|
85
|
+
5. **Write the config** — reachable hosts are added to `~/.config/clustermux/hosts.json` with sensible group/label defaults (existing entries are kept, and the old file is backed up); you can review the result in `$EDITOR`
|
|
86
|
+
|
|
87
|
+
Then verify the whole setup at any time:
|
|
88
|
+
|
|
89
|
+
```bash
|
|
90
|
+
clustermux --check
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
This checks Python, tmux, ssh, iTerm2, your SSH key and config file, then probes every configured host and reports sessions and latency per node.
|
|
94
|
+
|
|
95
|
+
## Configuration
|
|
96
|
+
|
|
97
|
+
`clustermux --init` writes this file for you, but you can also create `~/.config/clustermux/hosts.json` by hand (see [examples/hosts.json](examples/hosts.json)):
|
|
98
|
+
|
|
99
|
+
```json
|
|
100
|
+
[
|
|
101
|
+
{ "group": "GPU", "label": "login-01", "target": "me@gpu-login-01.example.com" },
|
|
102
|
+
{ "group": "GPU", "label": "dev-01", "target": "gpu-dev-01", "connect_timeout": 20 },
|
|
103
|
+
{ "group": "CPU", "label": "login", "target": "me@cpu-login.example.com" }
|
|
104
|
+
]
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
- `group` — shown as the cluster name in the UI
|
|
108
|
+
- `label` — per-host display name
|
|
109
|
+
- `target` — anything `ssh` accepts (host alias from `~/.ssh/config`, or `user@host`)
|
|
110
|
+
- `connect_timeout` — optional per-host SSH timeout in seconds (default: `--timeout`, 8s)
|
|
111
|
+
|
|
112
|
+
Hosts are validated at startup; SSH is always invoked with `BatchMode=yes`, so a host that needs a password simply shows up as offline instead of blocking the UI.
|
|
113
|
+
|
|
114
|
+
## Usage
|
|
115
|
+
|
|
116
|
+
```bash
|
|
117
|
+
clustermux # open the manager workspace in a new iTerm tab
|
|
118
|
+
clustermux --init # first-time setup: scan SSH config, install keys, write hosts.json
|
|
119
|
+
clustermux --check # verify local requirements and probe every host
|
|
120
|
+
clustermux --workspace # run the split navigator/terminal workspace here
|
|
121
|
+
clustermux --here # full-screen dashboard with pane previews, in this terminal
|
|
122
|
+
clustermux --list # print one snapshot as a table and exit
|
|
123
|
+
clustermux --refresh 60 # change the auto-refresh interval (seconds; 0 disables)
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
### Navigator keybindings (default workspace)
|
|
127
|
+
|
|
128
|
+
| Key | Action |
|
|
129
|
+
| --- | --- |
|
|
130
|
+
| `↑`/`↓` | move between clusters and sessions |
|
|
131
|
+
| `Enter` | attach the selected session in the right pane |
|
|
132
|
+
| `b` | open a remote Bash shell for the selected cluster |
|
|
133
|
+
| `t` | create a new empty tmux session on the selected cluster |
|
|
134
|
+
| `f` | fork the selected Codex session into a new tmux session |
|
|
135
|
+
| `e` / `x` | rename / kill the selected session |
|
|
136
|
+
| `o` | hand the session off to a standalone iTerm tab (auto-reconnects) |
|
|
137
|
+
| `r` | refresh all hosts |
|
|
138
|
+
| `Shift+←` | jump back to the sidebar from the remote pane |
|
|
139
|
+
| `q` | close the workspace (remote sessions keep running) |
|
|
140
|
+
|
|
141
|
+
Inside an attached remote tmux session, the remote prefix is `Ctrl-b` as usual; the local workspace uses `Ctrl-a`.
|
|
142
|
+
|
|
143
|
+
### Dashboard keybindings (`--here`)
|
|
144
|
+
|
|
145
|
+
`↑↓` select · `Enter` attach here · `t` new tab · `r` refresh · `p` preview · `q` quit
|
|
146
|
+
|
|
147
|
+
## How it works
|
|
148
|
+
|
|
149
|
+
- Discovery runs `tmux list-panes -a` on every host in parallel over SSH and parses a sentinel-separated format that survives older remote tmux builds.
|
|
150
|
+
- Attaching creates (or reuses) a hidden window in the local `clustermux` tmux session running a supervised `ssh -t host tmux attach-session ...`; the pane is swapped into the visible slot. Killing the workspace only disconnects local SSH clients — remote sessions and their processes keep running.
|
|
151
|
+
- The iTerm handoff moves a session into its own tab and respawns the workspace pane as a placeholder, so you can later pull it back into the workspace.
|
|
152
|
+
|
|
153
|
+
## License
|
|
154
|
+
|
|
155
|
+
[MIT](LICENSE)
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
# clustermux
|
|
2
|
+
|
|
3
|
+
A small, dependency-free TUI for managing **tmux sessions spread across SSH hosts** — HPC login nodes, cloud dev boxes, GPU clusters — from a single terminal window.
|
|
4
|
+
|
|
5
|
+
clustermux discovers every remote tmux session in parallel, shows you what's running where, and lets you attach, create, rename, kill, or hand off sessions without juggling terminal tabs or remembering which machine hosts which session.
|
|
6
|
+
|
|
7
|
+
## Features
|
|
8
|
+
|
|
9
|
+
- **One dashboard for every host** — parallel SSH discovery of all remote tmux sessions, with reachability, latency, running command, and working directory
|
|
10
|
+
- **Persistent connections** — each attached session lives in a hidden local tmux window; detach and re-attach without disturbing the remote work
|
|
11
|
+
- **Split workspace** — a navigator sidebar plus a remote terminal pane, inside one local tmux session
|
|
12
|
+
- **iTerm2 integration (macOS)** — opens the manager, or any single session, in a new tab without disturbing your current one; standalone tabs auto-reconnect after transient SSH drops
|
|
13
|
+
- **Session management** — create empty sessions, rename, and kill remote tmux sessions from the TUI
|
|
14
|
+
- **Codex fork** — fork a running [Codex CLI](https://github.com/openai/codex) session into a new tmux session (finds the live rollout thread via `/proc` and runs `codex fork <thread-id>`)
|
|
15
|
+
- **One-command setup** — `clustermux --init` scans your SSH config, installs your key, and writes the hosts file; `clustermux --check` verifies the whole setup
|
|
16
|
+
- **Plain output mode** — `clustermux --list` for scripts and quick checks
|
|
17
|
+
- **Zero dependencies** — a single Python file using only the standard library
|
|
18
|
+
|
|
19
|
+
## Requirements
|
|
20
|
+
|
|
21
|
+
- Local: Python ≥ 3.9, tmux, and (for tab features) macOS with iTerm2
|
|
22
|
+
- Remote hosts: SSH access (key-based, non-interactive) and tmux
|
|
23
|
+
- The full-screen dashboard (`--here`) and `--list` work on any terminal; the default tab-based flow requires iTerm2
|
|
24
|
+
|
|
25
|
+
## Install
|
|
26
|
+
|
|
27
|
+
### pipx / pip
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
pipx install clustermux
|
|
31
|
+
# or
|
|
32
|
+
pip install clustermux
|
|
33
|
+
# or straight from the repo
|
|
34
|
+
pipx install git+https://github.com/lyttttt3333/clustermux.git
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
### Single-file script
|
|
38
|
+
|
|
39
|
+
clustermux is self-contained — download the file anywhere on your `PATH`:
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
curl -L -o ~/.local/bin/clustermux \
|
|
43
|
+
https://raw.githubusercontent.com/lyttttt3333/clustermux/main/clustermux.py
|
|
44
|
+
chmod +x ~/.local/bin/clustermux
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## First-time setup
|
|
48
|
+
|
|
49
|
+
On a fresh machine, one command walks you through everything:
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
clustermux --init
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
The wizard will:
|
|
56
|
+
|
|
57
|
+
1. **SSH key** — use your existing `~/.ssh` key, or offer to generate an ed25519 one
|
|
58
|
+
2. **Discover hosts** — scan `~/.ssh/config` (`Host` aliases, including `Include`d files) and any unhashed entries in `~/.ssh/known_hosts`
|
|
59
|
+
3. **Probe connectivity** — test every candidate in parallel with `BatchMode` SSH, classifying each as reachable / key-rejected / unreachable
|
|
60
|
+
4. **Install your key** — for hosts that reject key auth, offer to run `ssh-copy-id` (you type the password once per host)
|
|
61
|
+
5. **Write the config** — reachable hosts are added to `~/.config/clustermux/hosts.json` with sensible group/label defaults (existing entries are kept, and the old file is backed up); you can review the result in `$EDITOR`
|
|
62
|
+
|
|
63
|
+
Then verify the whole setup at any time:
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
clustermux --check
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
This checks Python, tmux, ssh, iTerm2, your SSH key and config file, then probes every configured host and reports sessions and latency per node.
|
|
70
|
+
|
|
71
|
+
## Configuration
|
|
72
|
+
|
|
73
|
+
`clustermux --init` writes this file for you, but you can also create `~/.config/clustermux/hosts.json` by hand (see [examples/hosts.json](examples/hosts.json)):
|
|
74
|
+
|
|
75
|
+
```json
|
|
76
|
+
[
|
|
77
|
+
{ "group": "GPU", "label": "login-01", "target": "me@gpu-login-01.example.com" },
|
|
78
|
+
{ "group": "GPU", "label": "dev-01", "target": "gpu-dev-01", "connect_timeout": 20 },
|
|
79
|
+
{ "group": "CPU", "label": "login", "target": "me@cpu-login.example.com" }
|
|
80
|
+
]
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
- `group` — shown as the cluster name in the UI
|
|
84
|
+
- `label` — per-host display name
|
|
85
|
+
- `target` — anything `ssh` accepts (host alias from `~/.ssh/config`, or `user@host`)
|
|
86
|
+
- `connect_timeout` — optional per-host SSH timeout in seconds (default: `--timeout`, 8s)
|
|
87
|
+
|
|
88
|
+
Hosts are validated at startup; SSH is always invoked with `BatchMode=yes`, so a host that needs a password simply shows up as offline instead of blocking the UI.
|
|
89
|
+
|
|
90
|
+
## Usage
|
|
91
|
+
|
|
92
|
+
```bash
|
|
93
|
+
clustermux # open the manager workspace in a new iTerm tab
|
|
94
|
+
clustermux --init # first-time setup: scan SSH config, install keys, write hosts.json
|
|
95
|
+
clustermux --check # verify local requirements and probe every host
|
|
96
|
+
clustermux --workspace # run the split navigator/terminal workspace here
|
|
97
|
+
clustermux --here # full-screen dashboard with pane previews, in this terminal
|
|
98
|
+
clustermux --list # print one snapshot as a table and exit
|
|
99
|
+
clustermux --refresh 60 # change the auto-refresh interval (seconds; 0 disables)
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
### Navigator keybindings (default workspace)
|
|
103
|
+
|
|
104
|
+
| Key | Action |
|
|
105
|
+
| --- | --- |
|
|
106
|
+
| `↑`/`↓` | move between clusters and sessions |
|
|
107
|
+
| `Enter` | attach the selected session in the right pane |
|
|
108
|
+
| `b` | open a remote Bash shell for the selected cluster |
|
|
109
|
+
| `t` | create a new empty tmux session on the selected cluster |
|
|
110
|
+
| `f` | fork the selected Codex session into a new tmux session |
|
|
111
|
+
| `e` / `x` | rename / kill the selected session |
|
|
112
|
+
| `o` | hand the session off to a standalone iTerm tab (auto-reconnects) |
|
|
113
|
+
| `r` | refresh all hosts |
|
|
114
|
+
| `Shift+←` | jump back to the sidebar from the remote pane |
|
|
115
|
+
| `q` | close the workspace (remote sessions keep running) |
|
|
116
|
+
|
|
117
|
+
Inside an attached remote tmux session, the remote prefix is `Ctrl-b` as usual; the local workspace uses `Ctrl-a`.
|
|
118
|
+
|
|
119
|
+
### Dashboard keybindings (`--here`)
|
|
120
|
+
|
|
121
|
+
`↑↓` select · `Enter` attach here · `t` new tab · `r` refresh · `p` preview · `q` quit
|
|
122
|
+
|
|
123
|
+
## How it works
|
|
124
|
+
|
|
125
|
+
- Discovery runs `tmux list-panes -a` on every host in parallel over SSH and parses a sentinel-separated format that survives older remote tmux builds.
|
|
126
|
+
- Attaching creates (or reuses) a hidden window in the local `clustermux` tmux session running a supervised `ssh -t host tmux attach-session ...`; the pane is swapped into the visible slot. Killing the workspace only disconnects local SSH clients — remote sessions and their processes keep running.
|
|
127
|
+
- The iTerm handoff moves a session into its own tab and respawns the workspace pane as a placeholder, so you can later pull it back into the workspace.
|
|
128
|
+
|
|
129
|
+
## License
|
|
130
|
+
|
|
131
|
+
[MIT](LICENSE)
|