farhand-workspace 1.10.2

Agent-side workspace storage for Farhand: content-addressable store, copy-on-write cloning, locks, GC, and run history
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
<p align="center">
  <img src="assets/logo.png" alt="Farhand Logo" width="220" style="border-radius: 24px;" />
</p>

<h1 align="center">Farhand (fh)</h1>

<p align="center">
  <strong>Remote build and test offloader โ€” zero external system binaries.</strong>
</p>

<p align="center">
  <i>
    Farhand or fh (pronounced <strong>FAAAAAAAH</strong>)
  </i>
  <br/><br/>
  <a href="https://cdn.jsdelivr.net/gh/Rayrsn/farhand@main/assets/pronunciation.mp3" target="_blank" title="Click to listen to pronunciation audio">
    <img src="assets/pronunciation_player.png" alt="Listen to Pronunciation (FAAAAAAAH)" width="380" />
  </a>
  <br/>
  <small>
    <a href="https://cdn.jsdelivr.net/gh/Rayrsn/farhand@main/assets/pronunciation.mp3" target="_blank">๐Ÿ”Š Click to listen to pronunciation (.mp3)</a>
  </small>
</p>

<p align="center">
  <a href="https://github.com/Rayrsn/farhand/actions/workflows/ci.yml"><img src="https://github.com/Rayrsn/farhand/actions/workflows/ci.yml/badge.svg" alt="CI Status" /></a>
  <a href="https://github.com/Rayrsn/farhand/releases/latest"><img src="https://img.shields.io/github/v/release/Rayrsn/farhand?style=flat-square" alt="Release" /></a>
  <a href="LICENSE-MIT"><img src="https://img.shields.io/github/license/Rayrsn/farhand?style=flat-square" alt="License: MIT OR Apache-2.0" /></a>
  <img src="https://img.shields.io/badge/MSRV-1.88-orange?style=flat-square" alt="MSRV 1.88" />
  <a href="https://github.com/Rayrsn/farhand/releases/latest"><img src="https://img.shields.io/badge/no%20external%20system%20binaries-success?style=flat-square" alt="No External System Binaries" /></a>
  <img src="https://img.shields.io/badge/platform-linux%20%7C%20macos%20%7C%20windows-lightgrey?style=flat-square" alt="Platforms" />
</p>

<p align="center">
  <a href="assets/demo"><img src="assets/demo/demo-build.gif" alt="Farhand demo: remote delta-sync build with zero-byte second run" width="840" /></a>
</p>
<p align="center">
  <small>Second run: <code>0 files (0 bytes)</code> transferred โ€” persistent workspace + content-addressable storage doing their job. (<a href="assets/demo/demo-top.gif"><code>fh top</code> dashboard</a>)</small>
</p>

---

## What is Farhand?

Modern software projects have heavy compilation, bundling, and testing pipelines. Running `tsc -p .`, `cargo build --release`, `vitest run`, or `docker build` on a thin laptop or MacBook Air drains battery, spins loud fans, and throttles your system.

**Farhand** (`fh` + `fhd`) allows you to keep editing code locally in your favorite editor (VS Code, Neovim, Zed) while offloading heavy compilation to a powerful remote machine (such as an Apple Silicon Mac Mini, a Linux workstation, or an internal build server). 

Logs stream directly into your terminal in real time, and build artifacts (like `./dist` or `./target/release`) are automatically synced back to your local project directory.

---

## Why Farhand?

| | **Farhand** | VS Code Remote SSH | Bazel remote exec | mosh + tmux | `ssh` + `rsync` |
| :--- | :---: | :---: | :---: | :---: | :---: |
| **Scope** | Run one command on a build box | Full remote dev environment | Hermetic reproducible builds | Resilient shell over lossy links | Ad-hoc file + command copy |
| **Zstd wire compression** | **Yes**, negotiated | No | Bazel-specific | No | gzip or none |
| **Cross-project content dedup (CAS)** | **Yes** | No | Content-addressable store | No | No |
| **Dependency cache survives between runs** | **Yes**, per branch | Yes | Yes (natively) | n/a | Often wiped or conflicts |
| **Bring a dev server back to `localhost`** | **Yes**, `-L` | Yes | No | No | Needs a separate `ssh -L` |
| **Cancel kills the whole remote process tree** | **Yes** | Yes | Yes | n/a | Often orphans it |
| **Language-server offload** | **Yes** | Yes | No | No | No |
| **Multi-agent failover** | **Yes** | No | Yes | No | No |
| **External binaries required** | **None** | VS Code, extension host | Bazel, RBE | mosh, tmux | ssh, rsync, tar |
| **Local CPU still used for build** | Never | Configurable | Never | Yes, always | Yes, always |
| **Windows agent host** | **Yes** | No | Rarely | No | No |
| **Hermetic/reproducible by construction** | No โ€” it runs *your* build | No | **Yes** | No | No |
| **Works without a project system (no Bazel setup)** | **Yes** | Yes | **No** | Yes | Yes |

