@mmmbuto/nexuscrew 0.8.15 → 0.8.17

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.
package/README.md CHANGED
@@ -3,294 +3,66 @@
3
3
  [![npm](https://img.shields.io/npm/v/@mmmbuto/nexuscrew?style=flat-square&logo=npm&color=cb3837)](https://www.npmjs.com/package/@mmmbuto/nexuscrew)
4
4
  [![license](https://img.shields.io/badge/license-Apache--2.0-blue?style=flat-square)](LICENSE)
5
5
  [![node](https://img.shields.io/badge/node-%3E%3D18-339933?style=flat-square&logo=node.js&logoColor=white)](https://nodejs.org)
6
- [![platforms](https://img.shields.io/badge/platforms-linux%20%C2%B7%20macos%20%C2%B7%20android-555?style=flat-square)](#requirements)
7
- [![bind](https://img.shields.io/badge/bind-127.0.0.1%20only-success?style=flat-square)](#access-model--read-this)
8
-
9
- A faithful **browser tmux client**. It attaches to your live tmux sessions over a **real PTY**
10
- and streams them to a mobile-friendly web UI — full color, copy-mode scroll, special keys,
11
- panes, windows. tmux does the work; the browser is just a faithful client.
12
-
13
- > **tmux owns your sessions — NexusCrew attaches.** Since v0.7 it can also *create* new
14
- > sessions and *terminate* generic ones from the UI (protected names are always refused),
15
- > but recovery and persistence remain tmux's job.
16
-
17
- ---
18
-
19
- ## What it is (v0.8.15 "Steady Link")
20
-
21
- - Runs a small server on the host where your tmux sessions live.
22
- - Each attach spawns a real PTY running `tmux attach` and bridges its bytes over a WebSocket
23
- to [xterm.js](https://xtermjs.org) in the browser. **No screenshots, no polling.**
24
- - **Desktop grid** (≥1024px): drag sessions from the sidebar into a tiling column layout —
25
- live terminals side by side, draggable dividers, per-tile composer, layout remembered.
26
- Tiles attach with `ignore-size` so they never resize your real terminals.
27
- - **Ordered Fleet roster**: desktop and mobile share the same per-location model. Local and
28
- every Hydra route are independently collapsible and filterable by all, pinned, active, off,
29
- or technical. Technical tmux sessions stay out of the normal roster until explicitly shown,
30
- and every location count reflects the rows actually displayed. Route-qualified pins keep
31
- priority, while cells can be reordered from the dedicated handle with Pointer Events on
32
- mouse, touch, or pen, or with keyboard move controls. Reorder highlights the destination,
33
- scrolls at list edges, commits only on release and can be cancelled without changing the
34
- saved order. The owner-qualified order survives reloads and is shared by compact and expanded
35
- views. Desktop chrome and the mobile header stay fixed while their lists scroll, and the
36
- compact version/endpoint/language footer remains readable on narrow screens.
37
- - **Attached decks by default**: named workspaces switch as tabs inside the same PWA without
38
- reloading terminals or losing a pending layout save. Use `↗` only when you want to detach a
39
- deck into another browser window or monitor. Every Local or remote owner group ends with its
40
- own compact `+ new`, so the creation destination is explicit and never falls back elsewhere.
41
- A dedicated handle reorders owner-qualified deck tabs with mouse, touch, pen, or keyboard;
42
- the order autosaves locally and survives polling, reloads, rename, and deletion.
43
- - **Federated Hydra inventory**: connect existing NexusCrew installations through the SSH
44
- configuration you already control and see local, direct, and relayed tmux fleets in one UI.
45
- Route labels show where every session lives; creation, attach, files, lifecycle and Fleet
46
- management use the selected location through a scoped single-origin route.
47
- - **One-link node pairing**: paste a link or scan its QR in Settings → Nodes. A complete
48
- link tests SSH, exchanges the one-time invitation, confirms both directions and verifies
49
- the peer automatically; failures identify the exact connection stage. A device already
50
- connected to a hub creates invitations through that hub; a standalone hub asks only for
51
- the SSH address by which the receiving device can reach it. Readiness uses a real bounded
52
- deadline instead of exhausting rapid loopback refusals before a slower mobile SSH handshake
53
- completes. Per-tunnel logs contain safe supervisor lifecycle markers and actionable SSH
54
- errors, never argv, host aliases, key paths, tokens, or credentials.
55
- - **Settings and wizard**: manage roles, nodes, token rotation, and service regeneration
56
- from the UI; the first-run wizard uses the same pairing flow as Settings.
57
- - **Cell lifecycle from the UI**: the primary `+` creates a managed Fleet cell at Local or
58
- any reachable node. Power opens one shared launch sheet where engine, model, permission
59
- policy and boot can be reviewed before every start; deletion lives in Settings → Fleet.
60
- An immediately exiting client reports bounded, redacted diagnostics and cannot leave a
61
- zero-window phantom beside the configured cell.
62
- - **Legacy session adoption**: Settings → Fleet lists managed and unmanaged tmux sessions on
63
- every route. A live unmanaged session can be explicitly imported as a managed cell without
64
- inventing its engine, provider or model.
65
- - **Selective cell and engine backup**: export chosen cells, reusable engine definitions,
66
- engine mapping and system prompts, then select exactly what to restore. Archives contain
67
- credential-variable names but never their values, provider keys or runtime session state;
68
- conflicts and active cells that need a restart are reported explicitly.
69
- - **Private provider credentials**: each node resolves a required key from its runtime
70
- environment, compatible user-owned provider files, or an optional local write-only store.
71
- The PWA can set, replace, or forget a missing key on that exact node without displaying it.
72
- Values never enter Fleet definitions, backups, API responses, tmux state, process arguments,
73
- temporary files, or logs.
74
- - **Rich cards**: last activity, current command, a sanitized one-line preview per session.
75
- - **Fleet control**: a built-in schema-driven fleet manager handles cells, engines, model
76
- selection, and boot persistence; an existing external `fleet` CLI can take ownership through
77
- the documented JSON contract.
78
- - **i18n**: English, Italian, Spanish — follows your browser language, switchable in the UI.
79
- - **localhost-only**: the server binds `127.0.0.1` and refuses any non-loopback bind.
80
- - **Stateless**: tmux *is* the persistence. No database, no accounts.
81
- - **Mobile terminal controls**: long-press begins local text selection, drag extends it, and
82
- the composer sends long or multiline drafts through the terminal's real bracketed-paste
83
- mode while keeping both failed drafts and the software keyboard ready.
84
- - **Desktop file paste/drop**: paste a clipboard image or drop files directly on the target
85
- terminal. NexusCrew uploads them to that session's inbox—locally or through Hydra—and
86
- inserts the saved paths without submitting Enter; ordinary text paste is unchanged.
87
- - **Safe npm auto-update**: global installs follow stable npm `latest` without downgrades,
88
- serialize installation across processes, verify the restarted runtime and roll back once
89
- to the exact previous version if the new server does not become healthy. On Linux, stopping
90
- or restarting the HTTP service preserves the independent shared tmux server and every session.
91
- Registry checks and service processes use a stable NexusCrew working directory, so deleting
92
- the directory from which NexusCrew was originally launched cannot break future updates.
93
- - **Authenticated cell network**: AI cells can discover the owner-qualified Fleet directory
94
- visible through the authorized Hydra topology and submit bounded text to one exact active
95
- destination. Inactive cells remain visible but are never presented as queued recipients;
96
- a `submitted` receipt confirms only paste plus Enter in the target TUI, not that its model
97
- accepted, processed or completed the task.
98
- - **Universal**: a PTY is a PTY — a coding agent, a REPL, a plain shell, anything tmux holds.
99
-
100
- ## Screenshots
6
+ [![platforms](https://img.shields.io/badge/platforms-linux%20%C2%B7%20macos%20%C2%B7%20android-555?style=flat-square)](#platform-support)
101
7
 
102
- <p align="center">
103
- <img src="docs/img/fleet-deck-desktop.png" width="900" alt="NexusCrew desktop: the Fleet Deck grid with three live tmux sessions tiled side by side">
104
- </p>
105
-
106
- The **Fleet Deck** desktop grid (≥1024px): drag sessions into a tiling layout — live
107
- terminals side by side, each a real PTY streamed to the browser.
8
+ NexusCrew is a local-first web control plane for tmux sessions and AI CLI workers. It streams
9
+ real PTYs to a browser, organizes sessions into persistent decks, and connects multiple
10
+ NexusCrew installations through SSH without replacing tmux or your existing SSH setup.
108
11
 
109
12
  <p align="center">
110
- <img src="docs/img/fleet-mobile.gif" width="420" alt="Animated NexusCrew mobile Fleet overview with managed AI cells and direct power controls">
13
+ <img src="docs/img/fleet-deck-desktop.png" width="960" alt="NexusCrew desktop interface with multiple live tmux sessions arranged in a deck">
111
14
  </p>
112
15
 
113
- The mobile Fleet overview keeps managed cells, current engines, activity and direct power
114
- controls in one place. Tapping a live session still attaches through a real PTY.
115
-
116
- ## Fleet integration
117
-
118
- A clean install includes the built-in, schema-driven fleet manager. Its safe defaults contain
119
- four CLI adapters **Claude Code**, **Codex**, **Codex-VL**, and **Pi** — and no cells,
120
- prompts, API keys, or machine-specific paths. Provider, credential-variable name and reusable
121
- engine definitions live in Settings Fleet. When a cell is off, its shared launch sheet lets
122
- you choose the engine, model, permission policy and boot state before starting it; the last
123
- model and permission choice is remembered separately for each cell and engine.
124
-
125
- The concise provider catalog is scoped per CLI:
126
-
127
- - **Claude Code:** Anthropic account, Amazon Bedrock, Google Vertex AI, Microsoft Foundry,
128
- Ollama Cloud, local Ollama, Z.AI, and a renameable Anthropic-compatible endpoint.
129
- - **Codex / Codex-VL:** OpenAI/ChatGPT account, OpenAI API, Ollama Cloud, local Ollama,
130
- LM Studio, and a renameable custom endpoint using the real Responses wire API only.
131
- - **Pi:** its configured default, Anthropic, OpenAI API, OpenAI Codex OAuth, Google Gemini,
132
- GitHub Copilot, OpenRouter, local Ollama, DeepSeek, Z.AI, and a custom provider.
133
-
134
- Provider credentials are resolved from the selected CLI's native login or from an environment
135
- variable named in the PWA. A named variable is read first from the service environment, then
136
- from the optional node-local NexusCrew store, then—when present—from the user-owned
137
- `~/.config/ai-shell/providers.zsh`, `~/.config/keys/ai.env`, or
138
- `~/.config/secure/.env`, parsed strictly as assignment data and never sourced or executed.
139
- The PWA shows only whether the requested name is configured and its source category; a missing
140
- value can be saved locally in `~/.nexuscrew/credentials.json` under a user-owned `0700`
141
- directory and `0600` file, or removed again. The store is write-only through the API and is
142
- never included in config, services, Fleet backups, federation payloads, logs, or responses.
143
- At launch, secret-bearing environment data crosses a private one-shot Unix socket and reaches
144
- the CLI by direct process spawn; it never enters tmux environment state, argv, or a temporary
145
- file. Legacy Z.AI A/P engines remain launch-compatible for existing fleets but are not provider
146
- choices for new engines. Model discovery is used where the CLI/provider documents it, with a
147
- manual model field as the portable fallback.
148
-
149
- Managed engines expose a permission selector both in their definition and in the cell launch
150
- sheet. New Claude engines (native, Z.AI, Ollama, or custom) default to **Bypass permissions**
151
- and launch with `--dangerously-skip-permissions`; choose **Standard permissions** to disable
152
- it. New Codex and Codex-VL engines default to Standard and offer an explicit opt-in for
153
- `--dangerously-bypass-approvals-and-sandbox`. Pi is always launched with its native Standard
154
- permission behavior. Claude-compatible managed models also receive matching context and
155
- auto-compaction window variables, including one-million-token profiles where declared.
156
-
157
- Custom argv-based engines remain supported. Their command, environment, cwd, and prompt are
158
- validated against a strict trust boundary and launched without a shell.
159
-
160
- Settings → Fleet also provides a selective **Cells and engines backup** flow. The v2 JSON file
161
- contains portable cell definitions (cwd, engine choice, model mapping, boot flag and system
162
- prompt) plus only the selected reusable engine definitions. Custom-engine environment-variable
163
- names are portable; their values, provider credentials, PWA tokens and live tmux identifiers
164
- are never exported. Legacy cell-only v1 files remain importable. Restore previews conflicts,
165
- lets you choose each section independently, confirms every overwrite before mutation, preserves
166
- only matching values already configured on the destination, and reports which active cells need
167
- a restart.
168
-
169
- ### External fleet manager
170
-
171
- NexusCrew can instead act as a control panel for a *fleet manager* you already have: any
172
- trusted executable (default `~/.local/bin/fleet`, configurable via `fleet.bin` in
173
- `~/.nexuscrew/config.json`) that answers `fleet status --json` with:
174
-
175
- ```json
176
- {"schemaVersion":1,"kind":"ai-fleet","cells":[
177
- {"cell":"Build","tmuxSession":"work-build","engine":"native",
178
- "active":true,"boot":true,"tmux":true,"rc":"","key":""}],
179
- "engines":[{"id":"native","label":"Claude","rc":true},{"id":"my-engine","label":"My Engine"}]}
16
+ NexusCrew binds to `127.0.0.1`, authenticates the PWA with a local token, and leaves session
17
+ ownership to tmux. It has no hosted control service, user account system, or public network
18
+ listener.
19
+
20
+ ## Overview
21
+
22
+ | Area | What NexusCrew provides |
23
+ |---|---|
24
+ | Terminal | Real PTY attachment to live tmux sessions through WebSocket and xterm.js |
25
+ | Workspaces | Named decks, tiled desktop layouts, mobile session view, saved ordering and pins |
26
+ | Fleet | Reusable cells, engines, providers, models, permission policies, prompts and boot state |
27
+ | Nodes | One-link pairing and owner-qualified routing over supervised OpenSSH connections |
28
+ | Operations | Background service, boot integration, diagnostics, stable npm updates and selective backup |
29
+ | AI integration | A stdio MCP bridge for operator communication, deck discovery and cell-to-cell delivery |
30
+
31
+ The browser is a client, not the session host:
32
+
33
+ ```text
34
+ Browser PWA
35
+ authenticated HTTP + WebSocket on loopback
36
+
37
+ NexusCrew ── real PTY ── tmux sessions
38
+
39
+ ├── supervised OpenSSH ── remote NexusCrew nodes
40
+
41
+ └── stdio MCP bridge ── Claude Code / Codex / Codex-VL / Pi
180
42
  ```
181
43
 
182
- `engines` is optional: it declares the configured engine inventory — `id` is the stable
183
- identifier, `label` is what the UI displays, and `rc: true` marks engines that support your
184
- remote-control path. In external mode the external CLI owns its engine list and configuration;
185
- the NexusCrew power control starts or stops the cell without changing that configuration.
186
-
187
- and accepts `up <Cell> [--engine E] [--boot]`, `down <Cell> [--boot]`, `engine <Cell> <E>`,
188
- `boot|noboot <Cell>`. The binary is trust-checked (regular file, not a symlink, not
189
- world-writable) and the schema is validated strictly — anything else and the feature stays
190
- off. Automatic discovery checks the configured path, Termux's `$PREFIX/bin/fleet`, then
191
- `~/.local/bin/fleet`; startup-service ownership uses the same resolver so built-in and external
192
- boot managers cannot both take ownership. An explicitly pinned external binary fails closed
193
- instead of silently switching to another executable. Set `NEXUSCREW_FLEET=0` to disable Fleet
194
- entirely.
195
-
196
- ## Requirements
197
-
198
- - **Node.js ≥ 18**
199
- - **tmux** on the host (3.4+; the non-destructive `ignore-size` attach is honored on 3.4 and
200
- later)
201
- - **OpenSSH client (`ssh`)** for Hydra nodes and a clean `nexuscrew doctor`. A local-only tmux
202
- session does not invoke it, but the installation is reported degraded until it is present.
203
- `autossh` is detected by doctor but is not required.
204
- - A PTY backend is resolved automatically per platform: Darwin ARM64/x64 and Linux ARM64/x64
205
- scriptless prebuilds, including the native Android ARM64 provider on Termux.
206
-
207
- ## Access model — read this
208
-
209
- NexusCrew binds **only to `127.0.0.1`**. There is no built-in network exposure, no public
210
- tunnel, no TLS, no login server. You reach it by **bringing the loopback port to you over a
211
- channel you control**:
44
+ ## Install
212
45
 
213
- ```bash
214
- # from your laptop/phone, tunnel the loopback port over SSH
215
- ssh -L 41820:127.0.0.1:41820 user@your-host
216
- # then run `nexuscrew show` on the machine where the browser is available
217
- ```
46
+ ### Requirements
47
+
48
+ - Node.js 18 or newer
49
+ - tmux 3.4 or newer
50
+ - OpenSSH client (`ssh`) for node connections and a clean diagnostic result
51
+ - Linux x64/ARM64, macOS x64/ARM64, or Android ARM64 through Termux
218
52
 
219
- A user-managed autossh tunnel or a VPN works the same way. A local **authentication token** (0600 file,
220
- auto-generated and passed directly to the browser by `nexuscrew show`) is a second factor on top of your SSH/VPN gate. The
221
- token travels in the URL **fragment** (`#token=…`), so it never reaches the server logs.
222
-
223
- > **Exposing the app publicly (reverse proxy, network bind, port forward to the internet) is
224
- > unsupported and unsafe.** The whole security model is "localhost + a tunnel you control".
225
-
226
- ## Federated Hydra nodes (configured from the PWA)
227
-
228
- Every installation is always the local node and can join other NexusCrew nodes. The normal
229
- flow stays entirely in the PWA:
230
-
231
- 1. On the installation being shared, open **Settings → Nodes → Invite a node** and create the
232
- ten-minute link/QR. A device already connected to a hub uses that hub automatically.
233
- A standalone hub needs one value: the OpenSSH target or Host alias that the *other device*
234
- uses to reach it. This is not `127.0.0.1` and not a NexusCrew HTTP URL.
235
- 2. On the other device, open its own NexusCrew PWA (`nexuscrew show`), go to
236
- **Settings → Nodes**, and use the first card, **Connect with one link**. Paste the complete
237
- link in the prominent field or scan the QR. Do not navigate to the loopback address in the
238
- link: it is only a portable container for the pairing payload.
239
- 3. A complete v2 link connects automatically. NexusCrew starts a provisional SSH forward,
240
- checks transport readiness, consumes the one-time invite once, negotiates the reciprocal
241
- path, confirms it, and verifies authenticated federation health and peer identity. If a
242
- stage fails, the PWA preserves the link and shows the exact stage, detail and safe retry
243
- guidance. Older v1 links remain accepted and open only the missing routing fields.
244
-
245
- The link never contains an SSH key, identity file, API key or PWA token. Its only credential is
246
- the random, one-time pairing invite; SSH routing fields are non-secret configuration. A
247
- successful pairing creates one supervised SSH connection to the hub. Its normal `-L` channel
248
- is private and provides access to the hub. The optional `-R` channel is added to that same SSH
249
- process only when the user enables **Share this device through the selected hub** in the local
250
- device card. The hub verifies the authenticated reverse channel before advertising the device;
251
- its inbound-node controls then decide whether authorized clients see the whole network,
252
- relay-only or a selected set. Both sides exchange only redacted topology.
253
-
254
- A newly paired phone or laptop is private by default: the hub keeps it in Settings without
255
- probing it as a server or showing a false red error. Share always refers to the current local
256
- device—not to the remote hub card—and uses its already selected hub connection; no direct
257
- peer-to-peer SSH is required. Enabling Share makes it routable and turns authenticated
258
- reverse-channel health into a real requirement; a shared node that stops responding, or a live
259
- endpoint that rejects authentication, remains a real health error.
260
-
261
- NexusCrew does not create SSH keys or edit `authorized_keys`. OpenSSH remains authoritative for
262
- identity files, agents, host keys, ports, ProxyJump and forwarding policy. NexusCrew uses
263
- one built-in retry supervisor around `ssh`; it never nests `autossh`. `nexuscrew doctor` reports
264
- whether both binaries are installed and states that OpenSSH is the transport actually used.
265
- Missing `ssh` is a blocking error; `autossh` is optional. Configured links return at boot.
266
- Pair credentials are random, per-peer and scoped only to the federated session/file surface—the
267
- PWA token never crosses a peer link.
268
-
269
- A relay controls what its peers can see. The default is the whole network; a peer can be reduced
270
- to relay-only or a selected set. HTTP and WebSocket routing enforce that policy at every hop,
271
- with stable instance IDs, cycle rejection and a four-hop ceiling. Session creation, terminal,
272
- files, termination, Fleet editing and authorized cell discovery work on Local or any reachable
273
- route. Previously seen transitive nodes remain listed as offline with their last-seen time while
274
- a relay is down.
275
-
276
- ## Install & run
53
+ NexusCrew ships scriptless PTY prebuilds for the supported targets. A normal global install
54
+ does not need a compiler or native install-script approval.
277
55
 
278
56
  ### Linux
279
57
 
58
+ Install Node.js, tmux and OpenSSH with your distribution package manager, then:
59
+
280
60
  ```bash
281
- # Install Node.js 18+, tmux 3.4+ and OpenSSH with your package manager first.
282
61
  npm install -g @mmmbuto/nexuscrew
283
62
  nexuscrew
284
63
  ```
285
64
 
286
- The first run creates a loopback-only configuration and starts a detached process. Run
287
- `nexuscrew boot` only if you want a persistent `systemd --user` service. The generated unit
288
- waits for `network-online.target`; `nexuscrew doctor` also warns when user lingering is disabled,
289
- because boot without an interactive login then depends on the host's systemd policy. Linux x64
290
- and ARM64 use platform PTY prebuilds only, so global installs do not compile native code or
291
- require install-script approval.
292
-
293
- ### macOS (Apple Silicon or Intel)
65
+ ### macOS
294
66
 
295
67
  ```bash
296
68
  brew install node tmux
@@ -298,12 +70,7 @@ npm install -g @mmmbuto/nexuscrew
298
70
  nexuscrew
299
71
  ```
300
72
 
301
- The first run starts a detached process. Run `nexuscrew boot` to install a user LaunchAgent
302
- with an explicit Node/Homebrew PATH. The npm package selects the matching Darwin ARM64 or x64
303
- PTY prebuild. NexusCrew is an npm/Node CLI, not an `.app`, `.pkg`, or standalone Mach-O
304
- distribution, so it does not require Developer ID signing.
305
-
306
- ### Android / Termux (ARM64)
73
+ ### Android / Termux
307
74
 
308
75
  ```bash
309
76
  pkg update
@@ -312,118 +79,215 @@ npm install -g @mmmbuto/nexuscrew
312
79
  nexuscrew
313
80
  ```
314
81
 
315
- Termux uses the Android ARM64 PTY provider. The normal command starts NexusCrew in the
316
- background and exits. `nexuscrew boot` installs the Termux:Boot script explicitly; install the
317
- Termux:Boot app and launch it once, because Android app activation cannot be verified by the
318
- CLI. `nexuscrew doctor` reports that limitation even when the script itself is valid. Inside
319
- managed cells, npm-installed Codex and Codex-VL scripts are launched through the active Node
320
- executable when their shebang depends on the unavailable `/usr/bin/env`; native executables
321
- such as Pi remain direct launches.
82
+ The first run creates the loopback-only runtime, starts it in the background, opens the PWA,
83
+ and presents the setup wizard. Later runs reuse the configured service, print a compact status,
84
+ and exit.
322
85
 
323
- On every platform the first run starts the server in the background and opens the PWA wizard.
324
- After onboarding, the same command starts or reuses it, prints a compact status and guide, and
325
- exits:
86
+ The preferred port is `41820`. If another process owns it, NexusCrew selects the next free
87
+ loopback port and records the result.
326
88
 
327
- ```bash
328
- nexuscrew # background start; opens only on first run
329
- nexuscrew show # background start when needed + open the authenticated PWA
330
- nexuscrew show token # print the clickable authenticated URL; do not open a browser
331
- nexuscrew status # compact service, port and hub-connection state
332
- nexuscrew stop # stop server/tunnels; preserve every tmux session
333
- nexuscrew restart # restart server safely; restore autostart hub links, preserve tmux
334
- nexuscrew boot # opt in to startup persistence
335
- nexuscrew boot off # disable startup persistence, keep the current run alive
89
+ ## CLI
90
+
91
+ The CLI deliberately stays small. Configuration and routine lifecycle work belong in the PWA.
92
+
93
+ | Command | Purpose |
94
+ |---|---|
95
+ | `nexuscrew` | Start or reuse the background runtime and print a short status |
96
+ | `nexuscrew show` | Start when needed and open the authenticated PWA |
97
+ | `nexuscrew show token` | Print the authenticated browser link without opening it |
98
+ | `nexuscrew status` | Show service, port, role and node status |
99
+ | `nexuscrew stop` | Stop NexusCrew and its managed tunnels without stopping tmux sessions |
100
+ | `nexuscrew restart` | Restart NexusCrew and restore autostart node links without stopping tmux |
101
+ | `nexuscrew boot` | Enable startup persistence |
102
+ | `nexuscrew boot off` | Disable startup persistence while leaving the current runtime alive |
103
+ | `nexuscrew doctor` | Check Node, PTY, tmux, SSH, service and platform integration |
104
+ | `nexuscrew help` | Show command help |
105
+ | `nexuscrew version` | Show the installed version |
106
+
107
+ Boot integration uses a user systemd service on Linux, a LaunchAgent on macOS, and a
108
+ Termux:Boot script on Android. Termux users must install the Termux:Boot app and open it once;
109
+ the CLI can validate the script but cannot prove Android app activation.
110
+
111
+ ## Fleet: cells, engines and providers
112
+
113
+ A **cell** is a reusable worker definition: tmux session name, working directory, engine,
114
+ model, permission policy, optional system prompt and boot state. Starting a stopped cell opens
115
+ the same launch sheet on desktop and mobile, so the effective settings can be reviewed before
116
+ the process starts.
117
+
118
+ An **engine** describes how a CLI is launched. Clean installations include four base adapters:
119
+
120
+ - Claude Code
121
+ - Codex
122
+ - Codex-VL
123
+ - Pi
124
+
125
+ The provider catalog is scoped to the selected CLI rather than to a machine-specific setup:
126
+
127
+ | CLI | Built-in provider choices |
128
+ |---|---|
129
+ | Claude Code | Anthropic, Amazon Bedrock, Google Vertex AI, Microsoft Foundry, Ollama Cloud, local Ollama, Z.AI, custom Anthropic-compatible endpoint |
130
+ | Codex / Codex-VL | OpenAI or ChatGPT login, OpenAI API, Ollama Cloud, local Ollama, LM Studio, custom OpenAI Responses endpoint |
131
+ | Pi | Native default, Anthropic, OpenAI API, Codex OAuth, Gemini, GitHub Copilot, OpenRouter, Ollama, DeepSeek, Z.AI, custom provider |
132
+
133
+ Custom Codex-compatible endpoints use the real Responses wire API; NexusCrew does not silently
134
+ fall back to Chat Completions. Custom argv-based engines are also supported and are launched
135
+ directly without a shell after trust-boundary validation.
136
+
137
+ Permission handling is explicit per cell and engine:
138
+
139
+ - Claude engines can use standard permissions or `--dangerously-skip-permissions`.
140
+ - Codex and Codex-VL can use standard permissions or
141
+ `--dangerously-bypass-approvals-and-sandbox`.
142
+ - Pi uses its native permission behavior.
143
+
144
+ Provider keys are resolved on the node that launches the process. NexusCrew can use the
145
+ service environment, compatible user-owned provider files, or an optional node-local
146
+ write-only credential store. The PWA reports whether a variable is configured but never
147
+ returns its value. Keys are excluded from Fleet definitions, backups, API responses, tmux
148
+ state, process arguments, temporary files and logs.
149
+
150
+ ### External fleet manager
151
+
152
+ The built-in Fleet manager can be replaced by a trusted executable, configured as `fleetBin`
153
+ in `~/.nexuscrew/config.json`. The executable must be a regular, non-world-writable file and
154
+ must return the documented `schemaVersion: 1`, `kind: "ai-fleet"` JSON from
155
+ `fleet status --json`. It owns cell and engine configuration and must accept:
156
+
157
+ ```text
158
+ up <Cell> [--engine E] [--boot]
159
+ down <Cell> [--boot]
160
+ engine <Cell> <E>
161
+ boot <Cell>
162
+ noboot <Cell>
336
163
  ```
337
164
 
338
- The preferred port is `41820`. If it is occupied by another process, NexusCrew selects the
339
- next free loopback port and updates its configuration. If the configured port already hosts
340
- the same authenticated NexusCrew instance, it is reused.
165
+ Invalid binaries or schemas fail closed. Set `NEXUSCREW_FLEET=0` to disable Fleet entirely.
341
166
 
342
- Env knobs: `NEXUSCREW_PORT` (default 41820), `NEXUSCREW_CONFIG_FILE`,
343
- `NEXUSCREW_TOKEN_FILE`, `NEXUSCREW_FILES_ROOT`, `NEXUSCREW_TMUX`,
344
- `NEXUSCREW_FLEET=0`, `NEXUSCREW_READONLY=1`, and `NEXUSCREW_AUTO_UPDATE=0` to disable
345
- automatic stable npm updates. Set `NEXUSCREW_DEBUG=1` to log the resolved PTY provider at
346
- startup.
347
-
348
- ### Automatic updates
349
-
350
- A global npm installation checks `@mmmbuto/nexuscrew@latest` shortly after startup and then
351
- periodically. A newer stable version is installed exactly once, preflighted through the CLI,
352
- and the active service or detached runtime is restarted on the same loopback port. If the new
353
- runtime fails its bounded health check, NexusCrew reinstalls the exact previous version and
354
- restarts once; that failed version is then blocked from automatic retry. The updater never
355
- accepts a prerelease from `latest`, never downgrades, and redacts registry credentials and local
356
- paths from PWA errors. Registry commands run from a stable directory owned by NexusCrew and
357
- accept npm's JSON scalar or plain semantic-version output. Its current state and manual
358
- check/apply controls live in Settings → System. Set `NEXUSCREW_AUTO_UPDATE=0` (or `false`,
359
- `no`, `off`) to disable scheduling.
360
-
361
- On Linux, the installed service uses `KillMode=process`: service lifecycle affects NexusCrew,
362
- not the shared tmux server. Existing units are protected by an atomic drop-in before any CLI or
363
- auto-update restart; if systemd cannot apply that guard, the restart fails closed. `nexuscrew
364
- doctor` reports the effective runtime `KillMode`.
167
+ ## Workspaces and terminal behavior
365
168
 
366
- ## CLI
169
+ Desktop decks place multiple live terminals in a saved tiled layout. Decks remain attached to
170
+ the current PWA by default; `↗` detaches one into another browser window. Session and deck order
171
+ can be changed with pointer drag-and-drop or keyboard controls and is saved automatically.
367
172
 
173
+ On mobile, locations are independently collapsible and filterable by all, pinned, active, off,
174
+ or technical sessions. The same owner-qualified ordering model is used by compact and expanded
175
+ desktop views.
176
+
177
+ <p align="center">
178
+ <img src="docs/img/fleet-mobile.gif" width="420" alt="NexusCrew mobile Fleet view with managed cells and session controls">
179
+ </p>
180
+
181
+ Terminal attachment uses `tmux attach -f ignore-size` by default. A phone or narrow browser
182
+ therefore cannot resize a session held by another terminal client. Mobile controls expose
183
+ copy-mode scrolling, window and pane navigation, Escape, Ctrl-C and detach. Long text and
184
+ multiline prompts use the terminal application's bracketed-paste mode; clipboard images and
185
+ dropped files are stored in the selected session inbox and their paths are inserted without
186
+ submitting Enter.
187
+
188
+ ## Connect nodes through SSH
189
+
190
+ Every installation starts as a local node. A node joins another NexusCrew installation with a
191
+ single pairing link or QR code:
192
+
193
+ 1. On the reachable installation, open **Settings → Nodes → Invite a node**.
194
+ 2. Provide the OpenSSH target that the other device can use, such as `user@host` or a local
195
+ SSH config alias. SSH ports, identities, agents, ProxyJump and host-key policy stay in the
196
+ user's OpenSSH configuration.
197
+ 3. On the joining device, open **Settings → Nodes**, paste the complete pairing link, and choose
198
+ **Test and connect**. The link is a pairing payload; it is not a browser address to open.
199
+ 4. If the portable address cannot select the correct key, open **Advanced / edit** and replace
200
+ it with the SSH alias that already works from that device.
201
+
202
+ NexusCrew creates one supervised `ssh` process for the hub connection and proves the forwarded
203
+ TCP endpoint before reporting success. It does not generate SSH keys, edit `authorized_keys`,
204
+ or use `autossh` as a hidden second supervisor.
205
+
206
+ Newly joined devices are private by default. Enabling **Share this device through the selected
207
+ hub** adds a verified reverse channel to the existing SSH process. The hub then decides whether
208
+ authorized peers see the whole network, only the hub, or an explicit subset. Clients do not
209
+ need direct SSH reachability to one another.
210
+
211
+ Pairing links contain a short-lived one-time invite and routing fields, but no SSH private key,
212
+ provider key or PWA token. Node and deck identities remain owner-qualified across the network,
213
+ and every routed HTTP or WebSocket request rechecks authorization, hop count and cycle rules.
214
+
215
+ ## Access and security model
216
+
217
+ NexusCrew listens only on `127.0.0.1`. To use a remote installation, bring its loopback port to
218
+ your device through SSH or a VPN you control:
219
+
220
+ ```bash
221
+ ssh -L 41820:127.0.0.1:41820 user@your-host
368
222
  ```
369
- nexuscrew background start; first run opens the PWA wizard
370
- nexuscrew show start when needed and open the authenticated PWA
371
- nexuscrew show token print the clickable authenticated URL without opening it
372
- nexuscrew boot enable startup at boot (`boot off|status` are also available)
373
- nexuscrew doctor local diagnostics (exit 1 when a required check fails)
374
- nexuscrew help concise command help
375
- nexuscrew version installed version
376
- ```
377
223
 
378
- All configuration and lifecycle operations live in the PWA. Internal service-manager and MCP
379
- entry points are intentionally not part of the public CLI workflow. The token is never printed
380
- by normal startup, help, doctor, or service output.
224
+ Then open the authenticated link returned by `nexuscrew show token`. The token is stored in a
225
+ user-only file and travels in the URL fragment (`#token=...`), so it is not sent in the initial
226
+ HTTP request or written to server access logs.
227
+
228
+ The security boundary is intentionally narrow:
229
+
230
+ - loopback bind only; non-loopback binds are rejected
231
+ - local bearer token for every API and WebSocket connection
232
+ - tmux remains the session authority
233
+ - OpenSSH remains the network and identity authority
234
+ - provider credentials remain on the node that uses them
235
+ - file operations reject traversal and symlink escapes
236
+ - Fleet and federation mutations are schema-validated and ACL-checked
237
+
238
+ Direct public exposure through a reverse proxy, public port forward or network bind is not a
239
+ supported deployment model.
240
+
241
+ ## Backup and updates
242
+
243
+ Settings → Fleet can export and restore selected cells, system prompts and reusable engine
244
+ definitions. Restore previews conflicts, supports per-item selection and reports active cells
245
+ that need a restart. Archives contain credential variable names, never credential values,
246
+ tokens or live tmux state.
247
+
248
+ Global npm installations can follow the stable `latest` tag automatically. NexusCrew serializes
249
+ updates, verifies the new CLI and same-port runtime, and rolls back once to the exact previous
250
+ version if health checks fail. It never installs prereleases from `latest` or downgrades. Update
251
+ state and manual controls are available in Settings → System; set
252
+ `NEXUSCREW_AUTO_UPDATE=0` to disable the scheduler.
253
+
254
+ On Linux, generated user services use `KillMode=process` so restarting NexusCrew does not stop
255
+ the shared tmux server. Lifecycle commands fail closed when that protection cannot be verified.
381
256
 
382
257
  ## MCP bridge
383
258
 
384
- `nexuscrew mcp` runs a minimal **stdio MCP server** (JSON-RPC 2.0, one JSON message per
385
- line, zero SDK dependencies) that brings NexusCrew *inside* your AI sessions. An agent
386
- running in a tmux session gets eight tools: the cell→human channel, read-only deck context,
387
- and an authenticated active-cell network:
388
-
389
- - `nc_notify {title, body?, urgency?}` human notification: toast on every open UI +
390
- web push on subscribed devices (enable push from Settings System).
391
- - `nc_ask {question, options?}` asks a question and **returns immediately**; the answer
392
- you type in the UI is pasted back into the caller's tmux session as
393
- `[human reply · ask#<id>] <text>` by default (configurable with
394
- `NEXUSCREW_REPLY_LABEL`; bracketed paste, never submits).
395
- - `nc_send_file {path, caption?}` copies a file (absolute path under HOME) into the
396
- session outbox: badge + notification, downloadable from the Files panel.
397
- - `nc_deck {}` — identifies the caller's tmux session and node, then returns every local or
398
- authorized shared-owner deck that contains it. Deck identity is owner-qualified; members
399
- include stable owner ID, Fleet cell name (when managed), exact tmux session and the Hydra
400
- route valid from the caller. Unavailable members remain visible with `cell: null`.
401
- - `nc_cells {}` — returns the owner-qualified Fleet directory visible through the caller's
402
- authorized, non-stale Hydra topology. Every entry has a stable `<instanceId>:<cell>` ID,
403
- exact tmux session and route, activity state and `canReceive`; duplicate cell names on
404
- different devices remain unambiguous.
405
- - `nc_send_cell {to, message}` — submits bounded text to one exact ID returned by `nc_cells`.
406
- The caller must itself be an active local Fleet cell, the destination must still be active,
407
- and every remote hop rechecks identity and ACL. There is no silent offline queue. A
408
- `submitted` receipt means only that bracketed paste and a separate Enter reached the target
409
- TUI; it does not mean accepted, working or completed.
410
- - `nc_status {}` / `nc_inbox {}` — read-only: live sessions + fleet cells / inbox files.
411
-
412
- The caller's identity is the tmux session name (`$TMUX` → `tmux display-message`), with
413
- `NEXUSCREW_MCP_SESSION` as fallback for non-tmux contexts. The bridge talks to the local
414
- HTTP API (loopback + token from `~/.nexuscrew/token`). Use `nc_deck` for visual workspace
415
- neighbours and `nc_cells` for the global authorized directory; use `nc_send_cell` for managed
416
- cell delivery. Direct tmux injection is only a declared same-host compatibility or repair
417
- fallback and must never bypass Fleet membership or Hydra ACLs. Never scrape `decks.json`
418
- directly.
419
-
420
- Register it in **Claude Code** (`.mcp.json` in your project root, or `~/.claude.json`):
259
+ `nexuscrew mcp` exposes the local authenticated runtime as a dependency-free stdio MCP server.
260
+ It is intended for AI sessions running inside managed tmux cells.
261
+
262
+ | Tool | Purpose |
263
+ |---|---|
264
+ | `nc_notify` | Send a PWA notification to the operator |
265
+ | `nc_ask` | Ask a non-blocking question and return the answer to the calling session |
266
+ | `nc_send_file` | Place a file from the caller's home in its downloadable outbox |
267
+ | `nc_status` | Read live tmux and Fleet status |
268
+ | `nc_inbox` | List files received by the caller |
269
+ | `nc_deck` | Discover owner-qualified decks containing the calling tmux session |
270
+ | `nc_cells` | List authorized active and inactive Fleet cells across visible nodes |
271
+ | `nc_send_cell` | Submit bounded text to one exact active cell returned by `nc_cells` |
272
+
273
+ Cell delivery uses bracketed paste followed by a separate Enter. A `submitted` receipt confirms
274
+ delivery to the target TUI, not acceptance or completion by its model. There is no silent
275
+ offline queue.
276
+
277
+ Register the bridge in Claude Code:
421
278
 
422
279
  ```json
423
- { "mcpServers": { "nexuscrew": { "command": "nexuscrew", "args": ["mcp"] } } }
280
+ {
281
+ "mcpServers": {
282
+ "nexuscrew": {
283
+ "command": "nexuscrew",
284
+ "args": ["mcp"]
285
+ }
286
+ }
287
+ }
424
288
  ```
425
289
 
426
- …and in **codex** (`~/.codex/config.toml`):
290
+ Or in Codex / Codex-VL:
427
291
 
428
292
  ```toml
429
293
  [mcp_servers.nexuscrew]
@@ -431,43 +295,63 @@ command = "nexuscrew"
431
295
  args = ["mcp"]
432
296
  ```
433
297
 
434
- ## Mobile KeyBar
298
+ The caller is resolved from its tmux session. `NEXUSCREW_MCP_SESSION` is available only as an
299
+ explicit fallback for non-tmux contexts.
300
+
301
+ ## Configuration
435
302
 
436
- The awkward tmux gestures, as buttons: **scroll** (enters copy-mode; then PgUp/↑/↓, `q` to
437
- exit), **window** prev/next, **pane** left/right, **esc**, **Ctrl-C**, **detach**.
303
+ Runtime state is local to the current user:
438
304
 
439
- Long-press terminal text to enter local selection mode, then drag and use **Copy**. The
440
- composer send button writes the text followed by a real Enter while retaining textarea focus,
441
- so the mobile keyboard stays open between messages.
305
+ | Path | Contents |
306
+ |---|---|
307
+ | `~/.nexuscrew/config.json` | Port, Fleet mode and runtime options |
308
+ | `~/.nexuscrew/token` | Local PWA bearer token |
309
+ | `~/.nexuscrew/credentials.json` | Optional node-local write-only provider store |
310
+ | `~/.nexuscrew/tunnels/` | Managed SSH supervisor state and owner-only logs |
311
+ | `~/NexusFiles/<session>/` | Per-session inbox and outbox |
442
312
 
443
- Window and pane navigation run as **server-side, allowlisted tmux commands** on the active
444
- session they are *not* emulated with client-side prefix keys, which are fragile and depend
445
- on each host's key bindings.
313
+ Common environment overrides include `NEXUSCREW_PORT`, `NEXUSCREW_CONFIG_FILE`,
314
+ `NEXUSCREW_TOKEN_FILE`, `NEXUSCREW_FILES_ROOT`, `NEXUSCREW_TMUX`,
315
+ `NEXUSCREW_FLEET=0`, `NEXUSCREW_READONLY=1`, `NEXUSCREW_AUTO_UPDATE=0`, and
316
+ `NEXUSCREW_DEBUG=1`.
317
+
318
+ ## Platform support
446
319
 
447
- ## Non-destructive by default (`ignore-size`)
320
+ | Platform | Architectures | Background integration | PTY provider |
321
+ |---|---|---|---|
322
+ | Linux | x64, ARM64 | systemd user service or detached runtime | packaged native prebuild |
323
+ | macOS | x64, ARM64 | LaunchAgent or detached runtime | packaged native prebuild |
324
+ | Android / Termux | ARM64 | detached runtime and optional Termux:Boot | Android ARM64 package |
448
325
 
449
- Multiple clients on one tmux session share the window geometry. To avoid a small phone
450
- shrinking the window for the real terminal you also have attached, NexusCrew attaches with
451
- `-f ignore-size` by default: **the browser never resizes a session that a real terminal is
452
- holding.** On a screen smaller than the session you'll see a clipped view (expected). Pass
453
- `takeSize` only when you deliberately want the browser to drive the size.
326
+ Run `nexuscrew doctor` after installation or when moving a configuration between devices. A
327
+ missing OpenSSH client is a blocking diagnostic; `autossh` is reported separately and remains
328
+ optional because NexusCrew supervises OpenSSH directly.
454
329
 
455
- ## Develop
330
+ ## Development
456
331
 
457
332
  ```bash
458
- npm test # node --test on a private tmux socket (never the operator's server)
459
- npm run build # builds the frontend into frontend/dist
333
+ npm test # isolated Node tests plus frontend tests
334
+ npm run build # build the PWA into frontend/dist
460
335
  node bin/nexuscrew.js serve
461
336
  ```
462
337
 
338
+ Tests that exercise tmux use private sockets and must never attach to or terminate the
339
+ operator's tmux server.
340
+
341
+ ## Roadmap
342
+
343
+ The next architectural track is an optional MCP gateway: one NexusCrew MCP endpoint with a
344
+ local catalog of upstream MCP servers and explicit, per-tool federation through shared nodes.
345
+ Credentials and execution would remain on the owner node, with owner-qualified tool identities
346
+ and read/mutate ACLs. This gateway is planned work and is **not part of the current release**.
347
+
348
+ See [CHANGELOG.md](CHANGELOG.md) for released changes.
349
+
463
350
  ## Status
464
351
 
465
- The current release candidate is **v0.8.15**. npm **`latest`** is promoted from the verified
466
- artifact first; the GitHub tag and release follow the operator field test from the same source
467
- candidate.
352
+ The current stable release is **v0.8.17**. npm `latest`, the GitHub tag and the release use the
353
+ same audited package artifact.
468
354
 
469
355
  ## License
470
356
 
471
357
  Apache-2.0 © 2026 Davide A. Guglielmi (DioNanos)
472
-
473
- *Per aspera ad astra.*