Daemon
caveman serve starts a headless HTTP daemon that other Caveman Code clients (TUI, future desktop, future mobile) attach to. Sessions live in SQLite and survive SSH drops, machine sleep, and client crashes.
Quick start
caveman serve --port 39245 # start the daemon
caveman attach --host localhost:39245 # attach a TUI to it
caveman list # list sessions
By default caveman serve binds to 127.0.0.1 only. Use --host 0.0.0.0 and a TLS terminator for remote access.
Architecture
┌─────────────────────────────┐ ┌─────────────────────┐
│ cave TUI (client) │ ──HTTP─▶│ caveman serve │
│ caveman attach <session-id> │ ◀──WS── │ ├─ session store │
└─────────────────────────────┘ │ │ (SQLite) │
│ ├─ session loop │
┌─────────────────────────────┐ │ ├─ tool runtime │
│ cave-desktop (client) │ ──HTTP─▶│ └─ MCP clients │
└─────────────────────────────┘ └─────────────────────┘
- HTTP for control-plane (start session, list, kill).
- WebSocket for streaming tokens, low-latency tool events.
- SQLite at
~/.cave/serve/sessions.db.
OpenAPI spec
The daemon exposes an OpenAPI 3.1 spec at GET /openapi.yaml. The generated TypeScript SDK is published as @juliusbrussee/caveman-sdk:
npm install @juliusbrussee/caveman-sdk
import { CaveClient } from "@juliusbrussee/caveman-sdk";
const client = new CaveClient({ host: "localhost:39245" });
const session = await client.sessions.create({ model: "claude-sonnet-4" });
await session.prompt("explain this codebase");
for await (const ev of session.events()) {
console.log(ev);
}
Worker mode (cloud handoff)
Register a remote caveman worker:
# on the remote (e.g. a beefy GPU box)
caveman worker start --bind 0.0.0.0:39246 --token <secret>
# locally, register
caveman worker add gpu-rig http://gpu-rig:39246 --token <secret>
Then prepend & to any prompt and it dispatches to the worker:
& refactor packages/agent/src/checkpoints to use the new index format
The local terminal frees up. The worker runs the session. Re-attach later:
caveman list
caveman attach <session-id>
Multi-client
Multiple clients can attach to the same session. Edits stream to all attached clients in real-time. Useful for pair programming or for keeping a session open in your laptop's TUI while a desktop client tails it.
Survive SSH drops
ssh box
caveman serve &
caveman attach <id>
# SSH drops
ssh box
caveman attach <id> # picks up exactly where you left off
The daemon survives client disconnects. Tool calls in flight complete; the next attach replays missed events.
Stopping
caveman serve stop
caveman serve --pid-file ~/.cave/serve.pid stop
Ctrl+C on the foreground caveman serve stops it cleanly. Active sessions checkpoint to disk.
Security
- Default bind is
127.0.0.1only. - Tokens (
--token) are required for any non-loopback bind. - WebSocket uses bearer auth on connect.
- TLS is your terminator's job — front the daemon with Caddy, nginx, or
cloudflared tunnel.
Limitations
- Daemon is opt-in. Most users run caveman directly without it.
- Worker mode requires SSH-grade trust between local and remote.
- Not yet supported on Windows (preview Q3 2026).