**Where Farhand loses, plainly.** It is not a hermetic build system: Bazel
reproduces a result from a content-addressed graph, while Farhand runs whatever
your project's own tooling runs and inherits its determinism. It cannot replace
Bazel for that reason. It has no Windows agent story beyond the basics, it
cannot make your local machine faster by moving only part of a build, and
because the remote box keeps its own `node_modules`/`target`, a mismatch
between local and remote toolchain versions is your problem to manage. VS Code
Remote gives you a whole remote environment, not just a command runner.

If you need reproducible builds, use Bazel. If you want a thin, fast way to run
a project's own build and a dev server on a spare machine, that is this.
| **Multi-Branch APFS CoW Forking** | **Yes** (< 100ms, 0-byte duplicate) | No (duplicates entire folder) | No |
| **Delta Source Sync** | **Yes** (SHA-256 manifests over TCP) | Yes (rsync delta) | N/A (entire edit remote) |
| **Clean Process Cancellation** | **Yes** (kills remote process tree) | No (orphans compiler processes) | Yes |
| **Offline Multi-Agent Failover**| **Yes** (automatic load-balancing) | No | No |
| **Works with Any Local Editor** | **Yes** (pure CLI wrapper) | Yes | No |
| **Remote Dev Server Reachable at `localhost`** | **Yes** (`-L`, rides the build connection) | Needs a separate `ssh -L` | Yes (full remote desktop) |

---

## Core Features

