CLAUDE.md · diff
git:20260503.46dcc1b to git:20260507.43746a3
1 added, 115 removed. Audit A to B.
- # CLAUDE.md
-
- This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
-
- ## What This Is
-
- **Canvas Notebook** is a self-hosted Next.js web app combining:
- - A file browser + code editor (CodeMirror) for a workspace directory
- - A terminal emulator (xterm.js + node-pty via WebSocket)
- - A spreadsheet viewer (UniverseJS)
- - An AI agent chat interface powered by the **PI framework** (`@mariozechner/pi-ai` + `@mariozechner/pi-agent-core`)
-
- ## Commands
-
- ```bash
- npm run dev # Start dev server (tsx server.js, not next dev)
- npm run build # Production build (next build --webpack)
- npm run start # Production start (bootstrap admin + tsx server.js)
- npm run lint # ESLint
-
- npm run bootstrap:admin # Create initial admin user from BOOTSTRAP_ADMIN_* env vars
-
- npm run test:smoke # Quick smoke test
- npm run test:integration # API integration tests
- npm run test:integration:pi # PI agent integration tests
- npm run test:pi:attachments # PI attachment tests
- npm run test:prompt-builder # Prompt builder tests
- npm run test:e2e # Playwright E2E tests
- npm run test:all # Full suite (build + all above)
- ```
-
- **Important:** Every `dev`, `build`, `lint`, and `test:*` command runs `npm run todos:sync:agent` as a pre-hook, which syncs implementation TODOs from managed files in `app/lib/agents/`.
-
- The dev server is `tsx server.js` (not `next dev`) because the custom server adds WebSocket support for terminals and authenticated `/media/` file serving.
-
- ## Architecture
-
- ### Custom Server (`server.js`)
- The app runs through a custom Node.js server that wraps Next.js:
- - Handles `/media/` routes with auth-gated static file serving (range requests, cache control)
- - Attaches a WebSocket server for terminal sessions (`server/terminal-server.js`)
- - Delegates everything else to Next.js
-
- ### PI Agent Streaming (`/ws/chat`)
- The main AI agent transport is the authenticated chat WebSocket at `/ws/chat`. It:
- 1. Accepts request/response messages for `subscribe_session`, `send_message`, `control`, and `get_status`
- 2. Resolves provider/model from config via `app/lib/pi/model-resolver.ts`
- 3. Resolves the API key via `app/lib/pi/api-key-resolver.ts`
- 4. Looks up or creates a PI session in SQLite (`pi_sessions`, `pi_messages` tables)
- 5. Runs the PI agent loop with registered tools from `app/lib/pi/tool-registry.ts`
- 6. Streams runtime events back as WebSocket `agent_event` messages
-
- Tools available to the agent: `ls`, `read`, `write`, `mkdir`, `terminal exec`, and others registered in `tool-registry.ts`.
-
- ### Database (`app/lib/db/`)
- SQLite via Drizzle ORM. Schema in `app/lib/db/schema.ts`. Migration config in `drizzle.config.ts`.
-
- **Migrations** are managed in `app/lib/db/migrate.ts` and run automatically at server startup (before `app.prepare()`) via `server.js`. `db/index.ts` also calls `runMigrations()` on module load as a fallback (e.g. for tests and scripts).
-
- **To add a new table:** add `CREATE TABLE IF NOT EXISTS` to `migrate.ts`.
- **To add a new column to an existing table:** add an `addColumns(sqlite, 'table_name', { col: 'TYPE DEFAULT ...' })` entry in the column-additions section of `migrate.ts`. Do NOT add migrations to `db/index.ts` — that file is now just a thin wrapper.
-
- The `drizzle/` folder contains a reference migration generated by drizzle-kit but it is **not applied automatically** — the custom `migrate.ts` runner is used instead.
-
- Tables:
- - `user`, `session`, `account`, `verification` — managed by better-auth
- - `pi_sessions`, `pi_messages` — PI agent conversation persistence
- - `ai_sessions`, `ai_messages` — legacy, kept for compatibility
- - `studio_generations`, `studio_generation_outputs`, `studio_products`, `studio_personas`, `studio_styles`, `studio_presets`, `studio_bulk_jobs`, `studio_bulk_job_line_items` — Studio image/video generation
- - `automation_jobs`, `automation_runs` — scheduled automations
- - `pi_usage_events` — token usage tracking
- - `oauth_tokens` — provider OAuth tokens
- - `user_hint_state`, `page_onboarding_state`, `onboarding_log` — onboarding state
-
- ### Authentication (`app/lib/auth.ts`)
- better-auth with SQLite adapter. Session cookies cached for 5 minutes. Signup can be disabled via `ALLOW_SIGNUP=false`. Custom `role` field on users. Bootstrap admin user created from `BOOTSTRAP_ADMIN_EMAIL` / `BOOTSTRAP_ADMIN_PASSWORD` env vars.
-
- ### Terminal (`server/terminal-server.js`, `server/terminal-manager.js`)
- WebSocket-based PTY sessions. Max 3 terminals per user, 30-min idle timeout. Sessions are in-memory only (lost on server restart).
-
- ### Workspace & Files
- Base data path is configurable via `DATA` env (defaults to `./data`). Workspace files are stored under `${DATA}/workspace`. File CRUD via `app/api/files/`. The workspace path is sandboxed — file API rejects paths that escape it.
-
- ### PI Agent Config (`app/lib/pi/config.ts`)
- Config is file-based (PI v2 format), provider-driven. Supports openrouter, anthropic, google, ollama. The agent system prompt is composed from managed files in `app/lib/agents/` (synced by `scripts/sync-agent-todos.mjs`).
-
- ## Key Environment Variables
-
- ```
- BETTER_AUTH_SECRET # Required: 32-byte base64 session key
- BETTER_AUTH_BASE_URL # Required: auth redirect base URL
- DATA # Base data path (default: ./data). Workspace, SQLite, and skills stored under this path.
- ALLOW_SIGNUP # Set to "false" to disable registration
- BOOTSTRAP_ADMIN_EMAIL # Admin email for initial setup
- BOOTSTRAP_ADMIN_PASSWORD # Admin password for initial setup
- CLAUDE_API_KEY # Anthropic Claude API key
- OPENROUTER_API_KEY # OpenRouter API key
- GEMINI_API_KEY # Google Gemini API key
- OLLAMA_BASE_URL # Local Ollama endpoint
- INTEGRATIONS_ENV_PATH # Path to integrations secrets file
- AGENTS_ENV_PATH # Path to agents secrets file
- ```
-
- ## State Management
-
- UI state is managed with Zustand. The main store is in `app/lib/store/` or co-located with components. Server state flows through Next.js API routes — no tRPC or React Query.
-
- ## Docker
-
- ```bash
- docker compose up # Uses compose.yaml, single service
- ```
-
- Data volumes: `/data/workspace` (files), `/data/sqlite.db` (database), `/home/node` (npm globals/CLI config). Optionally installs `codex`, `claude`, or `ollama` at container startup based on env vars.
-
+ @AGENTS.md