Skip to content

Commit f3c922d

Browse files
fab-uleuhclaude
andcommitted
feat: replace tmux/ttyd with built-in PTY multiplexer
Replace the tmux + ttyd terminal architecture with a native PTY multiplexer built into the server binary. This eliminates two external dependencies and enables a unified WebSocket protocol for terminal panes across web, mobile, and CLI. Key changes: - Add nomadflow-pty crate with PTY actor, pane manager, snapshot system, and binary WS protocol - Add multiplexed pane WebSocket route and REST pane endpoints - Add Unix socket listener for local CLI attach - Replace WebView-based terminal on mobile with bundled HTML + typed message protocol bridge - Migrate web dashboard to xterm.js with shared WS context hook - Add file tree browser (web + mobile) and syntax highlighting - Add Basic Auth support with WWW-Authenticate header - Remove tmux, ttyd, and session picker dependencies - Add language toggle (en/fr), voice dictation on mobile - CWD-based agent state tracking (replaces session-ID based) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent cdca327 commit f3c922d

106 files changed

Lines changed: 9684 additions & 7308 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/build-setup.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,4 @@
77
with:
88
version: 9
99
- name: Build web dashboard
10-
run: cd nomadflowcode && pnpm install --frozen-lockfile && npx expo export --platform web
10+
run: cd nomadflowcode && pnpm install --frozen-lockfile && pnpm run build:terminal-html && npx expo export --platform web

.github/workflows/release.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,7 @@ jobs:
136136
with:
137137
"version": 9
138138
- name: "Build web dashboard"
139-
run: "cd nomadflowcode && pnpm install --frozen-lockfile && npx expo export --platform web"
139+
run: "cd nomadflowcode && pnpm install --frozen-lockfile && pnpm run build:terminal-html && npx expo export --platform web"
140140
- name: Install dist
141141
run: ${{ matrix.install_dist.run }}
142142
# Get the dist-manifest

Makefile

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ bump:
1212
if [ -z "$$VERSION" ]; then echo "Aborted."; exit 1; fi && \
1313
echo "Updating to $$VERSION..." && \
1414
sed -i '' 's/"version": "[0-9]*\.[0-9]*\.[0-9]*"/"version": "'$$VERSION'"/' nomadflowcode/app.json && \
15-
sed -i '' 's/"runtimeVersion": "[0-9]*\.[0-9]*\.[0-9]*"/"runtimeVersion": "'$$VERSION'"/' nomadflowcode/app.json && \
1615
sed -i '' 's/"version": "[0-9]*\.[0-9]*\.[0-9]*"/"version": "'$$VERSION'"/' nomadflowcode/package.json && \
1716
sed -i '' 's/"version": "[0-9]*\.[0-9]*\.[0-9]*"/"version": "'$$VERSION'"/' docs/package.json && \
1817
for f in nomadflow-rs/Cargo.toml \

README.md

Lines changed: 17 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
**Code from anywhere — mobile terminal & workflow manager for nomad developers**
44

5-
NomadFlow is an open-source platform that turns your phone into a full development environment. A single Rust binary manages git worktrees, tmux sessions, and a web terminal, while the React Native app lets you seamlessly switch between projects from your pocket.
5+
NomadFlow is an open-source platform that turns your phone into a full development environment. A single Rust binary manages git worktrees, Rust-native PTY sessions, and a real-time terminal, while the React Native app lets you seamlessly switch between projects from your pocket.
66

