# CLAUDE.md This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. ## Commands ```bash # Development (client + server with hot reload) npm run dev # Server only npm run dev:server # Client only npm run dev:client # Production build (frontend → dist/) npm run build # Run server against built dist/ npm start ``` No test runner is configured. Tests in `test/mvp/` and `tests/` are standalone Node.js scripts run directly: ```bash node test/mvp/test-e2e.js node test/mvp/test-hooks.js ``` ## Environment Required: `CLAWTAP_PASSWORD=` Optional: `PORT` (default 3456), `OPENAI_API_KEY` (enables voice transcription) State stored in `~/.clawtap/` — SQLite DB, VAPID keys, push subscriptions, PID file. In production, the server runs as a systemd user service (`~/.config/systemd/user/clawtap.service`) with env vars loaded from `~/.clawtap/env`; use `./update-service.sh` (not `npm install -g .`) to build and redeploy. ## Architecture ClawTap bridges mobile browsers to AI CLI tools running in tmux on the dev machine. ``` Mobile PWA (React) ◄─ WebSocket ─► Express Server ◄─ tmux sendKeys ─► claude/codex/gemini CLI ``` ### Server (`server/`) - **`index.ts`** — Express app, HTTP/HTTPS server, REST routes, WS transport setup, graceful shutdown - **`session-manager.ts`** — Bridges adapter events to WebSocket clients. Transport-agnostic. Routes all adapter events (streaming-text, tool-start/done, permission-request, etc.) to connected clients. Manages push notifications when no client is watching. - **`adapters/`** — Plugin system for CLI backends - **`interface.ts`** (`IAdapter`) — Abstract base class all adapters extend. Emits standardized events; see JSDoc for full event list. - **`registry.ts`** — Registers adapters; `DEFAULT_ADAPTER` is `'claude'` - **`shared/tmux-manager.ts`** — Core tmux primitive: create windows, send keys, paste buffers (>500 chars or multiline use paste buffer instead of sendKeys) - **`claude/`**, **`codex/`**, **`gemini/`** — Per-adapter implementations - **`transport/websocket-transport.ts`** — WS server; wraps raw `ws` into `ClientConnection` abstractions - **`db.ts`** — SQLite via `better-sqlite3`; tables: `push_subscriptions`, `login_attempts`, `session_reviews`, `session_stats`, `user_preferences` - **`push.ts`** — Web Push (VAPID) notifications - **`auth.ts`** — Password-based auth with bcrypt + JWT; rate-limits login attempts by IP - **`config.ts`** — Reads env vars; auto-detects HTTPS certs at `~/.clawtap/cert.pem` + `key.pem` - **`stores/task-aggregator.ts`** — Aggregates task-tool events (TodoRead/TodoWrite/Task) into round-based groups for the mobile task panel ### Frontend (`src/`) - **`App.tsx`** — Top-level view router (sessions / newchat / chat / settings). View persisted to `sessionStorage`; URL updated via `history.pushState`. - **`lib/ws.ts`** — WebSocket singleton; reconnect logic - **`lib/api.ts`** — Fetch wrapper with JWT auth header - **`hooks/useChat.ts`** — Main chat hook: sends queries, handles all WS message types, manages message list and tool state - **`hooks/useTaskState.ts`** — Consumes `TASK_STATE` WS events; surfaces round-based task groups to the FAB - **`components/ChatView.tsx`** — Full chat screen with message list, tool cards, interactive prompt overlay, review panel - **`components/FloatingReviewPanel.tsx`** — Multi-tab cross-AI review panel - **`components/adapters/`** — Adapter-specific UI (models, permission modes, branding) ### WebSocket Protocol All message types defined in `server/ws-types.ts` (`WS` const) and `server/types/messages.ts`. Key flows: - Client sends `query` → server routes to adapter → adapter emits `streaming-text` / `tool-start` / `tool-done` / `session-idle` → server broadcasts to clients - Adapter emits `permission-request` → server sends `interactive-prompt` to client → client sends `prompt-response` → server calls `respondInteractivePrompt` - Cross-AI review: client calls `POST /api/reviews/register` → server broadcasts `review-started` to parent session clients ### Adding a New Adapter 1. Create `server/adapters//index.ts` extending `IAdapter` 2. Set static `id`, `displayName`, `command` 3. Implement `setup(app)`, `startSession`, `resumeSession`, `sendMessage`, `interrupt`, `getSessions`, `getMessages` 4. Register in `server/adapters/init.ts` 5. Add frontend branding in `src/lib/adapter-brands.ts`