From cad63bdd7638d57e84c499709957e036cf2c6095 Mon Sep 17 00:00:00 2001 From: archipelago Date: Thu, 23 Apr 2026 04:51:53 -0400 Subject: [PATCH] =?UTF-8?q?docs:=20STATUS.md=20=E2=80=94=20FUSE/SSHFS=20de?= =?UTF-8?q?velopment=20loop=20section?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Dedicated section covering the file-ops-via-mount + git/cargo-via-ssh split that makes this dev setup work. Includes: - Exact running mount command (pulled from ps) - macFUSE + sshfs-mac brew install path - Health check + recovery sequence for when mount hangs (it will) - Full which-path-for-which-operation table - Don't-do list (cargo from mount, rsync without AppleDouble exclude, etc) - Cache caveat and inode-sharing note between mount and SSH views No code change. --- docs/STATUS.md | 95 ++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 89 insertions(+), 6 deletions(-) diff --git a/docs/STATUS.md b/docs/STATUS.md index a1f10540..58c9092d 100644 --- a/docs/STATUS.md +++ b/docs/STATUS.md @@ -12,13 +12,96 @@ Updated: 2026-04-23 (Dashboard Stop UX bug diagnosed; async-spawn fix fully desi ### How to work on this repo (SSH + SSHFS setup) -You are likely running on the **laptop** (macOS). The repo lives on the **ThinkPad** (.116). There are two access paths, use both: +You are likely running on the **laptop** (macOS). The repo lives on the **ThinkPad** (.116). There are two access paths, use both in parallel: -1. **SSHFS mount at `~/mnt/archy-thinkpad/`** — use for `read` / `edit` / `write` / `glob` / `grep` tools. Fast for file ops, too slow for git/cargo. Example: `/Users/dorian/mnt/archy-thinkpad/core/archipelago/src/api/rpc/container.rs`. - - Mount source: `archy:Projects/archy` (via the `archy` SSH alias, so it uses `~/.ssh/archy_opencode`) - - If mount is missing/stale, remount: `sshfs archy:Projects/archy ~/mnt/archy-thinkpad -o reconnect,ServerAliveInterval=15` - - AppleDouble `._*` files leak from macOS writes — add `--exclude="._*"` to any `rsync` over the mount; single-file `edit`/`write` is fine. -2. **SSH directly** — use for `git`, `cargo`, `npm`, running the server. SSH config aliases are already set up in `~/.ssh/config`: +1. **SSHFS mount at `~/mnt/archy-thinkpad/`** — for all file ops (`read`/`edit`/`write`/`glob`/`grep`). +2. **Direct SSH** — for everything that isn't file ops: `git`, `cargo`, `npm`, `systemctl`, running the server, tailing logs. + +See the "FUSE / SSHFS development loop" section below for the full mount lifecycle — that's _the_ thing that makes this dev setup work, and it will break periodically. + +### FUSE / SSHFS development loop + +**Why this exists**: editing the repo directly on the ThinkPad over raw SSH means no IDE, no tool-native file reads, no glob/grep speed. SSHFS mounts the remote filesystem as a local directory so OpenCode's file tools work transparently. But SSHFS is a leaky abstraction — know the gotchas or you'll waste hours. + +**Stack** (macOS laptop): +- **macFUSE** — kernel extension providing FUSE on macOS. Install via `brew install --cask macfuse` (requires reboot + security approval in System Settings the first time). +- **sshfs** — userspace mount tool. Install via `brew install gromgit/fuse/sshfs-mac` (the homebrew core `sshfs` was removed; use this tap). +- Verify: `which sshfs` → `/opt/homebrew/bin/sshfs`, `sshfs --version` → `SSHFS version 2.10 / FUSE library version 2.9.9`. + +**Actual mount command currently running** (verified from `ps`): +``` +sshfs archy:Projects/archy /Users/dorian/mnt/archy-thinkpad \ + -o reconnect,ServerAliveInterval=15,ServerAliveCountMax=3,volname=archy-thinkpad +``` + +Breakdown: +- `archy:Projects/archy` — remote path via the `archy` SSH alias (uses `~/.ssh/archy_opencode`, no password prompt). +- `~/mnt/archy-thinkpad` — local mount point. Create once: `mkdir -p ~/mnt/archy-thinkpad`. +- `reconnect` — sshfs auto-reconnects if the TCP session drops (WiFi flap, laptop sleep). Without this, the mount turns into a zombie immediately. +- `ServerAliveInterval=15` — sends a keepalive every 15s. +- `ServerAliveCountMax=3` — disconnect after 3 missed keepalives (45s). Tune up if your network is flaky. +- `volname=archy-thinkpad` — Finder display name. + +**Check mount health**: +``` +mount | grep archy-thinkpad +# should print: archy:Projects/archy on /Users/dorian/mnt/archy-thinkpad (macfuse, nodev, nosuid, synchronous, mounted by dorian) + +ls ~/mnt/archy-thinkpad/ | head +# should list repo contents fast (<1s). If it hangs, mount is stale. +``` + +**Recovery when the mount hangs / goes stale** (this WILL happen — laptop sleeps, WiFi drops, ThinkPad reboots): +``` +# 1. Force-unmount (macOS — `umount` alone often fails on a hung FUSE mount) +sudo diskutil unmount force ~/mnt/archy-thinkpad +# fallback if diskutil can't see it: +sudo umount -f ~/mnt/archy-thinkpad + +# 2. Kill any zombie sshfs process +pkill -f "sshfs archy:Projects/archy" + +# 3. Remount +sshfs archy:Projects/archy ~/mnt/archy-thinkpad \ + -o reconnect,ServerAliveInterval=15,ServerAliveCountMax=3,volname=archy-thinkpad + +# 4. Verify +ls ~/mnt/archy-thinkpad/ | head +``` + +If the mount point itself got wedged (`ls: /Users/dorian/mnt/archy-thinkpad: Device not configured`), the sequence above still works — macFUSE garbage-collects the inode after the force-unmount. + +**When to use which path** (rules, not suggestions): +| Operation | Use | Why | +|---|---|---| +| `read` / `edit` / `write` | SSHFS mount | OpenCode tools want local paths | +| `glob` / `grep` | SSHFS mount | Local FS traversal is fine; remote would need rg over SSH | +| Reading many files | SSHFS mount | Each read is a round-trip but parallelizable | +| `git status` / `git diff` / `git log` | SSH | Git over FUSE is painfully slow (lots of stat calls) | +| `git add` / `git commit` | SSH | Same — commit times grow linearly with tree size on FUSE | +| `cargo check` / `cargo test` / `cargo build` | SSH | Compiling over FUSE would take hours; cargo's incremental stat pattern destroys FUSE performance | +| `npm install` / `npm run build` | SSH | Same reason — massive file churn | +| Running the server / tailing journal | SSH | Service lives on .116 | +| Deploying to .228 | SSH from .116 | SCP from ThinkPad; laptop isn't in the critical path | + +**Don't do this** (will bite you): +- `cargo build` from the mount — will try to write target/ over FUSE, gets orders of magnitude slower, may hang. +- `rsync` without `--exclude="._*"` — macOS writes AppleDouble metadata files, they leak to the remote as `._*` siblings of every real file. `.gitignore` already excludes them (commit `13858842`), but they clutter the tree. +- Writing big binary files via the mount — use `scp` over SSH instead. +- Relying on file-change-watcher tools (watchman, chokidar) — they get confused by FUSE event semantics. + +**Editing workflow in a typical session**: +1. Laptop: OpenCode `read`s a file via `/Users/dorian/mnt/archy-thinkpad/...`. FUSE fetches it over SSH, caches briefly. +2. Laptop: OpenCode `edit`s the file — FUSE writes the new bytes back to .116 immediately (synchronous mount). +3. Laptop: `ssh archy "cd ~/Projects/archy && ~/.cargo/bin/cargo check -p archipelago"` — runs on the real filesystem on .116, sees the edit. +4. Laptop: `ssh archy "cd ~/Projects/archy && git diff path/to/file"` — confirms the edit landed. +5. Laptop: `ssh archy "cd ~/Projects/archy && git add path/to/file && git commit -m '...'"` — commit from .116. + +The SSHFS mount and the SSH shell are pointing at **the same inodes** — edits via the mount are instantly visible to `cargo`/`git` over SSH. There's no "sync" step. + +**Cache caveat**: macFUSE caches attributes briefly (default ~1s). If you write via SSH and read via the mount within that window, you may see stale metadata. The mount's `synchronous` flag (visible in `mount` output) minimizes but doesn't eliminate this. If you get a weird diff between what SSH and the mount report, re-read after a second, or `stat --file-system ~/mnt/archy-thinkpad/` to force a refresh. + +**Direct SSH** access (use when FUSE isn't the right tool): - `ssh archy` → `archipelago@192.168.1.116` using `~/.ssh/archy_opencode` - `ssh archy228` → `archipelago@192.168.1.228` using `~/.ssh/archy_opencode` - Full host form also works: `ssh archipelago@192.168.1.116` / `ssh archipelago@192.168.1.228` (same key resolves via IdentitiesOnly).