- โšก **No External System Binaries**: Pure static Rust binaries. Never invokes or depends on system `ssh`, `rsync`, `tar`, or `gzip` (templates are compiled in โ€” nothing is read from disk or executed).
- ๐Ÿš€ **High-Speed Zstandard (zstd) Wire Compression**: Automatic handshake negotiation chooses `zstd` (level 3) for delta and artifact transfers, delivering 3โ€“5ร— faster compression throughput than gzip with minimal CPU overhead.
- ๐Ÿ—„๏ธ **Global Content-Addressable Storage (CAS)**: Files with matching SHA-256 hashes are deduplicated globally on the agent host across all branches and projects, hydrated instantly via zero-copy CoW reflinks (`clonefile` on macOS / `FICLONE` ioctl on Linux). Zero-byte uploads for known files!
- ๐Ÿ“ **Persistent Workspace Cache**: Remote dependencies (`node_modules/`, `target/`, `.venv/`) remain on the agent host across runs. Only changed source files are transferred.
- โšก **Stat-Gated Warm Sync**: the agent keeps a digest index (`.farhand-hashindex.json`) in each workspace, so an unchanged build re-stats the tree instead of re-reading it. A warm no-op sync costs ~1.1 ms on a 320-file tree rather than a full re-hash. Cold scans hash in parallel across all cores.
- ๐Ÿ **Instant APFS Copy-on-Write (CoW) Forking**: When working across different branches on shared hosts, new branch workspaces are cloned from canonical seeds (`main`/`master`) in **< 100ms using 0 additional disk blocks**.
- ๐Ÿงน **Automated Two-Tier LRU & Emergency GC**: Daemon automatically soft-prunes intermediate caches, performs pre-flight emergency GC when disk space is tight (`--min-disk-gb`), and evicts stale branch workspaces.
- ๐Ÿ‘๏ธ **Continuous Watch Mode (`fh watch`)**: Automatically debounces local file changes, syncs source deltas, and re-triggers remote builds with zero manual intervention.
- ๐Ÿ–ฅ๏ธ **Interactive Shell & Ad-Hoc Exec (`fh shell`, `fh exec`)**: Drop into an interactive remote PTY shell inside your project workspace or run diagnostic commands without triggering hooks.
- ๐Ÿ”€ **Branch-Aware Project Addressing**: Automatically detects git branches and scopes workspaces as `<repo>__<branch>` so multiple developers never collide.
- ๐Ÿ›ก๏ธ **Section 5.1 Deletion Safety**: Strictly protects remote dependencies and build outputs from being deleted during manifest synchronization.
- ๐Ÿ›‘ **Process Group Isolation**: Spawns compilation inside isolated process groups (`setpgid`). If you `Ctrl+C` locally, the entire remote compiler hierarchy is gracefully terminated.
- ๐Ÿ”Œ **Reverse Port Forwarding (`-L`)**: run the dev server on the build box and open it on your laptop as if it were local โ€” `fh -L 3000:3000 -- npm run dev`, then browse `http://localhost:3000`. Repeatable, loopback-only, and multiplexed over the existing build connection, so there is no second tunnel to keep alive and no extra inbound port on the agent. See [the guide]docs/port-forwarding.md.
- ๐ŸŒ **Multi-Agent Pool & Tag Routing**: Automatically discovers, health-checks, and load-balances jobs across a cluster of build agents.
- ๐Ÿ”’ **Native Zero-Config TLS & Mutual TLS (mTLS)**: Pure-Rust, memory-safe TLS via `rustls` (zero OpenSSL / C library dependencies). Supports automatic self-signed cert generation (`fhd --tls-auto`), SHA-256 fingerprint verification (`fh --tls-fingerprint <sha256>`), CA verification (`--tls-ca`), and mutual TLS client certificates (`--tls-cert`, `--tls-key`).
- ๐Ÿ› ๏ธ **Declarative Toolchain Manager Hooks**: Declare language versions per project in `.farhand.yaml` or via CLI (`-T rust=nightly`). Farhand automatically configures `RUSTUP_TOOLCHAIN`, `PYENV_VERSION`, `NODE_VERSION`, and wraps remote invocations with `nvm`, `fnm`, `pyenv`, or `goenv`.
- ๐Ÿ“Š **Run Observability**: Query execution history, exit codes, synced bytes, and duration using `fh history` and host status via `fh status`.
- ๐Ÿ” **Transfer Transparency (`fh sync`, `fh why`)**: See exactly what a build would upload โ€” file count, bytes, and the share of the project that would cross the network โ€” with `fh sync --dry-run`; ask about any single path with `fh why`, which names the ignore rule that excluded it or reports the content-addressed hit that skipped it.
- ๐Ÿฉบ **`fh doctor`**: One read-only pass over everything that commonly breaks a remote build โ€” where it is pointed, whether the token is present and stored safely, whether the transport is encrypted, declared toolchains, and the agent's connectivity, disk, queue, and load. It distinguishes "cannot reach the agent" from "reached it and it rejected your token", and exits 125 when something is actually broken.

---

## How It Works

```
   your machine                              the build box
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”              โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚  you edit files        โ”‚              โ”‚  fhd                     โ”‚
โ”‚        โ”‚               โ”‚              โ”‚    โ”œโ”€โ”€ auth + TLS        โ”‚
โ”‚        โ–ผ               โ”‚   one TCP    โ”‚    โ”œโ”€โ”€ workspace per     โ”‚
โ”‚  fh                    โ”‚  connection  โ”‚    โ”‚   project + branch    โ”‚
โ”‚    โ”œโ”€โ”€ scan + SHA-256  โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ–บโ”‚    โ”‚     (CoW-cloned)       โ”‚
โ”‚    โ”œโ”€โ”€ diff vs agent   โ”‚   frames:     โ”‚    โ”œโ”€โ”€ CAS: content       โ”‚
โ”‚    โ”œโ”€โ”€ delta tar โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ–บโ”‚    โ”‚   addressed, shared   โ”‚
โ”‚    โ”‚                   โ”‚              โ”‚    โ”œโ”€โ”€ run in its own     โ”‚
โ”‚    โ—„โ”€โ”€ live stdout โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค    โ”‚   process group       โ”‚
โ”‚    โ—„โ”€โ”€ stderr โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค    โ””โ”€โ”€ send artifacts      โ”‚
โ”‚    โ—„โ”€โ”€ artifacts โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค                          โ”‚
โ”‚    โ”‚                   โ”‚              โ”‚  ~/.farhand/workspaces/  โ”‚
โ”‚    โ””โ”€โ”€ -L 3000:3000 โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ–บโ”‚      my-app__main        โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜              โ”‚      my-app__feat-x     โ”‚
                                        โ”‚      cas/objects/โ€ฆ       โ”‚
                                        โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
```

