From 350fcf371389308ba899f73c1275fe5055ee3cc0 Mon Sep 17 00:00:00 2001 From: Jared Miller Date: Wed, 28 Jan 2026 10:59:48 -0500 Subject: [PATCH] Add implementation plan to docs Copied from planning phase - full specification for PTY wrapper, WebSocket protocol, SQLite schema, and deployment setup. --- docs/plan.md | 157 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 157 insertions(+) create mode 100644 docs/plan.md diff --git a/docs/plan.md b/docs/plan.md new file mode 100644 index 0000000..d5cb8c7 --- /dev/null +++ b/docs/plan.md @@ -0,0 +1,157 @@ +# claude-remote + +self-hosted remote control for claude code, pure bun stack. + +## summary + +wrap claude cli in PTY, stream output to server, approve prompts from phone. + +## tech stack + +- bun-pty (native PTY via FFI to Rust) +- bun:sqlite (persistence) +- Bun.serve() (HTTP + WebSocket + SSE) +- no frameworks + +## project location + +`/home/jtm/projects/agentry/repos/claude-remote/` + +## structure + +``` +claude-remote/ +├── src/ +│ ├── cli.ts # PTY wrapper, connects to server +│ ├── server.ts # HTTP + WebSocket + SSE +│ ├── db.ts # SQLite schema + queries +│ ├── auth.ts # HMAC signing +│ └── types.ts # shared types +├── public/ +│ └── index.html # mobile dashboard +├── docs/ +│ └── plan.md # this plan (moved here) +├── CLAUDE.md +├── package.json +├── Dockerfile +├── compose.yml +└── justfile +``` + +## sqlite schema + +```sql +CREATE TABLE devices ( + id INTEGER PRIMARY KEY, + secret TEXT NOT NULL UNIQUE, + name TEXT, + created_at INTEGER NOT NULL, + last_seen INTEGER NOT NULL +); + +CREATE TABLE sessions ( + id INTEGER PRIMARY KEY, + device_id INTEGER NOT NULL, + started_at INTEGER NOT NULL, + ended_at INTEGER, + cwd TEXT, + command TEXT +); + +CREATE TABLE prompts ( + id INTEGER PRIMARY KEY, + session_id INTEGER NOT NULL, + created_at INTEGER NOT NULL, + prompt_text TEXT NOT NULL, + response TEXT, + responded_at INTEGER +); + +CREATE TABLE output_log ( + id INTEGER PRIMARY KEY, + session_id INTEGER NOT NULL, + timestamp INTEGER NOT NULL, + line TEXT NOT NULL +); +``` + +## api + +REST: +- `GET /` - dashboard +- `GET /api/sessions` - list sessions +- `POST /api/prompts/:id/approve` - approve +- `POST /api/prompts/:id/reject` - reject + +WebSocket `/ws` (CLI <-> Server): +- cli sends: auth, output, resize, exit +- server sends: input, resize, ping + +SSE `/events` (Server -> Dashboard): +- session_start, session_end, output, prompt, prompt_response + +## implementation phases + +### phase 1: foundation (~300 lines) +1. create project structure +2. `src/types.ts` - message types +3. `src/db.ts` - sqlite schema + queries +4. `src/auth.ts` - device secret + HMAC + +### phase 2: server (~250 lines) +5. `src/server.ts` - Bun.serve with routes +6. WebSocket handler for CLI +7. SSE endpoint for viewers +8. REST endpoints for approval + +### phase 3: cli wrapper (~150 lines) +9. `src/cli.ts` - spawn claude with bun-pty +10. WebSocket client to server +11. forward PTY output, handle resize + +### phase 4: dashboard (~300 lines) +12. `public/index.html` - mobile-first +13. SSE listener +14. terminal output display +15. approve/reject buttons + +### phase 5: deployment (~100 lines) +16. Dockerfile (oven/bun) +17. compose.yml with volume +18. justfile commands +19. error handling + reconnection + +## key decisions + +- bun-pty over node-pty: pure FFI, pre-built binaries +- SQLite over in-memory: persistence across restarts +- SSE over WebSocket for dashboard: simpler, auto-reconnect +- HMAC over TLS certs: simpler deployment +- plain text output over xterm.js: mobile-friendly, simpler + +## verification + +1. `bun run src/cli.ts` - starts PTY wrapper +2. visit `http://localhost:3000` - see dashboard +3. type in CLI - output appears in dashboard +4. trigger approval prompt - approve from dashboard +5. `docker compose up` - deploys successfully + +## dependencies + +```json +{ + "dependencies": { + "bun-pty": "^0.4.8" + } +} +``` + +that's it. one external dep. + +## CLAUDE.md notes + +- if bun-pty needs changes, fork and contribute upstream +- use bun:sqlite, not better-sqlite3 +- no frameworks (no express, no hono) +- target ~1000-1500 lines total