Files

4.4 KiB

CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

Commands

# 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:

node test/mvp/test-e2e.js
node test/mvp/test-hooks.js

Environment

Required: CLAWTAP_PASSWORD=<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/<name>/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