Logs, file deltas, artifact transfer, and port forwards all ride the same
multiplexed connection โ€” there is no second tunnel to open and no extra port
on the agent. `-L` reopens a port on *your* loopback that the agent relays to
its own, so a dev server on the build box appears at `localhost` locally.
Full protocol detail in [the architecture guide](docs/architecture.md).

---

## The Two Binaries

1. **`fh` (Client)**: Scans the local project directory, hashes files, uploads deltas, requests remote command execution, streams live logs, and retrieves generated artifacts.
2. **`fhd` (Daemon)**: Listens on TCP (port `9876`), authenticates connections via token, maintains per-project workspaces, unpacks deltas, runs commands in process groups, streams `stdout`/`stderr`, and returns artifacts.

---

## Quickstart

### 1. Installation

> **Using cargo?** The crate is `farhand-cli` / `farhand-agent`, **not**
> `farhand` โ€” that name belongs to an unrelated project on crates.io. See the
> "Via Cargo" section below for the exact commands.

#### โšก One-Liner Install

**Linux & macOS** (Terminal):
```bash
curl -fsSL https://raw.githubusercontent.com/Rayrsn/farhand/main/scripts/install.sh | bash
```

**Windows** (PowerShell โ€” *works whether MSVC / Visual Studio is installed or not*):
```powershell
irm https://raw.githubusercontent.com/Rayrsn/farhand/main/scripts/install.ps1 | iex
```

**Windows** (Command Prompt / `cmd.exe`):
```cmd
powershell -ExecutionPolicy Bypass -Command "irm https://raw.githubusercontent.com/Rayrsn/farhand/main/scripts/install.ps1 | iex"
```

> **Note for Windows Users**: Windows binaries are compiled with static C-runtime linking (`+crt-static`). They are 100% self-contained and run on any clean Windows machine out of the box without requiring Visual Studio, MSVC build tools, or the Microsoft Visual C++ Redistributable.

---

#### ๐Ÿ“ฆ Pre-Built Release Packages

Pre-compiled static release packages, each published with a `.sha256`
alongside it. These `latest` links always resolve to the newest release, so
this table cannot go stale:

| Platform | Architecture | Package Archive |
| :--- | :--- | :--- |
| **Linux** | x86_64 (64-bit) | [`farhand-x86_64-unknown-linux-musl.tar.gz`]https://github.com/Rayrsn/farhand/releases/latest/download/farhand-x86_64-unknown-linux-musl.tar.gz |
| **Linux** | aarch64 (ARM64) | [`farhand-aarch64-unknown-linux-musl.tar.gz`]https://github.com/Rayrsn/farhand/releases/latest/download/farhand-aarch64-unknown-linux-musl.tar.gz |
| **macOS** | Apple Silicon (M1/M2/M3/M4) | [`farhand-aarch64-apple-darwin.tar.gz`]https://github.com/Rayrsn/farhand/releases/latest/download/farhand-aarch64-apple-darwin.tar.gz |
| **macOS** | Intel x86_64 | [`farhand-x86_64-apple-darwin.tar.gz`]https://github.com/Rayrsn/farhand/releases/latest/download/farhand-x86_64-apple-darwin.tar.gz |
| **Windows** | x86_64 (Standalone Static) | [`farhand-x86_64-pc-windows-msvc.zip`]https://github.com/Rayrsn/farhand/releases/latest/download/farhand-x86_64-pc-windows-msvc.zip |

---

#### ๐Ÿบ Via Homebrew (macOS)
```bash
brew tap Rayrsn/farhand https://github.com/Rayrsn/farhand.git
brew install farhand
```

#### ๐Ÿฆ€ Via Cargo

```bash
# The two binaries come from two crates, because the agent is published
# separately: a client-only user should not have to build a daemon.
cargo install farhand-cli      # provides `fh`
cargo install farhand-agent    # provides `fhd`
```

Or straight from the repository, if you want unreleased changes:

```bash
cargo install --git https://github.com/Rayrsn/farhand.git farhand-cli farhand-agent
```

