Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 33 additions & 0 deletions tools/fleet/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# Fleet hardening — lid-close / internet-loss (#324)

Operational fix applied 2026-08-09, captured here as versioned template.

## Problem

Closing the MacBook lid killed the `ssh -L 127.0.0.1:4096` tunnel, so chat appeared to stop even though `Aarons-Mac-mini` (canonical server, `co.harmoniqs.amicode-server`, `opencode-dev.db` 707 sessions) kept running. Tunnel used `ServerAliveInterval 30 / CountMax 3` (90s detection) and the fleet guard was missing on the mini with a stale `~/harmoniqs` path, so a port-race could fork a laptop-local `opencode.db` during reconnect gaps.

## Fix (applied on hosts)

* **Guard** — `amico-opencode-fleet-guard` installed to `~/.local/bin` on both hosts. Client exits 1 (panel rides tunnel), server execs frozen `~/.amico/server/bin/opencode` falling back to VSIX. Prevents silent fork (ADR 0005, #279, #324).
* **Tunnel** — `co.harmoniqs.amico-tunnel.plist` tuned to `ServerAliveInterval 15 / CountMax 2 / TCPKeepAlive yes` (30s detection, matches `amico-mini` Host `ServerAliveInterval 15`). LAN-first `Match host amico-mini exec "ping -c1 -W1000 Aarons-Mac-mini.local"` keeps tunnel up on same Wi-Fi with no internet.
* **Hygiene** — forked `opencode.db` archived on macbook to `~/.local/share/opencode/archive/`, `~/.config/opencode/opencode.json` symlink repointed to `vault-aaron`, duplicate `Host the-feynmachine` removed.

## Verification

```
lsof -nP -iTCP:4096 -sTCP:LISTEN # ssh LISTEN, no opencode
curl http://127.0.0.1:4096/session # 200 via tunnel
sqlite3 ~/.local/share/opencode/opencode-dev.db "SELECT COUNT(*) FROM session;" # 707 on mini
cat ~/.amico/ops/fleet-status.json # guard ok, served 639
```

Lid-close/wake or LAN-only internet loss: tunnel respawns via `KeepAlive` within ~30s.

## Install

```bash
cp tools/fleet/amico-opencode-fleet-guard ~/.local/bin/amico-opencode-fleet-guard
chmod +x ~/.local/bin/amico-opencode-fleet-guard
# scope: machine — never synced
# settings.json: "amicode.opencodeBinary": "/Users/aaron/.local/bin/amico-opencode-fleet-guard"
```
28 changes: 28 additions & 0 deletions tools/fleet/amico-opencode-fleet-guard
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
#!/bin/bash
# amico-opencode-fleet-guard — fleet client guard for the Amicode extension.
# Only Aarons-Mac-mini may run the canonical opencode server. On any other
# machine, exit 1 immediately: the extension's health probe then rides the
# SSH tunnel on 127.0.0.1:4096 (canonical server), or fails closed if the
# tunnel is down — a client must NEVER spawn a local fork. (harmoniqs/amicode#279, #324)
#
# Install to ~/.local/bin on every host and point amicode.opencodeBinary at it:
# cp tools/fleet/amico-opencode-fleet-guard ~/.local/bin/amico-opencode-fleet-guard
# # then in settings.json (scope: machine): "amicode.opencodeBinary": "/Users/aaron/.local/bin/amico-opencode-fleet-guard"
if [ "$(scutil --get LocalHostName 2>/dev/null)" != "Aarons-Mac-mini" ]; then
echo "[amico-fleet-guard] refusing to spawn a local opencode server on a fleet client — panel will ride the tunnel" >&2
exit 1
fi
# SERVER: resolve opencode binary — frozen first (same order as amicode-server.sh)
FROZEN="$HOME/.amico/server/bin/opencode"
VSIX_BIN="$(ls -dt "$HOME"/.vscode/extensions/harmoniqs.amicode-*/vendor/opencode/darwin-arm64/opencode 2>/dev/null | head -1)"
DEV_BIN="$HOME/armonia/repos/amicode/packages/extension/vendor/opencode/darwin-arm64/opencode"
if [ -x "$FROZEN" ]; then
exec "$FROZEN" "$@"
elif [ -n "$VSIX_BIN" ] && [ -x "$VSIX_BIN" ]; then
exec "$VSIX_BIN" "$@"
elif [ -x "$DEV_BIN" ]; then
exec "$DEV_BIN" "$@"
else
echo "[amico-fleet-guard] no opencode binary found (frozen, VSIX, or armonia repos)" >&2
exit 1
fi
Loading