6.1 KiB
CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
Project Overview
Spiceflow is an AI Session Orchestration PWA for monitoring and interacting with Claude Code and OpenCode CLI sessions from mobile devices or web browsers. It's a monorepo with three main components: a Clojure backend server, a SvelteKit frontend, and Playwright E2E tests.
Commands
Backend (Clojure)
cd server
clj -M:run # Start server (port 3000)
clj -M:test # Run tests with Kaocha
clj -M:repl # Start REPL with nREPL for interactive development
Frontend (SvelteKit)
cd client
npm install # Install dependencies
npm run dev # Start dev server (port 5173, proxies /api to 3000)
npm run build # Production build
npm run check # Type checking with svelte-check
npm run check:watch # Watch mode for type checking
E2E Tests (Playwright)
cd e2e
npm test # Run all tests (starts both servers automatically)
npm run test:headed # Run tests with visible browser
npm run test:ui # Interactive Playwright UI mode
E2E tests use a separate database (server/test-e2e.db).
Development Scripts
./script/dev # Start backend + frontend concurrently
./script/test # Start servers and run E2E tests
The dev script starts both servers and waits for each to be ready before proceeding. The test script uses a separate test database and cleans up after tests complete.
Architecture
Claude Code/OpenCode CLI ↔ Spiceflow Server (Clojure) ↔ PWA Client (SvelteKit)
↓
SQLite DB
Backend (/server)
- Entry point:
src/spiceflow/core.clj- Ring/Jetty server with mount lifecycle - Routing:
src/spiceflow/api/routes.clj- Reitit-based REST API - Database: Protocol-based abstraction (
db/protocol.clj) with SQLite (db/sqlite.clj) and in-memory (db/memory.clj) implementations - Adapters: Pluggable CLI integrations (
adapters/protocol.clj) - Claude Code (adapters/claude.clj) and OpenCode (adapters/opencode.clj) - WebSocket:
api/websocket.clj- Real-time message streaming - Session management:
session/manager.clj- Session lifecycle
Frontend (/client)
- Routes: SvelteKit file-based routing in
src/routes/ - State: Svelte stores in
src/lib/stores/(sessions, runtime selection) - API client:
src/lib/api.ts- HTTP and WebSocket clients - Components:
src/lib/components/- UI componentsMessageList.svelte- Displays messages with collapsible long contentPermissionRequest.svelte- Permission prompts with accept/deny/steer actionsFileDiff.svelte- Expandable file diffs for Write/Edit operationsSessionSettings.svelte- Session settings dropdown (auto-accept edits)InputBar.svelte- Message input with steer mode support
- PWA: vite-plugin-pwa with Workbox service worker
- Responsive: Landscape mobile mode collapses header to hamburger menu
Key Protocols
DataStore (db/protocol.clj):
get-sessions,get-session,save-session,update-session,delete-sessionget-messages,save-message
AgentAdapter (adapters/protocol.clj):
discover- Find existing CLI sessionsspawn- Start CLI process with sessionsend- Pipe message to stdinread-stream- Parse JSONL output- Adding new runtimes requires implementing this protocol
Configuration
Server configuration via server/resources/config.edn or environment variables:
| Variable | Default | Description |
|---|---|---|
SPICEFLOW_PORT |
3000 | Server port |
SPICEFLOW_HOST |
0.0.0.0 | Server host |
SPICEFLOW_DB |
spiceflow.db | SQLite database path |
CLAUDE_SESSIONS_DIR |
~/.claude/projects | Claude sessions directory |
OPENCODE_CMD |
opencode | OpenCode command |
Features
Permission Handling
When Claude Code requests permission for file operations (Write/Edit) or shell commands (Bash), Spiceflow intercepts these and presents them to the user:
- Accept: Grant permission and continue
- Deny: Reject the request
- Steer ("No, and..."): Redirect Claude with alternative instructions
File operations show expandable diffs displaying the exact changes being made.
Auto-Accept Edits
Claude sessions can enable "Auto-accept edits" in session settings to automatically grant Write/Edit permissions, reducing interruptions during coding sessions.
Session Management
- Rename: Click session title to rename
- Delete: Remove sessions from the session list
- Condense: Collapse long messages for easier scrolling
Mobile Optimization
- Landscape mode collapses the header to a hamburger menu
- Compact file diffs with minimal padding
- Touch-friendly permission buttons
Session Flow
- User opens PWA → sees list of tracked sessions
- User selects session → loads message history
- User types message → POST to
/api/sessions/:id/send - Server spawns CLI process with
--resumeflag - Server pipes user message to stdin
- CLI streams response via stdout (JSONL format)
- Server broadcasts to client via WebSocket
- If permission required → WebSocket sends permission request → User accepts/denies/steers
- Process completes → response saved to database
API Endpoints
| Endpoint | Method | Description |
|---|---|---|
/api/health |
GET | Health check |
/api/sessions |
GET | List all sessions |
/api/sessions |
POST | Create new session |
/api/sessions/:id |
GET | Get session with messages |
/api/sessions/:id |
PATCH | Update session (title, auto-accept-edits) |
/api/sessions/:id |
DELETE | Delete session |
/api/sessions/:id/send |
POST | Send message to session |
/api/sessions/:id/permission |
POST | Respond to permission request |
/ws |
WebSocket | Real-time message streaming |
Tech Stack
- Backend: Clojure 1.11, Ring/Jetty, Reitit, next.jdbc, SQLite, mount, Kaocha
- Frontend: SvelteKit 2.5, Svelte 4, TypeScript, Tailwind CSS, Vite, vite-plugin-pwa
- E2E: Playwright