> **The crate is not called `farhand`.** `cargo install farhand` installs
> someone else's project โ€” an unrelated tool already owns that name on
> crates.io. The crates here are **`farhand-cli`** (the `fh` client) and
> **`farhand-agent`** (the `fhd` daemon). Note the split: `cargo install` takes
> *crate* names, while the *binaries* you run are `fh` and `fhd`. The Homebrew
> formula, by contrast, really is `farhand` โ€” so `brew install farhand` is
> correct and `cargo install farhand` is not.

---

#### โ˜๏ธ Automated Remote Setup (SSH Over Cloudflare Tunnel)

To automatically install all prerequisites (`cloudflared`, OpenSSH, and `fh`) on your local client machine and configure seamless SSH port forwarding:

- **Linux & macOS**:
  ```bash
  curl -fsSL https://raw.githubusercontent.com/Rayrsn/farhand/main/scripts/setup_remote_ssh.sh | bash
  # Or run locally from repository:
  ./scripts/setup_remote_ssh.sh --hostname mac.yourdomain.com --alias mac-mini --user builder
  ```
- **Windows (PowerShell)**:
  ```powershell
  & { irm https://raw.githubusercontent.com/Rayrsn/farhand/main/scripts/setup_remote_ssh.ps1 } -Hostname mac.yourdomain.com -HostAlias mac-mini -RemoteUser builder
  # Or run locally from repository:
  .\scripts\setup_remote_ssh.ps1
  ```

*(See the complete [Remote Access via Cloudflare Tunnel Guide](docs/cloudflared-tunnel.md) for full architecture details).*

---

### 2. Start the Daemon (`fhd`)

On your remote build machine or Mac Mini:

```bash
# Generate a secret token
export FARHAND_TOKEN="super-secret-token"

# Run the daemon (token required โ€” fhd refuses to start unauthenticated by default)
fhd --listen 0.0.0.0:9876 --token "${FARHAND_TOKEN}" --workdir /var/farhand/workspaces

# Development only: allow unauthenticated local clients explicitly
fhd --listen 127.0.0.1:9876 --allow-unauthenticated --workdir /tmp/farhand-dev
```

> `fhd` warns on non-loopback binds: without `--tls`, tokens travel in
> cleartext โ€” use `--tls` / `--tls-auto` or a tunnel on untrusted networks.
> Concurrent connections are capped via `--max-connections` (default 32).

*(For production background services on macOS or Linux, see the [Apple Silicon Mac Mini Setup Guide](docs/mac-build-server-setup.md) or [systemd service units](dist/services/fhd.service)).*

---

### 3. Run Builds Remotely (`fh`)

In your local project directory, initialize Farhand configuration automatically:

```bash
# Auto-detect project type and generate .farhand.yaml
fh init

# Or optionally generate customizable template definitions (.farhand/templates/<name>.yaml)
fh init --with-template
```

This generates a `.farhand.yaml` tailored to your project:

```yaml
# .farhand.yaml
host: "192.168.254.68:9876"  # Remote agent address or Tailscale name
token: "${FARHAND_TOKEN}"

# Unpack artifacts directly into the project directory (e.g. ./dist)
outDir: "."

# Outputs to pull back from the agent upon success
outputs:
  - "dist"
```

Now execute any command remotely by prefixing it with `fh`:

