CLAUDE.md@apps/canvas-workspace · git:20260621.d32c4bf · 2026-06-21 · sha256 b5caa9c12bbda462
CLAUDE.md@apps/canvas-workspace git:20260621.d32c4bfA
Immutable. This exact content is served forever at /api/v1/blob/b5caa9c12bbda462.
# CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working in
`apps/canvas-workspace`. It complements the repo-root `CLAUDE.md`.
## Overview
**Pulse Canvas** (`canvas-workspace`) is an Electron desktop app that provides a
free-form, infinite canvas workspace for AI-assisted coding. Users arrange
**nodes** on a canvas and interact with an embedded AI agent powered by
`pulse-coder-engine`.
## Tech Stack
- **Electron** (v30) + **electron-vite** — desktop shell and build pipeline
- **React** (v18) + **wouter** — renderer UI and routing
- **Tiptap** (v3) — rich-text editor for file nodes
- **xterm.js** + **node-pty** — terminal emulation in terminal/agent nodes
- **pulse-coder-engine** + **pulse-coder-agent-teams** (`workspace:*`) — power the
in-app AI agent and multi-agent flows
- **zod**, **markdown-it**, **mermaid**, **react-force-graph-2d** — schema,
markdown, diagrams, and graph rendering
## Node Types
| Type | Description |
|------|-------------|
| `file` | Tiptap-based rich-text/markdown editor backed by a real file path |
| `terminal` | Full PTY terminal session |
| `agent` | Runs an external AI agent CLI (e.g. `claude`) in a PTY; accepts inline prompts or prompt files |
| `frame` | Visual grouping rectangle with a label/color |
## Views & Shortcuts
- **Canvas view** (`/`) — free-form canvas with sidebar, node editing, optional right-side chat panel.
- **Chat view** (`/chat`) — full-screen AI chat page backed by `pulse-coder-engine`.
| Shortcut | Action |
|----------|--------|
| `Cmd/Ctrl+Shift+A` | Toggle right-side chat panel (canvas view only) |
| `Cmd/Ctrl+Shift+L` | Toggle full-screen chat view |
| `Esc` | Return to canvas from chat view |
## Project Structure
```
src/
main/ # Electron main process (domain-based modules)
app/ # Electron bootstrap, window, protocol, logging, link policy
agent/ # CanvasAgent + CanvasAgentService (engine-backed AI chat)
agent-teams/ # Multi-agent teams integration (pulse-coder-agent-teams)
artifacts/ # Artifact persistence and artifact IPC
canvas/ # Canvas persistence, storage migration, nodes, tags, broadcast
files/ # File read/write/dialog IPC and filesystem watcher
generation/ # HTML generation and streaming IPC
runtime/ # Runtime control server and MCP helpers
settings/ # App/model settings persistence and IPC
terminal/ # node-pty session management
webview/ # Webview registry, CDP helpers, page reader
index.ts # Main entry
preload/ # Context bridge (exposes window.canvasWorkspace API)
renderer/src/
components/ # Canvas, Sidebar, AgentNodeBody, FileNodeBody, chat/, …
hooks/ # useWorkspaces, canvas interaction hooks
editor/ # Tiptap editor setup
config/ constants/ i18n/ utils/
types.ts # Shared types (CanvasNode, CanvasWorkspaceApi, …)
```
The renderer communicates with the main process **exclusively** through
`window.canvasWorkspace` (typed in `types.ts`), bridged via `src/preload/`.
Never reach into Electron/Node APIs directly from the renderer — add an IPC
channel in the relevant `src/main/<domain>/` module and expose it through preload.
See `docs/main-domain-modules.md` for the `src/main` module layout and migration
plan, and `docs/renderer-surfaces.md` for renderer surface breakdown.
## Dev & Build Commands
```bash
pnpm install # also runs electron-rebuild for node-pty
pnpm --filter canvas-workspace dev # development (hot reload)
pnpm --filter canvas-workspace build # production build
pnpm --filter canvas-workspace typecheck # tsc --noEmit (renderer + main)
pnpm --filter canvas-workspace test # vitest run
# Packaging (output → release/, appId com.pulse-coder.canvas-workspace)
pnpm --filter canvas-workspace package # current platform
pnpm --filter canvas-workspace package:mac # macOS dmg (arm64 + x64)
pnpm --filter canvas-workspace package:win # Windows nsis x64
pnpm --filter canvas-workspace package:linux # Linux AppImage + deb x64
```
`typecheck` runs two tsconfigs (`tsconfig.json` for renderer, `tsconfig.node.json`
for main). `dev:temp-home` runs against a throwaway `$HOME` sandbox.
## Canvas Agent & Model Config
The AI chat feature is powered by `CanvasAgentService` (`src/main/agent/`), which
wraps `pulse-coder-engine`. Each workspace keeps its own agent session, persisted
under the workspace data directory, and receives a workspace/node summary as
context on every turn.
Model settings are read from `~/.pulse-coder/canvas/model-config.json` by default
(override with `PULSE_CANVAS_MODEL_CONFIG`). The config supports OpenAI-compatible
and Anthropic-compatible providers and stores only **env var names** for API keys,
never secret values. The renderer manages the same config through
`window.canvasWorkspace.model` (`status`, `saveConfig`, `upsertOption`,
`setCurrent`, `removeOption`, `reset`); changes apply to new agent turns and HTML
generation without restarting the app.
## Data Persistence
Canvas state (node positions, types, data) is saved per workspace as JSON via
`src/main/canvas/`. File nodes are backed by real files on disk; the file watcher
pushes external changes into the renderer via IPC.
## Coding Conventions
Detailed, reusable rules live in **[`docs/conventions/`](./docs/conventions/README.md)**.
Read the relevant doc before writing or reviewing code:
- **[`docs/conventions/README.md`](./docs/conventions/README.md)** — index + baseline rules.
- **[`docs/conventions/architecture-boundaries.md`](./docs/conventions/architecture-boundaries.md)**
— process layers (`shared`/`main`/`preload`/`renderer`), import rules, and
file-size governance. **Enforced by tests** (`src/main/__tests__/import-boundaries.test.ts`,
`file-size-governance.test.ts`).
- **[`docs/conventions/frontend.md`](./docs/conventions/frontend.md)** — renderer
(React) component/hook/styling/i18n/IPC-consumption conventions.
- **[`docs/conventions/backend.md`](./docs/conventions/backend.md)** — main
process domain modules, IPC, services, and persistence conventions.
Quick reminders (see the docs for the full rules):
- TypeScript strict mode; match local file style (2 spaces, semicolons, ESM
imports). Keep diffs minimal and preserve existing patterns.
- Aim **≤ 300 lines per component/module**; new files must stay **≤ 500**
(hard-gated). Split by responsibility rather than growing a file.
- Renderer reaches the main process **only** through `window.canvasWorkspace`
(preload bridge); domain logic lives in `src/main/<domain>/`.
- Cross-package imports use workspace package names (`pulse-coder-engine`,
`pulse-coder-agent-teams`).