@mmmbuto/nexuscrew 0.8.16 → 0.8.18

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