```bash
# Offload TypeScript compilation
fh npm run build

# Run unit tests on the remote machine
fh npm test

# Compile Rust binaries
fh cargo build --release

# Continuous watch mode: sync and rebuild on local file saves
fh watch cargo check

# Run the dev server on the build box, browse it at localhost:3000
fh -L 3000:3000 -- npm run dev

# Or declare it once in .farhand.yaml, then just run the build:
#   forward:
#     - "3000:3000"

# Interactive remote workspace shell (allocated PTY inside remote repo)
fh shell

# Ad-hoc command execution (bypasses dependency hooks and artifact downloads)
fh exec -- git status

# Override or suppress artifact downloads on the fly
fh -o target/release/my-bin -- cargo build --release
fh --no-output -- cargo test

# Run with secrets from Infisical (env vars forwarded automatically)
infisical run -- fh npm run build

# Or disable ambient env forwarding / pass explicit variables
fh --no-env -e DATABASE_URL=postgres://remote/app -- npm run build

# Zero-config TLS with SHA-256 fingerprint verification
fh --tls --tls-fingerprint "7f9a8b1c2d3e4f50..." -- cargo check

# Select language toolchain version on the fly
fh -T rust=nightly -T node=22 -- npm run build

# Inspect execution history and agent status (including available remote disk space)
fh history

# See exactly what a build would transfer โ€” nothing leaves your machine
fh sync --dry-run
fh sync --list           # ...and name every file in the transfer set
fh sync                  # actually sync, without running a build

# Ask why any single path is (or is not) on the agent
fh why src/main.rs       # uploaded, or a content-addressed hit?
fh why node_modules/x.js # excluded โ€” and by which rule

# One-shot diagnosis: config, token handling, transport, connectivity, and agent capacity
fh doctor

# Watch mode honours each template's ignoreExtra, and the debounce is tunable
fh --watch --watch-debounce 400 -- npm run build

# Nix (flake or plain nix-build)
nix build .#fh && ./result/bin/fh --help
nix build .#fhd
nix develop          # dev shell with rust-analyzer, cargo-audit, cargo-deny

# Shell completions and man pages, generated from the binary's own CLI definition
fh completions bash > /etc/bash_completion.d/fh
fh man --dir /usr/share/man/man1

# Prometheus metrics for Grafana/Prometheus (opt-in on the agent)
fhd --listen 0.0.0.0:9876 --token "$FARHAND_TOKEN" --metrics-port 9100

# Live terminal resource dashboard & host telemetry
fh top                  # Interactive live TUI (CPU, RAM, Disk, Active Builds)
fh top --once           # Print snapshot and exit
fh agent info           # Formatted host specs, cores, load averages, memory
fh agent info --json    # Machine-readable JSON telemetry

# Remote Language Server Protocol (LSP) offloading (rust-analyzer, pyright, gopls, etc.)
fh lsp -- rust-analyzer

# Free remote disk space for the current branch
fh clean
```

---

## Daily Developer Workflow

```bash
# 1. Start working on a new feature branch locally
git checkout -b feat/payments

# 2. Trigger build remotely
# Farhand automatically APFS-clones the seed workspace from main in < 100ms (0 bytes duplicate storage)
fh npm run build

# 3. Modify source code locally
nano src/index.ts

# 4. Re-run build
# Farhand only uploads the single changed file (0-byte delta sync for everything else)
fh npm run build

# 5. Finished with the branch? Free remote workspace space
fh clean
```

---

## Performance

Measured with criterion (`cargo bench -p fileset -p workspace`, release profile)
on an Intel Core Ultra 7 256V, `/tmp` on tmpfs โ€” full methodology and
reproduction steps in **[BENCHMARKS.md](BENCHMARKS.md)**:

| Metric | Result |
| :--- | ---: |
| Delta tar pack, zstd-3 vs gzip (2.4 MiB payload) | **74 ms vs 312 ms โ†’ 4.2ร— faster** |
| Delta tar unpack, zstd vs gzip | **18 ms vs 57 ms โ†’ 3.1ร— faster** |
| Scan + SHA-256 hash, 320 files (~2.4 MiB) | **3.1 ms** (parallel across cores) |
| Warm sync of an unchanged workspace | **1.1 ms** โ€” stats only, reads no file content |
| CAS hydration (CoW reflink), 256 KiB file | **~24 ยตs** (flat vs payload size) |
| Workspace branch clone (CoW, 100-file tree) | **~4 ms** |

Reproduce: `scripts/run_benchmarks.sh` regenerates `BENCHMARKS.md` from
criterion's saved estimates.

### End to end, on a real project

The microbenchmarks above measure the parts. This is the whole command,
`fh <anything>`, against a live agent over loopback, on a 304-file Rust
project (~1.2 MiB of source):

| Run | Wall clock | Agent scan |
| :--- | ---: | :--- |
| First build (cold workspace) | 255 ms | 305 files hashed |
| Second build | 168 ms | 305 files re-hashed โ€” see below |
| Third and every run after | **~150 ms** | 304 digests reused, 0 re-hashed |

**Two honest notes.** The second run deliberately re-hashes everything: a
file whose mtime is not strictly older than the digest index's own write is
treated as unsafe rather than trusted, and everything synced a moment earlier
falls inside that window. The gate engages from the third run on, and costs
one re-hash in exchange for never trusting a file that changed in the same
tick it was recorded.

