# 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-.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 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 file` → **the 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-.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.