Files
mopac-pmo/handoff/cto-state-20260828/.coordinate/archive/SPIKE-crush-server.md
T

4.1 KiB

SPIKE: crush server (v0.87.0) as screen+TUI replacement — RESEARCH

Date: 2026-08-28 | By: TSGCTO-Work | Turn: crush-spike | Status: DONE

a) Surface (crush server --help)

  • Flags: -c/--cwd, -D/--data-dir, -d/--debug, -H/--host (TCP or unix socket).
  • Default socket: unix:///tmp/crush-<uid>.sock → here /tmp/crush-1005.sock (uid 1005 confirmed).
  • Protocol: Go net/http mux speaking HTTP/1.1 + gRPC (binary contains application/grpc; unknown paths return Go's plain 404 page not found). Not REST — probed /healthz /health /v1/sessions /grpc.health.v1.Health/Check and connect-style paths: all 404. It exposes the crush client RPC API only.

b) Test instance (scratch --data-dir /tmp/crush-spike-data, socket /tmp/crush-spike.sock)

What it exposes / does:

  • Serves the client API: crush -H unix://... run|session ... all work through it.
  • Persists sessions to SQLite crush.db + logs/crush.log inside --data-dir.
  • No dashboard, no REST, no health endpoint. stdout log empty even with -d.
  • Socket created 0755 in world-writable /tmp (any local uid can connect).

c) Non-interactive client via -H unix://...

Yes, fully. Evidence:

  • crush -H unix://... --data-dir <scratch> run "Reply with exactly: SPIKE-OK" → replied SPIKE-OK, exit 0; real model turn (glm-5.2/zai, 11k tok) recorded.
  • session last --json, session list/new/delete/rename/show all functional.
  • Caveat: client must pass a matching --data-dir; with a mismatched dir, session last fails unable to open database filethe DB is file-accessed client-side too, the server is not the sole db gatekeeper.

d) Server-side session liveness (no per-client pty)?

No. Decisive evidence:

  • Mid-turn (agent running sleep 20 via shell tool), the tool process was a child of the CLIENT process; the server had zero child processes at every check.
  • Agent loop (app.RunNonInteractive, sessionAgent.Run per data-dir log) executes in the client binary. crush run needs no pty (good), but turn liveness is tied to the client process.
  • Killing the client kills the work; the server adopts nothing. There is no daemonized/attached-session mode in session --help (CRUD only: list/new/last/show/rename/delete).

e) Verdict

NOT production-viable TODAY as the agent process layer replacing screens. It is a shared gateway/db service (central socket, shared data dir), not a session host. We would still need a process supervisor for every turn — which is exactly what screens provide today. Adopting it adds risk without removing the supervision requirement.

Risks if adopted:

  • Auth: none observed. 0755 socket at predictable /tmp/crush-<uid>.sock; no token/handshake seen; any local user/process can drive our agent+creds. TCP mode would be strictly worse.
  • SPOF: one server crash takes out every connected client mid-turn.
  • Resource/locking: single SQLite crush.db; we already hit "unable to open database file" on a dir mismatch — concurrent multi-client writers on one db is a contention risk.
  • Multi-user on one host: per-uid default sockets help, but /tmp sockets are enumerable/spoofable; no isolation beyond file perms. Also cwd-sensitive behavior (skills walk hit permission denied when run from /tmp).
  • Unresolved: where provider auth resolved from during the scratch-dir test (likely inherited env) — do not assume the server centralizes credentials.

Migration sketch

Not viable → no migration. Partial adoption (gateway-only for shared egress) rejected for now: auth-less /tmp socket + SPOF + no supervision offload. Keep dispatch v2 (screen + crush run --session) as the process layer. Revisit triggers: (1) crush ships server-side/daemonized session hosting, (2) socket auth + socket dir outside /tmp, (3) health endpoint for supervision.

Cleanup confirmation

Test server killed (verified), /tmp/crush-spike-{data,logs}.sock removed (ls /tmp/crush-spike* → No such file). Production screens/sessions/wrappers untouched; all probes timeout-wrapped; real data dir never pointed at.