77
![License](https://img.shields.io/badge/license-MIT-blue.svg)
88
![Platform](https://img.shields.io/badge/platform-iOS%20%7C%20Android-lightgrey.svg)
@@ -12,27 +12,28 @@ NomadFlow is an open-source platform that turns your phone into a full developme
1212

1313
### Instant Workflow
1414
- **3-step selection**: Server → Repo → Feature → Terminal ready
15-
- **Zero manual commands**: environment auto-configured with git worktrees + tmux
15+
- **Zero manual commands**: environment auto-configured with git worktrees
1616
- **Branch management**: create, switch, and manage branches from your phone
1717

1818
### Mobile App
1919
- **iOS & Android** via React Native / Expo
20-
- **Integrated terminal** powered by ttyd with WebSocket proxy
21-
- **Session persistence** via tmux — reconnect where you left off
20+
- **Integrated terminal** powered by xterm.js with multiplexed binary protocol
21+
- **Session persistence**: Rust-native PTY multiplexer keeps your terminal sessions alive
2222
- **Command shortcuts**: quick bar with customizable terminal commands
2323
- **Deep linking**: connect to a server via `nomadflowcode://connect?url=...&secret=...`
2424

2525
### Server (Single Rust Binary)
2626
- **All-in-one**: HTTP API + TUI wizard + daemon mode in one binary
2727
- **Interactive TUI**: ratatui-based wizard to manage servers, repos, and features
28+
- **Rust-native PTY**: high-performance terminal multiplexing without external dependencies
2829
- **Daemon mode**: `nomadflow start` / `nomadflow stop` for background operation
2930
- **Graceful shutdown**: no orphan processes on Ctrl+C or SIGTERM
3031
- **Public tunnels**: expose your server via `--public` with automatic subdomain routing
3132

3233
### Secure Connection
3334
- **Shared secret authentication**: single secret protects both API and terminal
34-
- **Bearer + Basic Auth**: API uses Bearer token, terminal uses Basic Auth (same secret)
35-
- **WebSocket proxy**: terminal WS goes through the server (handles iOS WKWebView auth)
35+
- **Bearer token**: all communication is secured via Bearer token
36+
- **Multiplexed WebSocket**: multiple terminal panes over a single secure connection
3637

3738
## Screenshots
3839

@@ -103,11 +104,8 @@ nomadflow web --port 4000
103104
nomadflow start
104105
nomadflow stop
105106

106-
# Display tmux and daemon status
107+
# Display server status
107108
nomadflow --status
108-
109-
# Attach directly to a tmux window
110-
nomadflow attach <window>
111109
```
112110

113111
### Configuration
@@ -121,12 +119,6 @@ version = 1
121119
[paths]
122120
base_dir = "~/.nomadflowcode"
123121

124-
[tmux]
125-
session = "nomadflow"
126-
127-
[ttyd]
128-
port = 7681
129-
130122
[api]
131123
port = 8080
132124

@@ -166,14 +158,14 @@ pnpm run ios # or: pnpm run android
166158
│ │ /api/list-repos /api/list-features /health │ │
167159
│ │ /api/create-feature /api/switch-feature │ │
168160
│ │ /api/clone-repo /api/list-branches │ │
169-
│ │ /terminal (proxy) /terminal/ws (WS proxy) │ │
161+
│ │ /ws/panes (multiplexed WebSocket) │ │
170162
│ └──────────────────────┬───────────────────────────┘ │
171163
│ │ │
172164
│ ┌──────────────────────▼───────────────────────────┐ │
173-
│ │ ttyd + tmux │ │
165+
│ │ Rust-native PTY Multiplexer │ │
174166
│ │ ┌─────────┐ ┌─────────┐ ┌─────────┐ │ │
175-
│ │ │ repo: │ │ repo: │ │ repo: │ ... │ │
176-
│ │ │feature-a│ │feature-b│ │ main │ │ │
167+
│ │ │ Pane: │ │ Pane: │ │ Pane: │ ... │ │
168+
│ │ │repo/feat│ │repo/feat│ │ main │ │ │
177169
│ │ └────┬────┘ └────┬────┘ └────┬────┘ │ │
178170
│ └───────┼────────────┼────────────┼────────────────┘ │
179171
│ ▼ ▼ ▼ │
@@ -194,7 +186,7 @@ NomadFlowCode/
194186
├── nomadflow-rs/ # Rust binary (single binary: server + TUI)
195187
│ ├── src/main.rs # Entry point, CLI args, daemon mode
196188
│ ├── crates/
197-
│ │ ├── nomadflow-core/ # Config, models, shell, git/tmux/ttyd services
189+
│ │ ├── nomadflow-core/ # Config, models, shell, git services
198190
│ │ ├── nomadflow-server/ # Axum HTTP server with auth middleware
199191
│ │ ├── nomadflow-tui/ # Ratatui TUI wizard
200192
│ │ ├── nomadflow-relay/ # Standalone relay server for tunnel routing
@@ -209,8 +201,6 @@ NomadFlowCode/
209201

210202
### Server
211203
- macOS or Linux
212-
- **tmux** (terminal multiplexer)
213-
- **ttyd** (web terminal)
214204
- **Git** with worktree support
215205

216206
### Mobile
@@ -224,7 +214,7 @@ NomadFlowCode/
224214

225215
NomadFlow uses a single shared secret that protects both:
226216
- **REST API**: via Bearer token (`Authorization: Bearer <secret>`)
227-
- **Terminal**: via Basic Auth (user: `nomadflow`, password: `<secret>`)
217+
- **Terminal**: via token in WebSocket upgrade query param
228218

229219
**Setup:**
230220

@@ -261,8 +251,9 @@ MIT License — see [LICENSE](LICENSE) for details.
261251

262252
## Acknowledgements
263253

264-
- [ttyd](https://github.com/tsl0922/ttyd) — Web terminal
265-
- [tmux](https://github.com/tmux/tmux) — Terminal multiplexer
254+
- [xterm.js](https://xtermjs.org/) — Web terminal frontend
255+
- [pty-process](https://github.com/alacritty/pty-process) — Rust PTY handling
256+
- [alacritty_terminal](https://github.com/alacritty/alacritty) — Terminal state machine
266257
- [axum](https://github.com/tokio-rs/axum) — Rust web framework
267258
- [ratatui](https://github.com/ratatui/ratatui) — Terminal UI framework
268259
- [bore](https://github.com/ekzhang/bore) — TCP tunnel

docs/app/(home)/page.tsx

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ export default function HomePage() {
4343
NomadFlow
4444
</h1>
4545
<p className="text-base lg:text-lg text-fd-muted-foreground mb-6 lg:mb-8 text-center">
46-
Manage git worktrees and tmux sessions from your phone. A single Rust
46+
Manage git worktrees and PTY sessions from your phone. A single Rust
4747
binary that runs on your server, paired with a mobile app for on-the-go
4848
development.
4949
</p>
@@ -110,7 +110,7 @@ export default function HomePage() {
110110
</div>
111111
<h3 className="font-semibold mb-2">Single Binary</h3>
112112
<p className="text-sm text-fd-muted-foreground">
113-
One Rust binary ships the HTTP server, WebSocket proxy, and TUI
113+
One Rust binary ships the HTTP server, PTY multiplexer, and TUI
114114
wizard. No Node.js, no Docker required.
115115
</p>
116116
</div>
@@ -120,8 +120,8 @@ export default function HomePage() {
120120
</div>
121121
<h3 className="font-semibold mb-2">Mobile Terminal</h3>
122122
<p className="text-sm text-fd-muted-foreground">
123-
Full terminal access from your phone via ttyd. Browse repos, switch
124-
features, and code anywhere.
123+
Full terminal access from your phone via native PTY. Browse repos,
124+
switch features, and code anywhere.
125125
</p>
126126
</div>
127127
<div className="border border-fd-border rounded-xl p-5 bg-fd-card transition-colors hover:border-[#5336E2]/40">
@@ -130,8 +130,8 @@ export default function HomePage() {
130130
</div>
131131
<h3 className="font-semibold mb-2">Git Worktrees</h3>
132132
<p className="text-sm text-fd-muted-foreground">
133-
Each feature branch gets its own worktree and tmux window. Switch
134-
context instantly, no stashing needed.
133+
Each feature branch gets its own worktree and dedicated PTY pane.
134+
Switch context instantly, no stashing needed.
135135
</p>
136136
</div>
137137
</div>

docs/app/(home)/privacy/page.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ export default function PrivacyPage() {
1717
<p>
1818
NomadFlowCode (&quot;we&quot;, &quot;our&quot;, or &quot;the app&quot;)
1919
is a mobile application that connects to your own self-hosted server to
20-
manage git worktrees, tmux sessions, and terminal access. This privacy
20+
manage git worktrees, PTY sessions, and terminal access. This privacy
2121
policy explains how we handle your data.
2222
</p>
2323

docs/app/(home)/terms/page.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ export default function TermsPage() {
2323
<h2>2. Description of Service</h2>
2424
<p>
2525
NomadFlowCode is a mobile application that allows you to connect to your
26-
own self-hosted servers to manage git worktrees, tmux sessions, and
26+
own self-hosted servers to manage git worktrees, PTY sessions, and
2727
access terminal sessions remotely. The app acts as a client and requires
2828
you to set up and maintain your own server infrastructure.
2929
</p>

docs/app/layout.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,15 +13,15 @@ export const metadata: Metadata = {
1313
template: '%s | NomadFlow',
1414
},
1515
description:
16-
'Manage git worktrees and tmux sessions from your phone. A single Rust binary paired with a mobile app for on-the-go development.',
16+
'Manage git worktrees and PTY sessions from your phone. A single Rust binary paired with a mobile app for on-the-go development.',
1717
icons: {
1818
icon: '/favicon.ico',
1919
apple: '/apple-touch-icon.png',
2020
},
2121
openGraph: {
2222
title: 'NomadFlow',
2323
description:
24-
'Manage git worktrees and tmux sessions from your phone.',
24+
'Manage git worktrees and PTY sessions from your phone.',
2525
siteName: 'NomadFlow',
2626
type: 'website',
2727
},

docs/content/docs/cli.mdx

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ nomadflow [OPTIONS] [COMMAND]
1919
nomadflow
2020
```
2121

22-
Starts the HTTP server in the background, then launches the **TUI wizard**. When the TUI exits, the server is gracefully shut down (ttyd is cleanly stopped, no orphan processes). If the TUI returns a tmux session to attach to, `tmux attach-session` is executed automatically.
22+
Starts the HTTP server in the background, then launches the **TUI wizard**. When the TUI exits, the server is gracefully shut down. The TUI allows managing PTY sessions and worktrees interactively.
2323

2424
### `serve`
2525

@@ -35,7 +35,7 @@ Runs the HTTP server in the **foreground** with full tracing/logging enabled. Us
3535
| `--host <address>` | Override the displayed address (IP or domain name) for QR code and URL. |
3636
| `--port <port>` | Override the API server port (default: from `config.toml`, fallback `8080`). |
3737

38-
The server handles **graceful shutdown**: on `Ctrl+C` or `SIGTERM`, it stops accepting new connections, completes in-flight requests, then cleanly stops the ttyd subprocess.
38+
The server handles **graceful shutdown**: on `Ctrl+C` or `SIGTERM`, it stops accepting new connections, completes in-flight requests, and cleanly shuts down all managed PTY processes.
3939

4040
### `start`
4141

@@ -61,7 +61,7 @@ Stops the background daemon. Reads the PID file, sends `SIGTERM` to trigger grac
6161
nomadflow web [--port <port>]
6262
```
6363

64-
Starts a lightweight HTTP server that serves the **web dashboard** (static files), then opens it in your default browser. This is a standalone server — no tmux, no ttyd, no auth required.
64+
Starts a lightweight HTTP server that serves the **web dashboard** (static files), then opens it in your default browser. This is a standalone server — no auth required.
6565

6666
| Option | Description |
6767
|--------|-------------|
@@ -96,33 +96,39 @@ Removes a previously linked repository from NomadFlow. If no name is given, show
9696
nomadflow --status
9797
```
9898

99-
Displays the current **daemon status** (running/not running, PID) and the **tmux session status** (windows, features), then exits.
99+
Displays the current **daemon status** (running/not running, PID) and the **active PTY panes** (repo, worktree, agent type), then exits.
100100

101101
### `attach`
102102

103103
```bash
104-
nomadflow attach [<window>]
104+
nomadflow attach [--pane <id>]
105105
```
106106

107-
Attaches to an existing tmux window (no server needed). If a window name is provided (e.g. `omstudio:my-feature`), attaches directly. Otherwise, shows an interactive picker listing all windows with their current process status.
107+
Attaches to a server-managed PTY pane via a Unix socket. This provides a native terminal experience directly in your CLI.
108+
109+
| Option | Description |
110+
|--------|-------------|
111+
| `--pane <id>` | (Optional) The numeric ID of the pane to attach to. If omitted, shows an interactive picker. |
108112

109113
## TUI wizard
110114

111115
When running in default mode, the TUI provides an interactive terminal interface with the following screens:
112116

117+
- **Session picker** — quick resume of active PTY sessions
113118
- **Server list** — manage remote server connections
114119
- **Add server** — multi-step form: name, URL, token, confirmation
115120
- **Repository browser** — list and select repos
116121
- **Feature browser** — list, create, and switch feature branches
117122

118-
The TUI is built with [ratatui](https://ratatui.rs) and exits cleanly, handing off to `tmux attach` if a session was selected.
123+
The TUI is built with [ratatui](https://ratatui.rs) and exits cleanly.
119124

120125
## Daemon files
121126

122127
| File | Description |
123128
|------|-------------|
124129
| `~/.nomadflowcode/nomadflow.pid` | PID of the running daemon process |
125130
| `~/.nomadflowcode/nomadflow.log` | Stdout/stderr of the daemon process |
131+
| `~/.nomadflowcode/nomadflow.sock` | Unix socket for local CLI `attach` |
126132

127133
## Environment variables
128134

docs/content/docs/concepts.mdx

Lines changed: 19 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,20 @@
11
---
22
title: Concepts
3-
description: Architecture, git worktrees, tmux sessions, and how they fit together.
3+
description: Architecture, git worktrees, PTY sessions, and how they fit together.
44
---
55

66
## Architecture
77

8-
NomadFlowCode is built as a Rust workspace with three crates:
8+
NomadFlowCode is built as a Rust workspace with four core crates:
99

1010
| Crate | Role |
1111
|-------|------|
12-
| `nomadflow-core` | Configuration, data models, shell utilities, git/tmux/ttyd services |
13-
| `nomadflow-server` | Axum HTTP server with auth middleware and WebSocket proxy |
12+
| `nomadflow-core` | Configuration, data models, shell utilities, git services |
13+
| `nomadflow-pty` | Binary protocol definitions and PTY handling logic |
14+
| `nomadflow-server` | Axum HTTP server, authentication, and multiplexed WebSocket |
1415
| `nomadflow-tui` | Ratatui TUI wizard for interactive setup |
1516

16-
All three compile into a single `nomadflow` binary.
17+
All crates compile into a single `nomadflow` binary.
1718

1819
## Git worktrees
1920

@@ -31,22 +32,22 @@ Instead of switching branches in a single working directory, NomadFlowCode uses
3132

3233
This means you can have multiple features checked out simultaneously without stashing or losing state.
3334

34-
## Tmux sessions
35+
## Terminal sessions (PTY)
3536

36-
NomadFlowCode manages a single tmux session (default: `nomadflow`). Each feature gets a dedicated tmux window named `{repo}:{feature}` to avoid collisions across repositories.
37+
NomadFlowCode uses a native Rust PTY multiplexer instead of external tools like tmux. Each terminal session runs as a **PaneActor** managed by a **PaneManager**.
3738

3839
When you switch features, the server:
3940
1. Creates a worktree (if needed)
40-
2. Creates or selects the tmux window
41-
3. Changes to the worktree directory
41+
2. Spawns a PTY process in that worktree directory
42+
3. Manages the terminal state (ANSI parsing, buffer snapshots) in memory
4243

43-
## ttyd and WebSocket proxy
44+
## Multiplexed WebSocket
4445

45-
[ttyd](https://github.com/tsl0922/ttyd) exposes the tmux session as a web terminal on port 7681. The mobile app loads the ttyd HTML page directly for HTTP content.
46-
47-
For WebSocket connections, iOS WKWebView does not send Basic Auth headers on WebSocket upgrades. To solve this, the NomadFlowCode server provides a WebSocket proxy at `/terminal/ws` that:
48-
1. Authenticates via a `token` query parameter
49-
2. Forwards the WebSocket connection to ttyd with proper Basic Auth headers
46+
All terminal communication happens over a single WebSocket connection at `/ws/panes`. This protocol supports:
47+
- **Multiplexing** — multiple terminal panes over one connection
48+
- **Binary framing** — efficient data transfer with minimal overhead
49+
- **Buffer snapshots** — instant terminal state resume on reconnection
50+
- **Real-time resizing** — automatic adjustment to mobile/web screen sizes
5051

5152
## Authentication flow
5253

@@ -56,10 +57,8 @@ Mobile App
5657
├─ API requests ──► Bearer token in Authorization header
5758
│ Server validates against auth.secret
5859
59-
├─ ttyd HTML ──────► Loaded directly (basicAuthCredential in URL)
60-
61-
└─ Terminal WS ───► /terminal/ws?token=<secret>
62-
Server proxies to ttyd with Basic Auth
60+
└─ Terminal WS ───► /ws/panes?token=<secret>
61+
Multiplexed binary protocol
6362
```
6463

6564
## File structure
@@ -69,4 +68,5 @@ Mobile App
6968
config.toml # server configuration
7069
repos/ # bare git clones
7170
worktrees/ # checked-out worktrees per feature
71+
sessions/ # agent state tracking data
7272
```

0 commit comments

Comments
 (0)