openpencil/AGENTS.md
Kayshen-X c4e5359596 docs: drop op export from CLI docs and clarify pen-mcp usage
The `op export` command was removed in 0.7.x but the README still
advertised it (#116). The pen-mcp README also documented an
`npx @zseven-w/pen-mcp` quick-start that never worked because the
package ships TypeScript source against workspace-only deps with no
`bin` entry (#117).

- Strip `op export` references from all 15 root and 15 cli READMEs
- Sync AGENTS.md, CLAUDE.md, apps/cli/CLAUDE.md to match the codegen-
  pipeline reality (no standalone export command anymore)
- Rewrite pen-mcp README's quick-start: explain the package ships as
  part of the OpenPencil app and external clients connect over HTTP

Closes #116
Closes #117
2026-04-26 19:20:14 +08:00

146 lines
7.6 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# AGENTS.md
This file provides guidance to Codex (Codex.ai/code) when working with code in this repository.
Detailed module docs are in `packages/AGENTS.md`, `apps/web/AGENTS.md`, `apps/desktop/AGENTS.md`, and `apps/cli/AGENTS.md` — loaded automatically when working in those directories.
## Commands
- **Dev server:** `bun --bun run dev` (runs on port 3000)
- **Build:** `bun --bun run build`
- **Preview production build:** `bun --bun run preview`
- **Run all tests:** `bun --bun run test` (Vitest)
- **Run a single test:** `bun --bun vitest run path/to/test.ts`
- **Type check:** `npx tsc --noEmit`
- **Install dependencies:** `bun install`
- **Bump version:** `bun run bump <version>` (syncs all package.json files)
- **Electron dev:** `bun run electron:dev` (starts Vite + Electron together)
- **Electron compile:** `bun run electron:compile` (esbuild electron/ to out/desktop/)
- **Electron build:** `bun run electron:build` (full web build + compile + electron-builder package)
- **CLI compile:** `bun run cli:compile` (esbuild CLI to apps/cli/dist/)
- **CLI dev:** `bun run cli:dev` (run CLI from source via Bun)
- **Publish beta:** `bun run publish:beta [N]` (publish all npm packages with beta tag)
## Architecture
OpenPencil is an open-source vector design tool (alternative to Pencil.dev) with a Design-as-Code philosophy. Organized as a **Bun monorepo** with workspaces:
```text
openpencil/
├── apps/
│ ├── web/ TanStack Start full-stack React app (Vite + Nitro)
│ ├── desktop/ Electron desktop app (macOS, Windows, Linux)
│ └── cli/ CLI tool — control the design tool from the terminal
├── packages/
│ ├── pen-types/ Type definitions for PenDocument model
│ ├── pen-core/ Document tree ops, layout engine, variables, boolean ops, clone utilities
│ ├── pen-codegen/ Multi-platform code generators
│ ├── pen-figma/ Figma .fig file parser and converter
│ ├── pen-renderer/ Standalone CanvasKit/Skia renderer
│ ├── pen-sdk/ Umbrella SDK (re-exports all packages)
│ ├── pen-ai-skills/ AI prompt skill engine (phase-driven prompt loading + design memory)
│ └── agent/ Domain-agnostic AI agent SDK (Vercel AI SDK, multi-provider, agent teams)
├── scripts/ Build and publish scripts
└── .githooks/ Pre-commit version sync from branch name
```
**Key technologies:** React 19, CanvasKit/Skia WASM (canvas engine), Paper.js (boolean path operations), Zustand v5 (state management), TanStack Router (file-based routing), Tailwind CSS v4, shadcn/ui (UI primitives), Vite 7, Nitro (server), Electron 35 (desktop), Vercel AI SDK v6 (agent framework), i18next (15 locales), TypeScript (strict mode).
### Data Flow
```text
React Components (Toolbar, LayerPanel, PropertyPanel)
│ Zustand hooks
┌─────────────────┐ ┌───────────────────┐
│ canvas-store │ │ document-store │ ← single source of truth
│ (UI state: │ │ (PenDocument) │
│ tool/selection │ │ CRUD / tree ops │
│ /viewport) │ │ │
└────────┬────────┘ └────────┬──────────┘
│ │
▼ ▼
CanvasKit/Skia canvas-sync-lock
(GPU-accelerated (prevents circular sync)
WASM renderer)
```
- **document-store** is the single source of truth. CanvasKit only renders.
- User edits on canvas → SkiaEngine events → update document-store
- User edits in panels → update document-store → SkiaEngine `syncFromDocument()` re-renders
- `canvas-sync-lock.ts` prevents circular updates when canvas events write to the store
### Multi-Page Architecture
```text
PenDocument
├── pages?: PenPage[] (id, name, children)
└── children: PenNode[] (default/single-page fallback)
```
### Design Variables Architecture
- **`$variable` references are preserved** in the document store (e.g. `$color-1` in fill color)
- `resolveNodeForCanvas()` resolves `$refs` on-the-fly before CanvasKit rendering
- Code generators output `var(--name)` for `$ref` values
- Multiple theme axes supported (e.g. Theme-1 with Light/Dark, Theme-2 with Compact/Comfortable)
### MCP Layered Design Workflow
External LLMs (Codex, Codex, Gemini CLI, etc.) can generate designs via MCP:
- **Single-shot**: `batch_design` or `insert_node` — one call
- **Layered**: `design_skeleton``design_content` × N → `design_refine` — phased generation with focused context
- **Segmented prompts**: `get_design_prompt(section=...)` loads focused subsets (schema, layout, roles, icons, etc.)
### Path Aliases
`@/*` maps to `./src/*` (configured in `apps/web/tsconfig.json` and `apps/web/vite.config.ts`).
### Styling
Tailwind CSS v4 imported via `apps/web/src/styles.css`. UI primitives from shadcn/ui. Icons from `lucide-react`.
### CLI (`apps/cli/`)
The `op` command-line tool controls the desktop app or web server from the terminal. Arguments that accept JSON or DSL support three input methods: inline string, `@filepath` (read from file), or `-` (read from stdin).
- **App control:** `op start [--desktop|--web]`, `op stop`, `op status`
- **Design:** `op design <dsl|@file|->` — batch design DSL operations
- **Document:** `op open`, `op save`, `op get`, `op selection`
- **Nodes:** `op insert`, `op update`, `op delete`, `op move`, `op copy`, `op replace`
- **Cross-platform:** macOS, Windows (NSIS/portable), Linux (AppImage/deb/snap/flatpak)
### CI / CD
- **`.github/workflows/ci.yml`** — Push/PR on `main` and `v*` branches: type check, tests, web build
- **`.github/workflows/build-electron.yml`** — Tag push (`v*`) or manual: builds Electron for all platforms, creates draft GitHub Release
- **`.github/workflows/publish-cli.yml`** — Tag push (`v*`) or manual: publishes all `@zseven-w/*` npm packages in topological order
- **`.github/workflows/docker.yml`** — Docker image build and push
### Version Sync
- **Pre-commit hook** (`.githooks/pre-commit`): extracts version from branch name (e.g. `v0.5.0``0.5.0`) and syncs to all `package.json` files
- **Manual bump:** `bun run bump <version>` to set a specific version across all workspaces
- Requires `git config core.hooksPath .githooks` (one-time setup per clone)
## Code Style
- Single files must not exceed 800 lines. Split into smaller modules when they grow beyond this limit.
- One component per file, each with a single responsibility.
- `.ts` and `.tsx` files use kebab-case naming, e.g. `canvas-store.ts`, `use-keyboard-shortcuts.ts`.
- UI components must use shadcn/ui design tokens (`bg-card`, `text-foreground`, `border-border`, etc.). No hardcoded Tailwind colors like `gray-*`, `blue-*`.
- Toolbar button active state uses `isActive` conditional className (`bg-primary text-primary-foreground`), not Radix Toggle's `data-[state=on]:` selector (has twMerge conflicts).
## Git Commit Convention
Use [Conventional Commits](https://www.conventionalcommits.org/) format: `<type>(<scope>): <subject>`
**Types:** `feat`, `fix`, `refactor`, `perf`, `style`, `docs`, `test`, `chore`
**Scopes:** `editor`, `canvas`, `panels`, `history`, `ai`, `codegen`, `store`, `types`, `variables`, `figma`, `mcp`, `electron`, `renderer`, `sdk`, `cli`, `agent`, `i18n`
**Rules:** Subject in English, lowercase start, no period, imperative mood. Body is optional; explain **why** not what. One commit per change.
## License
MIT License. See [LICENSE](./LICENSE) for details.