And the 150 ms floor is process start, handshake, and round trips โ€” at 304
small files the fixed costs dominate, so the end-to-end win here is roughly
40%. The win is in the scan itself (3.11 ms โ†’ 1.13 ms on this fixture), and
that is the term that grows with your tree; on a project ten times this size
the fixed costs are the same and the scan is the part that hurts.

---

## Detailed Documentation

Deep-dive guides covering architecture, server setup, and configuration:

- ๐Ÿ–ฅ๏ธ **[CLI Reference]docs/cli.md** โ€” Every command, subcommand, and flag, plus the exit-code contract.
- ๐Ÿ“ฆ **[Templates]docs/templates.md** โ€” How build templates detect projects and drive dependency installs, and how to override them.
- ๐Ÿ–ง **[The Agent (`fhd`)]docs/agent.md** โ€” Every daemon flag, the security posture, resource limits, GC and CAS tuning, and running it as a service.
- ๐Ÿ™ˆ **[Ignore Rules]docs/ignores.md** โ€” What gets synced and what does not: built-in defaults, `.gitignore`, `.farhand-ignore`, and template rules.
- ๐Ÿ“ˆ **[Observability]docs/observability.md** โ€” live `fh top`, plus an opt-in Prometheus endpoint (`fhd --metrics-port`) with an importable Grafana dashboard.
- ๐Ÿ **[Apple Silicon Mac Mini Setup Guide]docs/mac-build-server-setup.md** โ€” Production step-by-step guide for turning a Mac Mini into a multi-developer build server (`launchd`, firewalls, network access).
- ๐Ÿ’พ **[Storage Optimization & Caching Guide]docs/storage-and-caching.md** โ€” Deep dive into APFS Copy-on-Write cloning, LRU garbage collection, and shared toolchain caches (`sccache`).
- โš™๏ธ **[Configuration Guide (`.farhand.yaml`)]docs/configuration.md** โ€” Complete reference for config discovery, field definitions, and environment variable interpolation.
- ๐ŸŒ **[Multi-Agent Pool & Dynamic Load Balancing]docs/multi-agent-pool.md** โ€” Setup guide for multi-agent clusters, health probing, and hardware tag routing (`--agent-tag`).
- โšก **[Language Server Protocol (LSP) Offloading Guide]docs/lsp-integration.md** โ€” Offload `rust-analyzer`, `pyright`, `gopls`, and `clangd` to remote agent with VS Code, Neovim, Helix, and Zed.
- ๐Ÿ”Œ **[Reverse Port Forwarding Guide]docs/port-forwarding.md** โ€” Run a dev server, database, or any port on the build box and reach it at `localhost` with `-L`, multiplexed over the existing build connection.
- โ˜๏ธ **[Remote Access via Cloudflare Tunnel]docs/cloudflared-tunnel.md** โ€” Connect securely over the internet with `cloudflared access tcp` without opening inbound router ports.
- ๐Ÿ“ **[Benchmarks]BENCHMARKS.md** โ€” Reproducible criterion numbers behind the performance claims above.

## Recipes

- ๐Ÿณ **[Migrate from `rsync` + `ssh`]recipes/migrating-from-rsync.md** โ€” what the script did, what replaces each part, and how to check a path is actually being sent.
- โš™๏ธ **[Run in GitHub Actions]recipes/github-actions.md** โ€” using a cheap hosted runner for orchestration while the build happens on a machine you control.

## Project & Community

- ๐Ÿ“œ **[Changelog]CHANGELOG.md** โ€” Notable changes per release.
- ๐Ÿค **[Contributing Guide]CONTRIBUTING.md** โ€” Dev setup, code style, commit conventions, testing expectations.
- ๐Ÿ” **[Security Policy]SECURITY.md** โ€” Supported versions, private vulnerability reporting, and the `fhd` threat model.

---

## License

Dual-licensed under either:
- **MIT License** ([LICENSE-MIT]LICENSE-MIT or [http://opensource.org/licenses/MIT]http://opensource.org/licenses/MIT)
- **Apache License, Version 2.0** ([LICENSE-APACHE]LICENSE-APACHE or [http://www.apache.org/licenses/LICENSE-2.0]http://www.apache.org/licenses/LICENSE-2.0)

at your option.