Skip to content

Fleet Deck 0.5.0

Choose a tag to compare

@lacion lacion released this 13 Jul 14:11

Fleet Deck installs as a Claude Code plugin — there is nothing to download here. Get it with:

claude plugin marketplace add lacion/fleet-deck
claude plugin install fleetdeck@fleetdeck

A deep security / reliability / performance / quality audit of the daemon and
board, run as a multi-agent effort with cross-provider adversarial review of
every change. See docs/AUDIT-2026-07.md for the full report.

Security

  • Fixed a critical CSRF / cross-site WebSocket hijack: loopback was auto-trusted with no Origin/Host/Content-Type check, so any web page you visited could read the /ws snapshot, drive /ws/term, and POST /api/spawn. State-changing routes and both WS upgrades now enforce an Origin/Host/Sec-Fetch allowlist plus an application/json requirement (this also closes DNS rebinding), without breaking the zero-config loopback board.
  • Hardened the LAN token: it no longer rides the WebSocket broadcast or gets logged; fleetd.log and hook-payload capture are now mode 0600 (capture off by default); remote.url is restricted to https://claude.ai; the mDNS instance name is anonymized.

Fixed

  • Node 24 compatibility: the HOME-lock owner check identified fleetd via /proc/<pid>/comm, which Node 24 renames to MainThread — a second daemon could misread a live owner as a recycled PID, steal the lock, and open its SQLite alongside it. The check now resolves the /proc/<pid>/exe symlink. Caught by the new CI's Node 22/24 matrix on its first run.
  • Four production spawn-lifecycle bugs (reported over the fleet board after they lost every live terminal): /clear no longer condemns a live pane; retention verifies a pane via tmux before presuming a silent-but-live agent dead; pane-dead/gone spawns are re-validated and resurrected with hysteresis, and revive() adopts a live pane instead of 409-deadlocking; mail no longer silently truncates at 500 chars (now bounded at 4000, surrogate-safe, and signalled).
  • Reliability hardening: worktree removal no longer rm -rfs uncommitted work without --force; boot reconciliation no longer tombstones the live fleet on a tmux timeout; per-paste unique tmux buffers stop cross-agent mail bleed; plus byte-correct UTF-8 request bodies, WS keepalive and backpressure, bounded DB and caches, and a global unhandledRejection handler.

Changed

  • Performance: broadcast coalescing, tiered transcript reads, memoized board and clock context, idle poll backoff, batched PTY output, and a prepared-statement cache.
  • Structure: derive.mjs (2955 lines) was split into a 314-line composition root plus 13 focused modules, and App.jsx (763 → 433 lines) into hooks plus a Header component — both verified behavior-preserving. Accessibility: ARIA-legal cards, modal focus traps, and keyboard tile focus.