@mmmbuto/nexuscrew 0.8.36 → 0.8.37

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,578 +3,139 @@
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)](#platform-support)
6
+ [![platforms](https://img.shields.io/badge/platforms-linux%20%C2%B7%20macos%20%C2%B7%20android-555?style=flat-square)](#platforms)
7
7
 
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.
8
+ **Your tmux fleet. Everywhere.**
9
+
10
+ NexusCrew turns live tmux sessions, AI CLI workers and connected machines into
11
+ one local-first browser control plane. Your terminals stay real, your tools
12
+ stay yours, and your infrastructure stays under your control.
11
13
 
12
14
  <p align="center">
13
- <img src="docs/img/fleet-deck-desktop.png" width="960" alt="NexusCrew desktop interface with multiple live tmux sessions arranged in a deck">
15
+ <img src="docs/img/fleet-deck-desktop.png" width="960" alt="NexusCrew desktop deck with multiple live tmux sessions">
14
16
  </p>
15
17
 
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, boot state and live working status |
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
42
- ```
43
-
44
- ## Install
45
-
46
- ### Requirements
18
+ ## One control plane. Every screen.
47
19
 
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
20
+ The desktop deck keeps the whole fleet visible. Open any cell from a phone and
21
+ NexusCrew gives the same live tmux session a touch-first terminal without
22
+ moving the session away from its host.
52
23
 
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.
55
-
56
- ### Linux
57
-
58
- Install Node.js, tmux and OpenSSH with your distribution package manager, then:
59
-
60
- ```bash
61
- npm install -g @mmmbuto/nexuscrew
62
- nexuscrew
63
- ```
64
-
65
- ### macOS
66
-
67
- ```bash
68
- brew install node tmux
69
- npm install -g @mmmbuto/nexuscrew
70
- nexuscrew
71
- ```
24
+ <p align="center">
25
+ <img src="docs/img/session-mobile.png" width="360" alt="NexusCrew mobile terminal connected to a real tmux session with touch controls">
26
+ <br>
27
+ <sub><strong>Real tmux on mobile.</strong> Terminal keys, dictation and file handoff stay within reach.</sub>
28
+ </p>
72
29
 
73
- ### Android / Termux
30
+ ## Install in 30 seconds
74
31
 
75
32
  ```bash
76
- pkg update
77
- pkg install nodejs-lts tmux openssh
78
33
  npm install -g @mmmbuto/nexuscrew
79
34
  nexuscrew
80
35
  ```
81
36
 
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.
85
-
86
- On Android, `nexuscrew doctor` also verifies the Termux execution bridge used by current app
87
- builds. NexusCrew carries forward only a validated `libtermux-exec` preload from the active
88
- Termux prefix; arbitrary loader injection remains excluded from Fleet environments.
37
+ The first run creates a loopback-only runtime, starts it in the background and
38
+ opens the authenticated PWA.
89
39
 
90
- Package upgrades self-repair installed Termux:Boot scripts before the runtime or Fleet can
91
- create tmux from a replaceable npm directory. NexusCrew also discards a tunnel pidfile when
92
- Android has reused its PID under another app UID; it never signals that foreign process and
93
- restarts only the configured OpenSSH supervisor. These repairs preserve the local port, token,
94
- pairing data and existing boot on/off choice.
40
+ | Platform | Prerequisites |
41
+ |---|---|
42
+ | Linux | Node.js 18+, tmux 3.4+, OpenSSH |
43
+ | macOS | `brew install node tmux` |
44
+ | Android / Termux | `pkg install nodejs-lts tmux openssh` |
95
45
 
96
- The preferred port is `41820`. If another process owns it, NexusCrew selects the next free
97
- loopback port and records the result.
46
+ NexusCrew ships scriptless PTY prebuilds for Linux x64/ARM64, macOS x64/ARM64
47
+ and Android ARM64. A normal global install does not need a compiler or native
48
+ install-script approval.
98
49
 
99
- ## CLI
50
+ [Full installation guide →](docs/INSTALLATION.md)
100
51
 
101
- The PWA remains the visual control surface, while the CLI exposes the complete peer workflow for
102
- headless hosts and VPS installations.
52
+ ## What NexusCrew gives you
103
53
 
104
- | Command | Purpose |
105
- |---|---|
106
- | `nexuscrew` | Start or reuse the background runtime and print a short status |
107
- | `nexuscrew init [--dry-run] [--port PORT]` | Initialize missing local stores idempotently or preview the operation |
108
- | `nexuscrew show` | Start when needed and open the authenticated PWA |
109
- | `nexuscrew show token` | Print the authenticated browser link without opening it |
110
- | `nexuscrew status` | Show service, port, role and node status |
111
- | `nexuscrew stop` | Stop NexusCrew and its managed tunnels without stopping tmux sessions |
112
- | `nexuscrew restart` | Restart NexusCrew and restore autostart node links without stopping tmux |
113
- | `nexuscrew boot` | Enable startup persistence |
114
- | `nexuscrew boot off` | Disable startup persistence while leaving the current runtime alive |
115
- | `nexuscrew doctor` | Check Node, PTY, tmux, SSH, service and platform integration |
116
- | `nexuscrew nodes list [--json]` | List direct hubs, connected clients and routed read-only peers |
117
- | `nexuscrew nodes inspect <name\|nodeId>` | Inspect a peer by stable identity |
118
- | `nexuscrew nodes edit <name\|nodeId> ...` | Change the canonical label or direction-specific connection settings |
119
- | `nexuscrew nodes up\|down\|connect\|disconnect\|restart\|reconnect <name\|nodeId>` | Manage a direct node link without requiring the PWA |
120
- | `nexuscrew nodes share <name\|nodeId> on\|off` | Publish or withdraw a direct node from the authorized network |
121
- | `nexuscrew nodes remove <name\|nodeId> --yes` | Revoke/forget a direct peer after explicit confirmation |
122
- | `nexuscrew nodes invite --ssh <target>` | Create a one-time pairing link from a headless hub |
123
- | `nexuscrew nodes pair\|join` | Read a one-time pairing link from stdin and join headlessly |
124
- | `nexuscrew help` | Show command help |
125
- | `nexuscrew version` | Show the installed version |
126
-
127
- Boot integration uses a user systemd service on Linux, a LaunchAgent on macOS, and a
128
- Termux:Boot script on Android. Termux users must install the Termux:Boot app and open it once;
129
- the CLI can validate the script but cannot prove Android app activation.
130
-
131
- Cells marked `boot:true` are started when that platform boot integration runs. This is startup
132
- persistence, not a watchdog for the tmux server itself: if the entire tmux server disappears
133
- later, the boot companion is not automatically rerun.
134
-
135
- ## Fleet: cells, engines and providers
136
-
137
- A **cell** is a reusable worker definition: tmux session name, working directory, engine,
138
- model, permission policy, optional system prompt, optional Shell command and boot state. Starting
139
- a stopped cell opens the same launch sheet on desktop and mobile, so the effective settings can
140
- be reviewed before the process starts.
141
-
142
- An **engine** describes how a CLI is launched. Clean installations include these base adapters:
143
-
144
- - Claude Code
145
- - Codex
146
- - Codex-VL
147
- - Pi
148
- - Agy — Linux and macOS only (auth delegated to Agy's local login; `standard`/`unsafe` permission policies). On Android/Termux use the Shell adapter with a per-cell `agy` command.
149
- - Shell
150
-
151
- The provider catalog is scoped to the selected CLI rather than to a machine-specific setup:
152
-
153
- | CLI | Built-in provider choices |
54
+ | | |
154
55
  |---|---|
155
- | Claude Code | Anthropic, Alibaba Token Plan Personal, OpenRouter, Kimi Code, Amazon Bedrock, Google Vertex AI, Microsoft Foundry, Ollama Cloud, local Ollama, Z.AI, custom Anthropic-compatible endpoint |
156
- | Codex | OpenAI or ChatGPT login, OpenAI API, Ollama Cloud, local Ollama, LM Studio, custom OpenAI Responses endpoint |
157
- | Codex-VL | OpenAI or ChatGPT login, OpenAI API, Alibaba Token Plan Personal, OpenRouter, Ollama Cloud, local Ollama, LM Studio, custom OpenAI Responses endpoint |
158
- | Pi | Native default, Anthropic, OpenAI API, Alibaba Token Plan Personal, Codex OAuth, Gemini, GitHub Copilot, OpenRouter, Ollama, DeepSeek, Z.AI, custom provider |
159
- | Shell | Device-local interactive shell, with an optional per-cell command |
160
-
161
- Custom Codex-compatible endpoints use the real Responses wire API; NexusCrew does not silently
162
- fall back to Chat Completions. Custom argv-based engines are also supported and are launched
163
- directly without a shell after trust-boundary validation.
164
-
165
- The Shell engine resolves `$SHELL` or a trusted platform shell when the cell starts; executable
166
- paths are not stored in Fleet definitions or backups. Leaving its command empty opens an
167
- interactive login shell. A configured command is passed as one opaque argument through the
168
- private launch broker, runs once without restart supervision, and then leaves the cell stopped.
169
- Known POSIX shells use an interactive login invocation (`-lic`) so the user's configured PATH is
170
- available; custom shells retain the conservative `-lc` contract. Shell does not accept prompts,
171
- models or unsafe permission policy.
172
-
173
- OpenRouter is first-class for Claude Code and Codex-VL. Claude uses OpenRouter's Anthropic
174
- Messages compatibility endpoint, while Codex-VL uses the beta, stateless Responses endpoint
175
- with direct command-based authentication and no shell. Because provider/model compatibility can
176
- change independently, the selected OpenRouter model remains explicit. The packaged Kimi K3
177
- profile pins its one-million-token metadata instead of falling back to a smaller generic window.
178
-
179
- Kimi Code is a separate Claude Code provider for Kimi membership keys. It defaults to `k3[1m]`,
180
- uses `https://api.kimi.com/coding/`, and runs with an isolated Claude configuration so a native
181
- Anthropic account remains untouched. A Kimi Code membership key is not interchangeable with a
182
- Moonshot pay-as-you-go API key.
183
-
184
- Alibaba Token Plan Personal is a separate managed profile for Claude Code, Codex-VL and Pi. It
185
- uses only `ALIBABA_CODE_API_KEY`, defaults to `qwen3.8-max-preview`, and has no OpenAI or
186
- pay-as-you-go fallback. The npm package also includes the portable `alibaba-token-media` skill
187
- for dry-run-first Wan image/edit and HappyHorse video workflows. Claude Code, Codex, Codex-VL
188
- and Pi can invoke its dependency-free Python CLI directly; Pi is not assumed to support MCP
189
- natively. The media skill requires Python 3. Media generation always requires explicit Credit
190
- consent and never runs during installation, tests, or startup.
191
-
192
- The package also includes the portable [`fill-forms`](skills/fill-forms/SKILL.md) skill for
193
- inspecting, filling and visually validating local PDF and DOCX forms. It supports named
194
- AcroForm fields, coordinate overlays, checkboxes, character boxes and explicitly authorised
195
- signature images. Its scripts never install dependencies automatically, never overwrite the
196
- blank source and do not send documents anywhere. Canonical instructions are in English while
197
- user-facing guidance follows the user's language; field values and document wording are not
198
- translated without an explicit request. Optional Python dependencies are not bundled and remain
199
- subject to their own licences.
200
-
201
- Permission handling is explicit per cell and engine:
202
-
203
- - Claude engines can use standard permissions or `--dangerously-skip-permissions`.
204
- - Codex and Codex-VL can use standard permissions or
205
- `--dangerously-bypass-approvals-and-sandbox`.
206
- - Pi uses its native permission behavior.
207
-
208
- Provider keys are resolved on the node that launches the process. NexusCrew can use the
209
- service environment, compatible user-owned provider files, or an optional node-local
210
- write-only credential store. The PWA reports whether a variable is configured but never
211
- returns its value. Keys are excluded from Fleet definitions, backups, API responses, tmux
212
- state, process arguments, temporary files and logs.
213
-
214
- Built-in providers with a fixed variable expose a dedicated **KEY** section in the engine editor.
215
- It shows only the variable name, configured source and affected engines on the selected node.
216
- Replacing or removing a shared key warns which engines use it; the entered value is transient in
217
- the browser and is written only to the node-local credential store.
218
-
219
- ### Built-in Fleet ownership
220
-
221
- NexusCrew is the only Fleet manager. Cell and engine definitions, lifecycle, boot ownership,
222
- restart supervision and write-only credentials are all handled by the built-in runtime; no
223
- external `fleet` executable is discovered or invoked. `nexuscrew-fleet.service` is the optional
224
- NexusCrew boot companion and starts only cells marked `boot:true`.
225
-
226
- Set `NEXUSCREW_FLEET=0` to disable Fleet entirely.
227
-
228
- ## Workspaces and terminal behavior
229
-
230
- Desktop decks place multiple live terminals in a saved tiled layout. Decks remain attached to
231
- the current PWA by default; `↗` detaches one into another browser window. Session and deck order
232
- can be changed with pointer drag-and-drop or keyboard controls and is saved automatically.
233
-
234
- The top deck bar groups workspaces by owner node. Clicking a node name expands or collapses its
235
- decks; newly seen nodes start collapsed so connected-but-idle machines remain available without
236
- occupying the bar. Every deck carries a compact activity dot, and collapse choices are stored in
237
- the current browser and synchronized across its open NexusCrew windows.
238
-
239
- On mobile, locations are independently collapsible and filterable by all, pinned, active, off,
240
- or technical sessions. The same owner-qualified ordering model is used by compact and expanded
241
- desktop views. Managed terminals use the logical Fleet cell name as their visible title; tmux
242
- session and route identifiers remain technical context rather than the primary heading.
56
+ | **Live terminals** | Attach to real tmux sessions through a real PTY, WebSocket and xterm.js. |
57
+ | **Persistent workspaces** | Arrange sessions into decks with saved layouts, ordering, pins and per-cell drafts. |
58
+ | **Multi-node Fleet** | See and control authorized cells across Linux, macOS and Android nodes. |
59
+ | **AI-ready cells** | Launch Claude Code, Codex, Codex-VL, Pi, Agy or a trusted shell with explicit providers and policies. |
60
+ | **Mobile-native control** | Scroll tmux history, use terminal keys, dictate prompts and move files from a phone. |
61
+ | **Operator alerts** | Receive visual, push and optional on-device spoken notifications. |
243
62
 
244
- <p align="center">
245
- <img src="docs/img/fleet-mobile.gif" width="420" alt="NexusCrew mobile Fleet view with managed cells and session controls">
246
- </p>
247
-
248
- Terminal attachment uses `tmux attach -f ignore-size` by default. A phone or narrow browser
249
- therefore cannot resize a session held by another terminal client. Mobile controls expose
250
- copy-mode scrolling, window and pane navigation, Escape, Ctrl-C and detach. Long text and
251
- multiline prompts use the terminal application's bracketed-paste mode; clipboard images and
252
- dropped files are stored in the selected session inbox and their paths are inserted without
253
- submitting Enter.
254
-
255
- The two-row mobile key bar can also show a full-height Enter key beside Page Up/Page Down, so
256
- interactive terminal choices can be confirmed without opening the software keyboard. By default,
257
- key-bar and speech-to-text actions keep that keyboard closed, while a nearby double tap inside the
258
- terminal or a direct tap in the composer textarea explicitly opens it. The composer send button
259
- and the composer history/size controls work without focusing the textarea. **Settings → Input** can change the
260
- terminal gesture, hide the Enter key, or allow key-bar and voice actions to retain the keyboard.
261
- The key bar also has a
262
- **compact** layout (one row with an expand toggle that temporarily reveals the full key set
263
- without changing the preference). Mobile finger drags always browse tmux history, including when
264
- the attached TUI uses an alternate screen; desktop wheel events in writable alternate-screen TUIs
265
- remain application-owned Page Up/Page Down, while normal and readonly terminals use tmux scroll.
266
- These preferences are browser-local and are synchronized between open NexusCrew windows for
267
- the same origin.
268
-
269
- The input composer can expand for longer prompts. Each owner-qualified tmux cell keeps its own
270
- draft, size preference and bounded prompt history in the current browser, including safe
271
- ArrowUp/ArrowDown recall at textarea boundaries. This browser-local state is not federated or
272
- included in Fleet backups and can be cleared from Settings → System.
273
-
274
- ## Notifications and optional spoken alerts
275
-
276
- Live cell notifications appear as in-app toasts and can also use Web Push when that browser and
277
- operating system support it. Push delivery remains best-effort and requires the browser permission;
278
- on iOS it also requires an installed PWA. The service worker cannot synthesize speech, so a hidden
279
- or closed PWA uses only its normal system-notification path.
280
-
281
- **Settings → System → Read notifications aloud** adds browser-local speech for new live
282
- notifications. It is off by default, remains editable when server settings are read-only, uses the
283
- device's system voice in the current UI language, and sends no notification text to a speech
284
- service. Enabling it runs an audible test. NexusCrew reports success only after the browser emits
285
- both speech start and end; if the native engine stays silent or errors, the UI reports that voice
286
- is unavailable. Credential-shaped values and private home paths are redacted before speech. The
287
- test must succeed once per page session, including after a reload.
288
-
289
- Speech runs only while that document is visible and has operating-system focus. Blur, background,
290
- opt-out and unmount cancel the current utterance and clear pending work; skipped notifications are
291
- not replayed when focus returns. Duplicate live frames are suppressed for 60 seconds, at most two
292
- normal alerts remain pending, and a high-urgency alert interrupts the current queue. A 30-second
293
- watchdog cancels a stuck browser utterance and advances to the next alert.
294
-
295
- Focus provides one speaker among NexusCrew windows on the same device. Two separately opted-in
296
- devices may both speak when each PWA is visible and focused; this is intentional for a per-device
297
- preference. Spoken alerts are optional and do not replace the toast's accessibility status, so
298
- screen-reader users can leave speech disabled if their assistive technology already announces it.
299
- Depending on the operating system, an enabled Web Push notification may still coexist with the
300
- visible toast and spoken alert.
301
-
302
- ## Connect nodes through SSH
303
-
304
- Every installation starts as a local node. A node joins another NexusCrew installation with a
305
- single pairing link or QR code:
306
-
307
- 1. On the reachable installation, open **Settings → Nodes → Invite a node**.
308
- 2. Provide the OpenSSH target that the other device can use, such as `user@host` or a local
309
- SSH config alias. SSH ports, identities, agents, ProxyJump and host-key policy stay in the
310
- user's OpenSSH configuration.
311
- 3. On the joining device, open **Settings → Nodes**, paste the complete pairing link, and choose
312
- **Test and connect**. The link is a pairing payload; it is not a browser address to open.
313
- 4. If the portable address cannot select the correct key, open **Advanced / edit** and replace
314
- it with the SSH alias that already works from that device.
315
-
316
- Advanced settings keep the local display label separate from the local route handle. The route
317
- defaults to a readable slug plus a stable node-ID suffix, so devices that all report the hostname
318
- `localhost` still receive distinct handles. If a hub reports a collision, NexusCrew applies its
319
- deterministic suggestion and lets the device retry with the same invitation.
320
-
321
- NexusCrew creates one supervised `ssh` process for the hub connection and proves the forwarded
322
- TCP endpoint before reporting success. It does not generate SSH keys, edit `authorized_keys`,
323
- or use `autossh` as a hidden second supervisor.
324
-
325
- Newly joined devices are private by default. Enabling **Share this device through the selected
326
- hub** adds a verified reverse channel to the existing SSH process. The hub then decides whether
327
- authorized peers see the whole network, only the hub, or an explicit subset. Clients do not
328
- need direct SSH reachability to one another.
329
-
330
- Reverse ports are reserved across active and pending pairings, probed before use and protected
331
- by a persistent uniqueness check. Share is stored as desired state: failed activation rolls back
332
- to private. Deactivation first saves private intent, then asks the hub to withdraw the node over
333
- the still-live private forward, and only after that acknowledgement removes the reverse channel.
334
- If the hub cannot acknowledge the revocation, Settings refreshes to the saved private state and
335
- shows that hub reconciliation is still pending; bounded boot retries continue without claiming
336
- that remote removal already completed. A stale same-name peer or a late allocation collision
337
- returns an actionable conflict instead of silently creating a duplicate record or consuming the
338
- invitation.
339
-
340
- Private pairing is administrative inventory, not operational publication. A paired client can
341
- remain listed as **private** in Settings so it can be reconnected or shared again, but it is absent
342
- from routable topology, owner/deck bars and MCP cell/deck discovery. Temporary loss of reachability
343
- does not revoke consent: an authorized node remains visible as stale/offline until a successful
344
- authoritative refresh either restores it or confirms its withdrawal.
345
-
346
- The Share control reports desired publication separately from verified tunnel reachability. If a
347
- detached process survives an upgrade with stale `-R` arguments, **Reconnect and reconcile** applies
348
- the current checkbox state without changing consent and replaces only the verified NexusCrew
349
- supervisor when its saved command differs. The checkbox itself remains usable while disconnected.
350
-
351
- OpenSSH key restrictions still apply after global `AllowTcpForwarding` is enabled. A shared client
352
- needs its accepted hub key to allow the exact negotiated reverse listener, for example
353
- `permitlisten="127.0.0.1:44002"`; the actionable tunnel diagnostic prints the actual required port.
354
- NexusCrew never edits `authorized_keys`, so this policy remains an explicit hub-operator action.
355
-
356
- Node groups can be reordered independently in each browser from both desktop and mobile lists.
357
- Their human-readable label has one server-backed source: rename from Settings or a roster and the
358
- same canonical label appears everywhere without changing the technical route name, node identity,
359
- credentials, Share state or deck identity.
360
-
361
- For routed nodes that the current installation does not own, Settings → Nodes offers a local
362
- alias instead of a remote rename. The alias is private to the viewing installation, follows the
363
- stable instance identity and never changes or federates the remote label, route or owner.
364
-
365
- Pairing links contain a short-lived one-time invite and routing fields, but no SSH private key,
366
- provider key or PWA token. Node and deck identities remain owner-qualified across the network,
367
- and every routed HTTP or WebSocket request rechecks authorization, hop count and cycle rules.
368
-
369
- ## Access and security model
370
-
371
- NexusCrew listens only on `127.0.0.1`. To use a remote installation, bring its loopback port to
372
- your device through SSH or a VPN you control:
63
+ The browser is a client, not the session host:
373
64
 
374
- ```bash
375
- ssh -L 41820:127.0.0.1:41820 user@your-host
65
+ ```text
66
+ Browser PWA
67
+ │ authenticated HTTP + WebSocket on loopback
68
+
69
+ NexusCrew ── real PTY ── tmux sessions
70
+
71
+ ├── supervised OpenSSH ── remote NexusCrew nodes
72
+
73
+ └── stdio MCP bridge ── AI CLI workers
376
74
  ```
377
75
 
378
- Then open the authenticated link returned by `nexuscrew show token`. The token is stored in a
379
- user-only file and travels in the URL fragment (`#token=...`), so it is not sent in the initial
380
- HTTP request or written to server access logs.
381
-
382
- The security boundary is intentionally narrow:
383
-
384
- - loopback bind only; non-loopback binds are rejected
385
- - local bearer token for every API and WebSocket connection
386
- - tmux remains the session authority
387
- - OpenSSH remains the network and identity authority
388
- - provider credentials remain on the node that uses them
389
- - file operations reject traversal and symlink escapes
390
- - Fleet and federation mutations are schema-validated and ACL-checked
391
-
392
- Direct public exposure through a reverse proxy, public port forward or network bind is not a
393
- supported deployment model.
394
-
395
- ## Backup and updates
76
+ ## Local-first by design
396
77
 
397
- Settings Fleet can export and restore selected cells, system prompts and reusable engine
398
- definitions. Restore previews conflicts, supports per-item selection and reports active cells
399
- that need a restart. Current archives store working directories relative to the target user's
400
- home instead of copying device-specific absolute paths. A legacy or foreign path is shown as an
401
- explicit repair action and is never silently remapped. Archives contain credential variable
402
- names, never credential values, tokens or live tmux state.
78
+ NexusCrew has no hosted control service, required account or public listener.
79
+ It binds to `127.0.0.1`, authenticates the PWA with a local token and leaves
80
+ session ownership to tmux.
403
81
 
404
- Global npm installations can follow the stable `latest` tag automatically. NexusCrew serializes
405
- updates, verifies the new CLI and same-port runtime, and rolls back once to the exact previous
406
- version if health checks fail. It never installs prereleases from `latest` or downgrades. Update
407
- state and manual controls are available in Settings → System; set
408
- `NEXUSCREW_AUTO_UPDATE=0` to disable the scheduler.
82
+ - OpenSSH remains the network and identity authority.
83
+ - Provider credentials stay on the node that uses them.
84
+ - Pairing links contain no SSH private key, provider key or PWA token.
85
+ - File operations reject traversal and symlink escapes.
86
+ - Updates preserve tmux sessions and roll back when health checks fail.
409
87
 
410
- On Linux, generated user services use `KillMode=process` so restarting NexusCrew does not stop
411
- the shared tmux server. Lifecycle commands fail closed when that protection cannot be verified.
88
+ Remote access is intentionally carried through SSH or a VPN you control:
412
89
 
413
- ## Structured diagnostics
414
-
415
- Settings → Diagnostics shows a bounded in-memory event buffer for the local installation or an
416
- authorized routed node. Verbose collection is explicit and expires after 5, 15, 30 or 60 minutes;
417
- operational warnings and errors remain available when verbose mode is off. The view supports
418
- level/component filtering, pause, autoscroll, copy, JSON export and explicit clear.
419
-
420
- Records are structured and redacted before storage. Raw terminal content, prompts, command lines,
421
- environment values, tokens, credentials and filesystem paths are not accepted as diagnostic
422
- metadata. Fleet launch failures include only closed `code` and `phase` values so preflight,
423
- broker, tmux, readiness and client-spawn failures can be distinguished safely. The buffer is not
424
- a reader for service journals or log files.
425
-
426
- ## MCP bridge
427
-
428
- `nexuscrew mcp` exposes the local authenticated runtime as a dependency-free stdio MCP server.
429
- It is intended for AI sessions running inside managed tmux cells.
430
-
431
- | Tool | Purpose |
432
- |---|---|
433
- | `nc_notify` | Send a PWA notification to the operator |
434
- | `nc_ask` | Ask a non-blocking question and return the answer to the calling session |
435
- | `nc_send_file` | Place a file from the caller's home in its downloadable outbox |
436
- | `nc_status` | Read live tmux and Fleet status |
437
- | `nc_inbox` | List files received by the caller |
438
- | `nc_deck` | Discover owner-qualified decks containing the calling tmux session |
439
- | `nc_cells` | List authorized active and inactive Fleet cells across visible nodes |
440
- | `nc_cell_diagnostics` | Read the redacted Shell command and latest bounded start/spawn failure for one exact local cell |
441
- | `nc_send_cell` | Submit bounded text to one exact active cell returned by `nc_cells` |
442
- | `nc_identity` | Read-only identity diagnostics; callable with no session and no token |
443
-
444
- Cell delivery uses bracketed paste followed by a separate Enter. A `submitted` receipt confirms
445
- delivery to the target TUI, not acceptance or completion by its model. There is no silent
446
- offline queue.
447
-
448
- `nc_identity` returns only non-sensitive data: the `source` the caller was resolved from
449
- (`tmux`, `NEXUSCREW_MCP_SESSION`, or `missing`), boolean presence of the identity env vars,
450
- a stable `code` (`OK`, `NEXUSCREW_MCP_IDENTITY_MISSING`, `NEXUSCREW_MCP_IDENTITY_INVALID`) and
451
- a remediation hint. It never calls an HTTP API or reads the token, so it works even when the
452
- identity is missing — use it to diagnose why the identity-gated tools fail closed.
453
-
454
- Register the bridge in Claude Code:
455
-
456
- ```json
457
- {
458
- "mcpServers": {
459
- "nexuscrew": {
460
- "command": "nexuscrew",
461
- "args": ["mcp"]
462
- }
463
- }
464
- }
465
- ```
466
-
467
- Or in Codex / Codex-VL (`env_vars` allowlists variable **names** only — no values are copied
468
- into the CLI or config file):
469
-
470
- ```toml
471
- [mcp_servers.nexuscrew]
472
- command = "nexuscrew"
473
- args = ["mcp"]
474
- env_vars = ["NEXUSCREW_MCP_SESSION", "TMUX", "TMUX_PANE"]
90
+ ```bash
91
+ ssh -L 41820:127.0.0.1:41820 user@your-host
475
92
  ```
476
93
 
477
- The equivalent CLI form on a Codex-VL build that supports `--env-var` (allowlist by name, repeated):
94
+ [Security model →](docs/SECURITY.md)
478
95
 
479
- ```text
480
- codex-vl mcp add nexuscrew \
481
- --env-var NEXUSCREW_MCP_SESSION \
482
- --env-var TMUX \
483
- --env-var TMUX_PANE \
484
- -- nexuscrew mcp
485
- ```
96
+ ## Documentation
486
97
 
487
- The caller is resolved, in order, from its tmux session (`tmux display-message -p '#S'`),
488
- then from the `NEXUSCREW_MCP_SESSION` fallback, then not at all. Codex/Codex-VL launch MCP stdio
489
- processes with a cleared environment, so those clients must explicitly allowlist the identity
490
- env vars for the server to observe them; otherwise the identity-gated tools (`nc_ask`, `nc_send_file`,
491
- `nc_deck`, `nc_cell_diagnostics`, `nc_send_cell`, `nc_inbox`) stay fail-closed with a stable
492
- `NEXUSCREW_MCP_IDENTITY_*` code, while `nc_notify` degrades to an unknown sender.
493
-
494
- `nc_cell_diagnostics` accepts an exact owner-qualified ID returned by `nc_cells`, but only when
495
- that target belongs to the local node and the caller is an active local Fleet cell. It does not
496
- query remote nodes or add commands to the federated directory. The returned command is bounded
497
- and credential-redacted; the failure is a closed `{status, code, phase}` cause rather than raw
498
- stderr, paths, environment values, prompts or tokens.
499
-
500
- ## Optional MCP companions
501
-
502
- NexusCrew can work alongside separate local-first MCP servers for durable
503
- structured memory, searchable document memory, bounded worker delegation and
504
- mail access. They are optional projects rather than hidden NexusCrew
505
- dependencies: the AI should discover its existing tools first, recommend a
506
- companion only for a capability the user actually requested, and ask before
507
- installing or changing client configuration.
508
-
509
- See [MCP_COMPANIONS.md](MCP_COMPANIONS.md) for the capability guide and
510
- [`mcp-companions.json`](mcp-companions.json) for the machine-readable catalog.
511
- The npm package also includes generic [`memory`](skills/memory/SKILL.md),
512
- [`vl-msa`](skills/vl-msa/SKILL.md), [`crew`](skills/crew/SKILL.md) and
513
- [`mail-assistant`](skills/mail-assistant/SKILL.md) skills. Their instructions
514
- are written in English, while user-facing output follows the user's explicit
515
- preference or request language; Mail reply drafts follow the email thread by
516
- default.
517
-
518
- `fill-forms` is a separate bundled local document skill, not an MCP companion.
519
- It is documented in [Fleet: cells, engines and providers](#fleet-cells-engines-and-providers)
520
- and carries no automatic installation or external-service behaviour.
521
-
522
- ## Configuration
523
-
524
- Runtime state is local to the current user:
525
-
526
- | Path | Contents |
98
+ | Guide | Covers |
527
99
  |---|---|
528
- | `~/.nexuscrew/config.json` | Port, Fleet mode and runtime options |
529
- | `~/.nexuscrew/token` | Local PWA bearer token |
530
- | `~/.nexuscrew/credentials.json` | Optional node-local write-only provider store |
531
- | `~/.nexuscrew/tunnels/` | Managed SSH supervisor state and owner-only logs |
532
- | `~/NexusFiles/<session>/` | Per-session inbox and outbox |
533
-
534
- Common environment overrides include `NEXUSCREW_PORT`, `NEXUSCREW_CONFIG_FILE`,
535
- `NEXUSCREW_TOKEN_FILE`, `NEXUSCREW_FILES_ROOT`, `NEXUSCREW_TMUX`,
536
- `NEXUSCREW_FLEET=0`, `NEXUSCREW_READONLY=1`, `NEXUSCREW_AUTO_UPDATE=0`, and
537
- `NEXUSCREW_DEBUG=1`.
538
-
539
- ## Platform support
540
-
541
- | Platform | Architectures | Background integration | PTY provider |
542
- |---|---|---|---|
543
- | Linux | x64, ARM64 | systemd user service or detached runtime | packaged native prebuild |
544
- | macOS | x64, ARM64 | LaunchAgent or detached runtime | packaged native prebuild |
545
- | Android / Termux | ARM64 | detached runtime and optional Termux:Boot | Android ARM64 package |
546
-
547
- Run `nexuscrew doctor` after installation or when moving a configuration between devices. A
548
- missing OpenSSH client is a blocking diagnostic; `autossh` is reported separately and remains
549
- optional because NexusCrew supervises OpenSSH directly. The doctor also verifies that the service
550
- and shared tmux server have a resolvable stable working directory. On Termux it reports whether
551
- the tmux server inherited a trusted `termux-exec` preload; it never kills a stale server or user
552
- sessions automatically.
100
+ | [Documentation index](docs/README.md) | Start here for every guide |
101
+ | [Installation](docs/INSTALLATION.md) | Linux, macOS, Termux, first run and upgrades |
102
+ | [Fleet and terminals](docs/FLEET.md) | Cells, engines, providers, decks and mobile input |
103
+ | [Connect nodes](docs/NODES.md) | Pairing, SSH routes, sharing and routed aliases |
104
+ | [Notifications](docs/NOTIFICATIONS.md) | Toasts, Web Push and optional spoken alerts |
105
+ | [MCP bridge](docs/MCP.md) | Operator tools, cell delivery and client setup |
106
+ | [Configuration](docs/CONFIGURATION.md) | Files, environment overrides and local settings |
107
+ | [Operations](docs/OPERATIONS.md) | CLI, boot, backup, updates and diagnostics |
108
+ | [Security](docs/SECURITY.md) | Trust boundaries, tokens and credential handling |
109
+
110
+ The repository also includes [MCP companion guidance](MCP_COMPANIONS.md),
111
+ the machine-readable [`mcp-companions.json`](mcp-companions.json), and portable
112
+ skills for memory, searchable document memory, bounded worker delegation,
113
+ mail assistance and form filling.
114
+
115
+ ## Platforms
116
+
117
+ | Platform | Architectures | Background integration |
118
+ |---|---|---|
119
+ | Linux | x64, ARM64 | systemd user service or detached runtime |
120
+ | macOS | x64, ARM64 | LaunchAgent or detached runtime |
121
+ | Android / Termux | ARM64 | detached runtime and optional Termux:Boot |
122
+
123
+ Run `nexuscrew doctor` after installation or when moving configuration between
124
+ devices.
553
125
 
554
126
  ## Development
555
127
 
556
128
  ```bash
557
- npm test # isolated Node tests plus frontend tests
558
- npm run build # build the PWA into frontend/dist
129
+ npm test
130
+ npm run build
559
131
  node bin/nexuscrew.js serve
560
132
  ```
561
133
 
562
- Tests that exercise tmux use private sockets and must never attach to or terminate the
563
- operator's tmux server.
564
-
565
- ## Roadmap
566
-
567
- The current companion catalog is documentation and agent guidance only. A future optional MCP
568
- gateway could expose one NexusCrew endpoint with explicit, per-tool federation through shared
569
- nodes. Credentials and execution would remain on the owner node, with owner-qualified tool
570
- identities and read/mutate ACLs. The gateway is planned work and is **not part of this release**.
134
+ Tests that exercise tmux use private sockets and never attach to or terminate
135
+ the operator's tmux server.
571
136
 
572
137
  See [CHANGELOG.md](CHANGELOG.md) for released changes.
573
138
 
574
- ## Status
575
-
576
- The current stable release is **v0.8.36** on npm and GitHub.
577
-
578
139
  ## License
579
140
 
580
141
  Apache-2.0 © 2026 Davide A. Guglielmi (DioNanos)