## File: README.md

# Open CoDesign

**简体中文**: [README.zh-CN.md](./README.zh-CN.md)

> Your prompts. Your model. Your laptop.
>
> Turn prompts into polished artifacts — locally, openly, and with whichever model you already pay for.

[Website](https://opencoworkai.github.io/open-codesign/) · [Quickstart](#quickstart) · [What's new](https://github.com/OpenCoworkAI/open-codesign/releases) · [Changelog](./CHANGELOG.md) · [Discussions](https://github.com/OpenCoworkAI/open-codesign/discussions) · [Docs](https://opencoworkai.github.io/open-codesign/quickstart) · [Contributing](./CONTRIBUTING.md) · [Security](./SECURITY.md)

**Open-source alternative to:** [Claude Design](https://opencoworkai.github.io/open-codesign/claude-design-alternative) · [v0 by Vercel](https://opencoworkai.github.io/open-codesign/v0-alternative) · [Lovable](https://opencoworkai.github.io/open-codesign/lovable-alternative) · [Bolt.new](https://opencoworkai.github.io/open-codesign/bolt-alternative) · [Figma AI](https://opencoworkai.github.io/open-codesign/figma-ai-alternative)









---

## What's new

- **`feat/decompose-to-ui-kit`** *(branch)* — Image -> componentized `ui_kits/<slug>/` bundle for coding-agent handoff · Boolean-per-dimension visual parity judge (12 standard checks) · Verify-and-iterate loop · Per-decompose cost row · See [BENCHMARKS.md](./BENCHMARKS.md). Refs [#225](https://github.com/OpenCoworkAI/open-codesign/issues/225).
- **v0.2.0** *(2026-05-09)* — Agentic Design: workspace-backed sessions · permissioned local tools · Files panel upgrades · provider diagnostics · security hardening · `DESIGN.md` design systems
- **v0.1.4** *(2026-04-23)* — AI image generation · ChatGPT Plus/Codex subscription support · CLIProxyAPI one-click import · API config hardening
- **v0.1.3** *(2026-04-21)* — Gemini `models/` prefix fix · OpenAI-compatible relay "instructions required" fix · third-party relay SSE-truncation hint
- **v0.1.2** *(2026-04-21)* — Release pipeline · Homebrew / winget / Scoop packaging manifests

[Full release history →](https://github.com/OpenCoworkAI/open-codesign/releases) · [Changelog →](./CHANGELOG.md)

---

## What it is

Turn a prompt into a polished prototype, slide deck, or marketing asset, locally, with the model you already use.

**Open CoDesign is the open-source Claude Design alternative** — built for people who want the speed of AI-native design tools without subscription lock-in, cloud-only workflows, or being forced onto a single provider. An MIT-licensed desktop app, local-first from day one, with BYOK for any model (Claude, GPT, Gemini, DeepSeek, Kimi, GLM, Ollama, or any OpenAI-compatible endpoint) plus direct ChatGPT Plus / Pro / Team subscription sign-in for Codex models. One-click import of existing Claude Code or Codex provider configs, or one-click ChatGPT sign-in, gets you running in under 90 seconds.

---

## See it generate

From a blank prompt to a finished artifact, the agent plans, writes, self-checks, and ships something with hover states, tabs, and empty states already wired up:



---

## Why people star it

- **Runs on your laptop** — no mandatory cloud workspace
- **Works with your model** — Claude, GPT, Gemini, Ollama, OpenRouter, and more
- **Exports real files** — HTML, PDF, PPTX, ZIP, Markdown
- **Shows its work** — live agent activity, visible tool calls, interruptible generation

---

## Why Open CoDesign?

Open source, desktop-native, and built for people who do not want their design workflow locked to one model or one cloud.

| | **Open CoDesign** | Claude Design | v0 by Vercel | Lovable |
|---|:---:|:---:|:---:|:---:|
| Open source | ✅ MIT | ❌ Closed | ❌ Closed | ❌ Closed |
| Desktop native | ✅ Electron | ❌ Web only | ❌ Web only | ❌ Web only |
| Bring your own key | ✅ Any provider | ❌ Anthropic only | ❌ Vercel only | ⚠️ Limited |
| Local / offline | ✅ Fully local app | ❌ Cloud | ❌ Cloud | ❌ Cloud |
| Models | ✅ 20+ (Claude, GPT, Gemini, Ollama…) | Claude only | GPT-4o | Multi-LLM |
| Version history | ✅ Local sessions + workspace files | ❌ | ❌ | ❌ |
| Data privacy | ✅ On-device app state | ❌ Cloud-processed | ❌ Cloud | ❌ Cloud |
| Editable export | ✅ HTML, PDF, PPTX, ZIP, Markdown | ⚠️ Limited | ⚠️ Limited | ⚠️ Limited |
| Price | ✅ Free app, provider/subscription cost only | 💳 Subscription | 💳 Subscription | 💳 Subscription |

---

## Highlights



| **Comment, don’t retype.**Click any element, drop a pin, and let the model rewrite only that region. | **AI-tuned sliders.**The model surfaces the parameters worth tweaking, so you can refine color, spacing, and typography without another full prompt. |
| --- | --- |
| **Every iteration, kept.**Designs are saved locally, with instant switching between recent versions. | **Watch the agent work.**Todos, tool calls, and live progress stay visible and interruptible throughout generation. |



---

## Quickstart

**Time to first artifact:** about 3 minutes

**Requires:** one API key, ChatGPT subscription sign-in, or local Ollama

**Runs on:** macOS 12+ (Monterey or later), Windows 10+, Linux (glibc ≥ 2.31)

### 1. Install

**Package manager** (recommended):

```bash
# macOS
brew install --cask opencoworkai/tap/open-codesign

# Windows — Scoop
scoop bucket add opencoworkai https://github.com/OpenCoworkAI/scoop-bucket
scoop install opencoworkai/open-codesign
```

**Or direct download** from the [v0.2.0 GitHub Release](https://github.com/OpenCoworkAI/open-codesign/releases/tag/v0.2.0):

| Platform | File |
|---|---|
| macOS (Apple Silicon) | `open-codesign-*-arm64.dmg` |
| macOS (Intel) | `open-codesign-*-x64.dmg` |
| Windows (x64) | `open-codesign-*-x64-setup.exe` |
| Windows (ARM64) | `open-codesign-*-arm64-setup.exe` |
| Linux (x64, AppImage) | `open-codesign-*-x64.AppImage` |
| Linux (x64, Debian/Ubuntu) | `open-codesign-*-x64.deb` |
| Linux (x64, Fedora/RHEL) | `open-codesign-*-x64.rpm` |

Each release ships with `SHA256SUMS.txt` and a CycloneDX SBOM (`*-sbom.cdx.json`) so you can verify what you downloaded.


**More package managers**

| Manager | Command | Status |
|---|---|---|
| Homebrew Cask (macOS) | `brew install --cask opencoworkai/tap/open-codesign` | 🟢 Live |
| Scoop (Windows) | `scoop bucket add opencoworkai https://github.com/OpenCoworkAI/scoop-bucket && scoop install opencoworkai/open-codesign` | 🟢 Live |
| winget (Windows) | `winget install OpenCoworkAI.OpenCoDesign` | 🟡 PR submitted; waiting for Microsoft review |
| Flathub (Linux) | `flatpak install flathub ai.opencowork.codesign` | ⏸ Deferred; needs signed build + AppStream metadata |
| Snap (Linux) | `snap install --dangerous open-codesign-*.snap` | 🟡 Attached to releases best-effort; Snap Store publish not yet wired |

After each stable tag push, CI syncs SHAs back into `packaging/` and publishes downstream Homebrew/Scoop updates when the repo secrets are configured. The first winget submission is in review; once Microsoft accepts the package, future winget bumps can be automated from the release workflow. Every `packaging/*/README.md` documents its own channel.


> **Unsigned installer note:** installers are not notarized or Authenticode-signed yet. On **macOS Sequoia 15+** right-click → Open no longer bypasses Gatekeeper, and "Open Anyway" in System Settings often fails. Reliable one-liner:
>
> ```sh
> xattr -cr "/Applications/Open CoDesign.app"
> ```
>
> Then double-click normally. (Older 0.1.x builds are installed as `/Applications/open-codesign.app`.)
> On **Windows**: SmartScreen → More info → Run anyway.
>
> Want a verified build? Compile from source — see [CONTRIBUTING.md](./CONTRIBUTING.md).

### 2. Add a provider

On first launch, Open CoDesign opens the Settings page. Pick the path that matches how you already use models:

- **ChatGPT subscription** — sign in with ChatGPT to use Codex models without pasting an API key.
- **API key** — paste Anthropic (`sk-ant-...`), OpenAI (`sk-...`), Google Gemini, OpenRouter, SiliconFlow, DeepSeek, or another supported provider key.
- **Local / keyless** — use Ollama or an IP-allowlisted OpenAI-compatible gateway.

Credentials stay in `~/.config/open-codesign/config.toml` and the ChatGPT OAuth token store under the app config directory. Nothing leaves your machine unless your chosen model route requires it.

### 3. Type your first prompt

Pick one of **fifteen built-in demos** — landing page, dashboard, pitch slide, pricing, mobile app, chat UI, event calendar, blog article, receipt/invoice, portfolio, settings panel, and more — or describe your own. A sandboxed prototype appears in seconds.

---

## Bring your stack

Already using Claude Code or Codex? API-key provider configs import in one click, with no copy-paste and no need to re-enter settings. If you use Codex through ChatGPT subscription login, sign in directly from Settings:



---

## Built-in taste

Generic AI tools tend to produce generic output. Open CoDesign ships with **twelve built-in design skill modules** — slide decks, dashboards, landing pages, SVG charts, glassmorphism, editorial typography, heroes, pricing, footers, chat UIs, data tables, and calendars — plus a built-in taste layer that steers the model toward considered typography, purposeful whitespace, and meaningful color.

Every skill is available in every generation. Before the model writes a line of CSS, it selects the skills that fit the brief and reasons through layout intent, design-system coherence, and contrast, bringing higher-quality design behavior to whichever model you choose.

Add a `SKILL.md` to any project to teach the model your own taste.

---

## What you get

### Models and providers
- **Unified provider model** — Anthropic, OpenAI, Gemini, DeepSeek, OpenRouter, SiliconFlow, local Ollama, or any OpenAI-compatible relay; keyless (IP-allowlisted) proxies supported
- **One-click import and sign-in** — bring Claude Code / Codex API-key provider configs across, or sign in with ChatGPT subscription for Codex models
- **Dynamic model picker** — every provider exposes its real model catalogue, not a hardcoded shortlist

### Generation and editing
- **Prompt → HTML or JSX/React component** prototype, rendered in a sandboxed iframe (vendored React 18 + Babel on-device)
- **Fifteen built-in demos + twelve design skill modules** — ready-to-edit starting points for common design briefs
- **Live agent panel** — watch tool calls stream in real time as the model edits files
- **AI image generation** — opt-in bitmap assets for heroes, product shots, backgrounds, and illustrations via OpenAI, OpenRouter, or signed-in ChatGPT subscription
- **AI-generated sliders** — the model emits the parameters worth tweaking (color, spacing, font)
- **Comment mode** — click any element in the preview to drop a pin, leave a note, and let the model rewrite only that region
- **Decompose to UI Kit** — one click in the chat sidebar emits a `ui_kits/<slug>/` folder (`index.html` + `components/*.tsx` + `tokens.css` + `manifest.json` + `README.md`) shaped for coding-agent handoff. Built-in deterministic + vision verifiers self-check parity using a 12-question boolean rubric (no floating-point arbitrary scores) and re-iterate on gaps. Per-decompose cost surfaces inline as a toast. See [BENCHMARKS.md](./BENCHMARKS.md).

  
  <sub>Source image (gpt-image input) on the left, agent-emitted `ui_kit` rendered headlessly on the right. Parity score and status are derived deterministically — `parityScore = passCount / totalChecks` — from the 12-check boolean rubric. Numbers are from a real `e2e-opus-final` run, not a mock.</sub>

  
  <sub>4-frame reel from the `e2e-nodebench-iter` run: source → iter-0 (parityScore 0.82, 6 gaps) → iter-1 (parityScore 0.78, 5 gaps) → honest verdict. The agent fixed some gaps and introduced new layout drift; the boolean rubric exposes the regression instead of hiding it. [MP4 version](https://raw.githubusercontent.com/OpenCoworkAI/open-codesign/main/website/public/demos/decompose-iter-reel.mp4).</sub>
- **Generation cancellation** — stop mid-stream without losing prior turns

### Preview and workflow
- **Phone / tablet / desktop preview** — true responsive frames, switch with one click
- **Files panel** — inspect multi-file artifacts (HTML, CSS, JS) before export
- **Instant design switching** — the last five designs keep their preview iframes alive, so Hub ↔ Workspace and sidebar navigation stay zero-delay
- **Connection diagnostic panel** — one-click test for any provider, with actionable errors
- **Per-generation token counter** — see exactly how many tokens each run cost in the sidebar
- **Settings with four tabs** — Models, Appearance, Storage, and Advanced
- **Light + dark themes**, **EN + 简体中文 UI** with live toggle

### Export and packaging
- **Five export formats** — HTML (inlined CSS), PDF (local Chrome), PPTX, ZIP, Markdown
- **GitHub Release pipeline** — unsigned DMG (macOS), EXE (Windows), AppImage (Linux). Code-signing lands in v0.5 along with opt-in auto-update

---

## Roadmap

Current release: v0.2.0. The current release theme is **Agentic Design**.

### Now — v0.2.0 shipped

v0.2 turns Open CoDesign from a one-shot generator into a local design agent with a real workspace:

- **Design as session** — every design is a pi session with JSONL history and a workspace folder on disk
- **Permissioned agent loop** — pi built-ins for read, write, edit, bash, grep, find, and ls, gated by Open CoDesign's permission UI
- **Design tools on demand** — `ask`, `scaffold`, `skill`, `preview`, `gen_image`, `tweaks`, `todos`, and `done`
- **`DESIGN.md` as shared memory** — brand tokens and design-system decisions become editable files, not model memory
- **v0.1 migration path** — existing SQLite designs migrate into workspaces and session history

### Previous — v0.1.4

- **AI image generation** — opt-in bitmap assets through OpenAI image models or OpenRouter image models
- **ChatGPT Plus / Codex subscription login** — one-click OAuth for users who do not want to paste an API key
- **CLIProxyAPI one-click import** — auto-detect a running local proxy and bring it into Settings
- **API config hardening** — clearer relay diagnostics for timeouts, SSE truncation, missing `/models`, and incompatible Messages APIs

### Later — v0.2.x and beyond

- Renderer polish for the new `ask`, `preview`, tweaks, and process-management surfaces
- Cost transparency — pre-generation estimate + weekly budget (per-generation token count already shipped)
- Version snapshots + side-by-side diff
- Three-style parallel exploration
- Codebase → design system (token extraction)
- Code-signing (Apple ID + Authenticode) + opt-in auto-update — v0.5
- Figma layer export — post-1.0

Have a different priority in mind? [Open an issue](https://github.com/OpenCoworkAI/open-codesign/issues/new/choose) or 👍 an existing one — we do read them.

---

## Star History



---

## Built on

- Electron + React 19 + Vite 6 + Tailwind v4
- `@mariozechner/pi-ai` and `pi-coding-agent` (model/provider and agent-loop primitives)
- `electron-builder`

## Reporting issues

Found a bug or have a feature request?

1. **Search** [existing issues](https://github.com/OpenCoworkAI/open-codesign/issues) first.
2. **Generate a diagnostics bundle** — Settings → Storage → Export diagnostics (API keys and prompts are redacted automatically).
3. **Open a new issue** using our [bug report](https://github.com/OpenCoworkAI/open-codesign/issues/new?template=bug_report.yml) or [feature request](https://github.com/OpenCoworkAI/open-codesign/issues/new?template=feature_request.yml) template.
4. For security vulnerabilities, see [SECURITY.md](./SECURITY.md).

## More from OpenCoworkAI 

If you like Open CoDesign, you may also want to check out our earlier project, [Open Cowork](https://github.com/OpenCoworkAI/open-cowork), an open-source AI agent desktop app for Windows and macOS with one-click install, multi-model support, sandbox isolation, and built-in skills.

## Community

Open CoDesign first launched on the [LINUX DO](https://linux.do/) community — thanks to everyone there for the early feedback and discussion.

- **[GitHub Discussions](https://github.com/OpenCoworkAI/open-codesign/discussions)** — share your designs in [Show & Tell](https://github.com/OpenCoworkAI/open-codesign/discussions/categories/show-and-tell), ask questions in [Q&A](https://github.com/OpenCoworkAI/open-codesign/discussions/categories/q-a), and propose features in [Ideas](https://github.com/OpenCoworkAI/open-codesign/discussions/categories/ideas).
- **[LINUX DO](https://linux.do/)** — Chinese-speaking discussion, use tips, and feedback (primary community).
- **GitHub Issues** — [bug reports and reproducible problems](https://github.com/OpenCoworkAI/open-codesign/issues).

### WeChat group

For Chinese-speaking users, we also keep a WeChat group for product updates, usage questions, and community discussion.



> ⚠️ The WeChat QR code rotates every 7 days and is currently valid until **May 16**.
> If the code has expired, please leave a message in [GitHub Issues](https://github.com/OpenCoworkAI/open-codesign/issues) and we will refresh the image in-repo.

See also the Chinese README: [README.zh-CN.md#社群](./README.zh-CN.md#%E7%A4%BE%E7%BE%A4).

## Contributing

Read [CONTRIBUTING.md](./CONTRIBUTING.md). Open an issue before writing code and run `pnpm lint && pnpm typecheck && pnpm test` before a PR.

## License

MIT — fork it, ship it, sell it. Third-party notices remain in [NOTICE](./NOTICE).

## Cite this project

If you reference Open CoDesign in a paper, article, or product comparison, please cite the repository as:

```bibtex
@misc{open_codesign_github,
  author       = {OpenCoworkAI Contributors},
  title        = {Open CoDesign: An Open-Source Desktop AI Design Tool},
  year         = {2026},
  howpublished = {\url{https://github.com/OpenCoworkAI/open-codesign}},
  note         = {GitHub repository}
}
````

Or the machine-readable `CITATION.cff` at the repo root.

---

## File: apps/desktop/resources/templates/README.md

# Open CoDesign Built-In Resources

This directory is copied into the user's app data as an editable templates tree.
Treat every file here as shippable product surface.

## Resource Types

- `skills/*.md` are markdown method skills loaded with `skill(name)`. They
  describe how to work: layout, accessibility, charts, forms, responsive
  behavior, craft checks, and `DESIGN.md` baton rules.
- `brand-refs/*/DESIGN.md` are reference-only brand design systems loaded with
  `skill("brand:<slug>")`. They are not project files. When a brand is adopted,
  translate the relevant choices into the workspace `DESIGN.md`.
- `scaffolds/**` are concrete starter/source assets copied with
  `scaffold(kind, destPath)`. They may be `.jsx`, `.html`, `.css`, `.md`, or
  another text format, but the extension must match the content.
- `design-skills/*.jsx` are copyable JSX component snippets. The host exposes
  them in the agent virtual filesystem as `skills/<file>.jsx`; despite that
  virtual path, they are source snippets, not markdown method skills.
- `frames/*.jsx` are copyable device/browser frame snippets exposed as
  `frames/<file>.jsx` in the virtual filesystem.

## Workspace DESIGN.md

Workspace `DESIGN.md` is the project-specific design-system baton. It is not a
built-in preset once copied or authored in a workspace. Generated multi-screen,
brand-driven, or reusable work should preserve, repair, and update it as the
source of visual truth.

## Maintenance Checklist

- Keep manifest metadata truthful: category, path, source, license, aliases.
- Keep source format and extension aligned.
- Avoid CDN scripts, external hotlinked assets, and non-MIT-compatible bundled
  code or assets.
- Avoid weak placeholder copy such as "Replace this", "Page content", or
  "Point one".
- Add focused tests when a resource affects loader behavior, manifest output,
  preview classification, or `DESIGN.md` validation.

---

## File: docs/research/11-custom-sliders.md

# Research 11 — Custom Sliders / EDITMODE Parameter Tweaks

**Date**: 2026-04-18 · **Status**: Decision recorded (corrected)

---

## ⚠️ Mechanism Correction (2026-04-18)

An earlier draft of this document (unpublished, written before research 15) incorrectly inferred that the Claude Design slider mechanism used a `<script type="application/json" id="design-params">` tag to embed tunable parameters.

**That inference was wrong.**

The actual mechanism, confirmed by analysis of the leaked Claude Design system prompt (see `docs/research/15-claude-design-prompts.md`, Section 6), uses:

1. **A `/*EDITMODE-BEGIN*/ ... /*EDITMODE-END*/` marker block** wrapping a JSON object literal inside a `<script>` tag — not a separate `<script type="application/json">` element.
2. **`window.postMessage({ type: '__edit_mode_set_keys', edits: {...} }, '*')`** for two-way communication between the parent renderer and the sandbox iframe.

The corrected implementation is described in full below.

---

## Decision summary

| Mechanism | Chosen approach |
|---|---|
| Parameter storage in artifact | `/*EDITMODE-BEGIN*/{...}/*EDITMODE-END*/` block inside `<script>` |
| Parent → iframe update | `postMessage({ type: '__edit_mode_set_keys', edits })` |
| Iframe applies change | `root.style.setProperty('--' + key, value)` |
| Persistence (save) | Parent reads live `getPropertyValue()` values, merges back into EDITMODE block |
| UI controls | Range / color / select inputs bound to EDITMODE keys |

---

## EDITMODE block format

Every generated artifact that supports tweaking must embed an EDITMODE block in its inline `<script>`:

```html
<script>
/*EDITMODE-BEGIN*/
{
  "color-bg":      "#f8f5f0",
  "color-accent":  "oklch(62% 0.22 265)",
  "color-text":    "oklch(12% 0.01 265)",
  "radius-base":   "0.5rem",
  "font-sans":     "'Syne', system-ui, sans-serif",
  "space-unit":    "1rem"
}
/*EDITMODE-END*/

(function () {
  // Apply initial values from EDITMODE block on load
  const block = document.currentScript.textContent.match(
    /\/\*EDITMODE-BEGIN\*\/([\s\S]*?)\/\*EDITMODE-END\*\//
  );
  if (block) {
    const params = JSON.parse(block[1]);
    const root = document.documentElement;
    for (const [key, value] of Object.entries(params)) {
      root.style.setProperty('--' + key, String(value));
    }
  }

  // Listen for runtime updates from parent renderer
  window.addEventListener('message', (e) => {
    if (!e.data || e.data.type !== '__edit_mode_set_keys') return;
    const root = document.documentElement;
    for (const [key, value] of Object.entries(e.data.edits)) {
      root.style.setProperty('--' + key, String(value));
    }
  });
})();
</script>
```

Rules:
- The JSON block must be valid: no trailing commas, no comments inside the braces.
- Keys match `:root` CSS custom property names WITHOUT the `--` prefix.
- Values are CSS value strings (colors, lengths, font stacks).
- The block must appear before any code that reads the CSS variables.
- Every key in the EDITMODE block must have a corresponding `--key` on `:root`.

---

## postMessage protocol

### Parent → iframe (apply change)

```ts
// In packages/runtime or apps/desktop renderer
function applyParamChange(
  iframe: HTMLIFrameElement,
  key: string,
  value: string,
): void {
  iframe.contentWindow?.postMessage(
    { type: '__edit_mode_set_keys', edits: { [key]: value } },
    '*',
  );
}

// Batch update (e.g., when dragging a slider quickly)
function applyParamBatch(
  iframe: HTMLIFrameElement,
  edits: Record<string, string>,
): void {
  iframe.contentWindow?.postMessage({ type: '__edit_mode_set_keys', edits }, '*');
}
```

### Persistence on save

When the user saves a tweaked design, the parent:

1. Reads the current live value of each EDITMODE key from the iframe DOM:
   ```ts
   const liveValue = iframe.contentDocument?.documentElement
     .style.getPropertyValue('--' + key).trim();
   ```
2. Merges the live values back into the artifact's source string by replacing the EDITMODE block.
3. Persists the updated source to SQLite.

The LLM generates the initial EDITMODE block; the renderer owns persistence.

---

## open-codesign implementation plan

### Artifact schema

The existing `design_params` field in `@open-codesign/artifacts` needs updating:

```ts
// Before (wrong — matched the inferred <script type="application/json"> approach)
interface DesignParam {
  id: string;
  label: string;
  type: 'color' | 'range' | 'select' | 'toggle';
  cssVar: string;
  defaultValue: string;
  min?: number; max?: number; step?: number;
  unit?: string;
  options?: string[];
}

// After (aligned with EDITMODE protocol)
interface EditModeParam {
  key: string;          // CSS var name without '--'
  label: string;        // Human-readable label for the slider UI
  type: 'color' | 'range' | 'select' | 'toggle';
  defaultValue: string; // From the EDITMODE block
  min?: number; max?: number; step?: number;
  unit?: string;
  options?: string[];
}
```

The LLM generates the EDITMODE block; the frontend parses it to derive the `EditModeParam[]` array for the slider UI. No separate JSON output is needed.

### Slider UI (packages/runtime or apps/desktop)

When the preview renders an artifact with an EDITMODE block:

1. Parse the block at render time → derive `EditModeParam[]`.
2. Render slider controls for each param.
3. On slider input: call `applyParamBatch(iframe, { [param.key]: newValue })`.
4. On slider change (mouseup / pointerup): record undo state.
5. On save: read live values back, update artifact source, persist.

### System prompt responsibility

The system prompt (tweaks-protocol.v1.txt) instructs the LLM to:
- Emit the EDITMODE block in every design that has tunable values.
- Keep the block valid JSON (no trailing commas).
- Match keys exactly to `:root` property names.
- Include the message listener script immediately after the block.

---

## Traps to avoid

1. **Stale EDITMODE block on revision**: when applying a text revision, preserve the EDITMODE block values; don't reset them to defaults.
2. **Color format mismatch**: slider color pickers emit `#rrggbb`; the EDITMODE block may have `oklch(...)`. The renderer must normalize before writing back.
3. **Too many parameters**: cap at 8 EDITMODE keys in the system prompt. More than 8 overwhelms the UI and signals poor CSS variable hygiene.
4. **`*` origin in postMessage**: acceptable for same-device local sandbox; would need origin restriction for any hosted/cloud version.

---

## Reference

- EDITMODE protocol details: `docs/research/15-claude-design-prompts.md` Section 6
- Prompt section that governs LLM output: `packages/core/src/prompts/tweaks-protocol.v1.txt`
- Inline comment / element selection (separate mechanism): `docs/research/02-inline-comment-and-sliders.md`

---

## File: docs/research/15-claude-design-prompts.md

# Research 15 — Claude Design System Prompt Structure Analysis

**Date**: 2026-04-18 · **Status**: Reference (informs prompt v1 design, do not copy)

> **Legal note**: This document describes the *structure and design patterns* observed in the leaked Claude Design system prompt. It does not reproduce any original text verbatim. Our own prompt sections in `packages/core/src/prompts/` are independently authored.

## Overview

The leaked Claude Design system prompt is approximately 14,700 tokens across 10 logical sections. The following is a structural analysis of what each section does — not a transcription.

## Section 1 — Identity and scope

Establishes the AI's role as a design-focused assistant. Defines what artifact types it can produce (UI screens, landing pages, presentations, marketing materials). Sets the character: confident design authority, not a general-purpose assistant.

## Section 2 — Artifact output contract

Specifies the exact wrapping format for generated artifacts. Defines identifier, type, and title attributes. Constrains the number of artifacts per response (one). Defines what is permitted outside the artifact tag (short prose summary only).

## Section 3 — Technical stack and construction rules

Enumerates permitted external resources with exact CDN URLs and integrity hashes for specific library versions (React, etc.). Defines inline-only rule for everything else. Specifies CSS-variable-first approach for all tunable values.

## Section 4 — Design quality and aesthetic guidance

Covers typography choices, color space preferences (oklch), layout asymmetry, spacing scale, motion restraint. Includes a list of visual patterns to avoid ("slop" list). References the publicly documented Skills approach to frontend design quality.

## Section 5 — Workflow and reasoning

Describes the expected thought process before generating: understanding intent, exploring directions, self-checking output quality. Defines "done" criteria.

## Section 6 — EDITMODE protocol (tweaks)

This is the most technically distinctive section. Describes the two-way communication protocol between the sandbox iframe and the parent renderer for live parameter tweaks.

### 6a — Embedded parameter block

Tweakable parameters are embedded in the artifact source as a JS object literal surrounded by marker comments:

```
/*EDITMODE-BEGIN*/
{
  "key": "value",
  ...
}
/*EDITMODE-END*/
```

This block lives inside a `<script>` tag in the artifact. The keys correspond 1:1 to CSS custom property names (without the leading `--`). Values are CSS value strings.

### 6b — Message protocol

The parent renderer communicates parameter changes to the iframe via `window.postMessage`:

```js
// Parent → iframe: apply parameter changes
iframe.contentWindow.postMessage(
  {
    type: '__edit_mode_set_keys',
    edits: { 'color-accent': 'oklch(70% 0.25 30)', 'radius-base': '0.75rem' }
  },
  '*'
);
```

The iframe listens for this message type and applies changes via `document.documentElement.style.setProperty`.

### 6c — Persistence

On save, the parent reads the live `getPropertyValue()` values back, merges them into the EDITMODE block, and persists the updated source. The LLM does not need to handle persistence — only the initial embedding and read-back.

## Section 7 — Multi-variant output

In "explore" mode, the prompt guides the model to emit multiple artifact variants (typically 3) in a single response, each with a distinct visual direction. Each variant gets its own artifact tag with a distinct identifier.

## Section 8 — Revision behavior

Defines how the model should handle follow-up requests: minimal-change principle, preserve voice/palette/structure unless explicitly asked to change them, re-read the current artifact before editing.

## Section 9 — Safety and scope limitations

Standard IP protection, phishing prevention, and out-of-scope deflection. Brief (< 100 tokens).

## Section 10 — Skills injection format

Describes how capability "Skills" are serialized and injected into the prompt at runtime. Each skill is a named, versioned block of instructions that can be included or excluded depending on the generation context.

## Implications for open-codesign

Our prompt composer in `packages/core/src/prompts/index.ts` mirrors this 10-section architecture with independently authored text. The EDITMODE protocol described in Section 6 is implemented in `docs/research/11-custom-sliders.md` (corrected 2026-04-18) and `packages/runtime/`.

---

## File: docs/plans/2026-04-23-v0.2-agentic-design-loop-design.md

# v0.2 Agentic Design Loop — Design Doc

Date: 2026-04-23
Status: Draft, pending review
Target: v0.2.0 (multi-milestone)

## 0. Context

v0.1.x agent runs on `@mariozechner/pi-agent-core` with a virtual-filesystem tool (`str_replace_based_edit_tool`). Pipeline assumes single prompt → single artifact. 13 design skills are injected wholesale into the system prompt every call.

This is insufficient for the product we are becoming:

- Users increasingly want multi-page / multi-artifact projects (landing + pricing + email in one session)
- Agent cannot see user's existing files, design tokens, or previous work
- Revision flow requires re-describing the whole page
- Skill injection eats 20-40k tokens per call regardless of relevance

v0.2 upgrades the loop to a real agentic design system: read/edit a user-bound workspace, pull skills on demand, verify its own output visually, revise by pointing at regions.

## 1. Non-goals

- Not replicating Claude Code. We optimize for design-artifact iteration, not general software engineering.
- No bundled model runtime. BYOK still mandatory.
- No cloud sync of workspace content. Local-first remains a hard constraint.
- No auto-retry on LLM errors beyond what `pi-agent-core` already does. Error recovery is user-triggered ("Try to fix").

## 2. Architecture overview

```
Renderer (React)                             Main (Electron)
┌─────────────────────────────┐   IPC   ┌──────────────────────────────┐
│ Chat / Preview / Perm modals│ ──────► │ ToolHandler (IPC-fronted)    │
│ Point-and-prompt selector   │ ◄────── │   ├─ PermissionManager       │
│ Zustand: session + perms    │         │   ├─ PathGuard (workspace)   │
└─────────────────────────────┘         │   └─ Tools (see §4)          │
                                        │      ↓                        │
                                        │ pi-agent-core Agent loop      │
                                        │   ├─ Compaction               │
                                        │   ├─ AbortSignal              │
                                        │   └─ Stream → parser          │
                                        │                                │
                                        │ design-workspace.ts (Roy PR)  │
                                        │   ├─ bindWorkspace            │
                                        │   ├─ migrate                   │
                                        │   └─ write-through             │
                                        │                                │
                                        │ SQLite: projects, designs,     │
                                        │         files, permissions    │
                                        └──────────────────────────────┘
```

Three layers from bottom to top:

1. **Workspace layer** (Roy PR foundation + path guard): real disk, write-through, binding
2. **Harness layer** (new): permission, path sandbox, streaming parser, action runner, compaction, IPC
3. **Tool layer** (new + #177 + existing): fs + design-specific tools, progressive-disclosed skills

## 3. Mental model: Quick mode vs Project mode

Both coexist. User picks at session start; they share the tool surface but differ in persistence and loop shape.

| | Quick mode (v0.1 parity) | Project mode (new in v0.2) |
|---|---|---|
| Input | Single prompt | Long-running chat |
| Storage | Virtual fs, extracted as artifact | Real disk under bound workspace |
| Tools | `text_editor` (virtual) + image-gen (#177) + `done` | Full fs tools + image-gen + preview-capture + revision |
| Skills | Wholesale inject (current behavior) | Index-only inject, tool-pull bodies |
| Loop | 6-15 tool calls → done | Multi-turn, compacted, abort-able |
| Revision | Regenerate whole artifact | Scoped to clicked region |
| Exit | Emit artifact, close session | Session stays open, artifact evolves |

The guarantee: everything that works in v0.1 keeps working. Quick mode is the default for new users; Project mode is opt-in by binding a workspace.

## 4. Tool surface

Keep everything that exists. Add new tools in two batches (see phasing §7).

| Tool | Source | Mode | Permission default | Phase |
|---|---|---|---|---|
| `set_todos` | existing | both | allow | M0 |
| `str_replace_based_edit_tool` | existing | Quick | allow | M0 |
| `read_url` | existing | both | ask | M0 |
| `done` / `declare_tweak_schema` | existing | both | allow | M0 |
| `generate_image_asset` | PR #177 | both | ask (paid) | M0 |
| `read_file` | adapt `pi-coding-agent.createReadTool` | Project | allow | M1 |
| `list_files` | adapt `pi-coding-agent.createLsTool` | Project | allow | M1 |
| `grep` | adapt `pi-coding-agent.createGrepTool` | Project | allow | M1 |
| `find` | adapt `pi-coding-agent.createFindTool` | Project | allow | M1 |
| `edit_file` (str-replace) | adapt `pi-coding-agent.createEditTool` | Project | ask once, then allow | M2 |
| `write_file` | adapt `pi-coding-agent.createWriteTool` | Project | ask once, then allow | M2 |
| `read_skill(name)` | new | both | allow | M2 |
| `list_skills` | new (optional; index already in prompt) | both | allow | M2 |
| `preview_capture` | new — wraps `webContents.capturePage` | Project | allow | M3 |
| `check_token_compliance` | new — reads `.codesign/tokens.{css,json}` | Project | allow | M3 |
| `query_artifact(selector)` | new — operates on artifact HTML, not DOM | Project | allow | M3 |
| `replace_artifact_fragment(selector, html)` | new | Project | ask once, then allow | M3 |
| `search_icons` | fork `marcoripa96/i0` pattern, local SQLite | both | allow | M4 |
| `export_artifact(format)` | wrap `packages/exporters/` | Project | allow | M4 |

Explicitly NOT in v0.2: `bash` / shell execution. Too much blast radius; re-evaluate in v0.3.

## 5. Permission model

Copy opencode's `allow / deny / ask / always` rule engine. Roughly 200 lines of logic + an ordered `Ruleset` array evaluated with wildcard match (last matching rule wins).

Default ruleset for Project mode:

```ts
const DEFAULT_PROJECT_RULES: Ruleset = [
  { permission: '*', pattern: '*', action: 'ask' },
  { permission: 'read', pattern: '*', action: 'allow' },
  { permission: 'read', pattern: '*.env*', action: 'ask' },
  { permission: 'read', pattern: '.git/config', action: 'deny' },
  { permission: 'read', pattern: 'id_rsa*', action: 'deny' },
  { permission: 'external_directory', pattern: '*', action: 'ask' },
  { permission: 'image_generation', pattern: '*', action: 'ask' },
  { permission: 'edit', pattern: '*', action: 'ask' },
  { permission: 'write', pattern: '*', action: 'ask' },
];
```

UX: on the first `ask`, show a modal with `Once | Always | Deny`. `Always` appends an `allow` rule to `~/.config/open-codesign/permissions.toml`. A Permissions panel lets users review/revoke.

Reasoning for being strict by default: new users are unfamiliar; they should consent visibly to disk writes, paid API calls, and external-directory access.

## 6. Path sandbox

Builds on Roy's `normalizeWorkspacePath()`. Add a `PathGuard` wrapper that every tool goes through:

```ts
class PathGuard {
  constructor(private root: string) {}

  resolveWithin(rel: string): string {
    const joined = path.resolve(this.root, rel);
    const real = fs.realpathSync.native(joined);
    if (!real.startsWith(this.root + path.sep) && real !== this.root) {
      throw new PermissionError('external_directory', real);
    }
    return real;
  }
}
```

Also applied to Roy's existing `persistMutation` (see §10). Blocked patterns: `*.env*`, `.git/config`, `id_rsa*`, `*.pem` — matched against both source and symlink target. Matches opencode's pattern.

## 7. Phasing

Each milestone is independently shippable. Do not start milestone N+1 before N's acceptance criteria are met on main.

### M0 — v0.1.x close-out (blocker for v0.2 start)

Goal: ship current value to international users landing from the star wave.

- [ ] Roy PR #173 merged (remaining 1 Blocker + 2 Major fixed)
- [ ] Path guard PR (harden Roy's `persistMutation`, prevent `../` writes, filter `skills/`/`frames/` out of write-through)
- [ ] yangjunx21 PR #177 rebased, bot review passes, merged
- [ ] API config bug batch: #175 Gemini 400, #176 local db, #167 SSE truncation, #158, #134, #130
- [ ] Cut v0.1.x release, update CHANGELOG, Changeset

Exit criteria: fresh install works end-to-end; new user can bind a workspace and generate an HTML prototype with an AI image.

Branch policy: continue on `main`. No v0.2-dev branch yet.

### M1 — v0.2.0-alpha: Read-only agent (2 weeks)

Goal: agent can see the user's workspace without touching it yet.

- [ ] Create `v0.2-dev` long-lived branch off main
- [ ] New `projects` table + `design.project_id` FK (migration). A "project" groups designs and owns the workspace binding. Roy's per-design `workspacePath` migrates to `project.workspacePath`; per-design binding still works (single-design project).
- [ ] `PermissionManager` (§5) + `PathGuard` (§6) + IPC plumbing
- [ ] Adapt pi-coding-agent tools `read` / `ls` / `grep` / `find` as `read_file` / `list_files` / `grep` / `find`; inject `PathGuard` via `Operations` hook
- [ ] Agent system prompt: add "Explore phase" instruction (first turn reads workspace before writing)
- [ ] Quick mode remains the default; Project mode activated by binding a workspace
- [ ] Vitest coverage for path-guard escapes, ignore patterns, and permission-ask flow

Exit criteria: in Project mode with bound workspace, agent can list files, read an existing `index.html`, grep for a component name, and explain what it found — with zero write capability.

### M2 — v0.2.0-beta: Write-capable agent + skill-as-tool (2-3 weeks)

Goal: agent can edit workspace files and pull skills on demand.

- [ ] `edit_file` (str-replace) + `write_file`, wired through `PathGuard` + permission ask-once
- [ ] StreamingMessageParser on top of pi-agent-core stream (historical alternative only; not the current v0.2 mainline)
- [ ] **ActionRunner** promise chain for ordered tool execution with live UI progress
- [ ] **Snapshot-on-first-write** under `.codesign/history/`, following Bolt's pattern; expose a "Revert" button per turn
- [ ] **read_skill(name)** tool — reads from `packages/core/src/skills/builtin/` and from `{workspace}/.codesign/skills/`
- [ ] System prompt: switch from wholesale skill injection to **skill index only** (name + one-line description, ~2k tokens total for 13 skills); Quick mode retains wholesale injection
- [ ] `edit_file` preferred over `write_file` in prompt ("prefer targeted replace over full write")
- [ ] Compaction: wire up `pi-coding-agent`'s `compaction/` module; tune thresholds (20k trigger, 40k protect, last 2 turns verbatim)
- [ ] AbortSignal plumbed end-to-end; Cancel button in chat

Exit criteria: agent can open a project, read context, propose edits, write them to disk, and be safely interrupted/rolled-back. Skills are pulled on demand. Token cost per turn drops measurably (report before/after).

### M3 — v0.2.0: Visual verification + point-and-prompt revision (2 weeks)

Goal: close the generate→verify→revise loop.

- [ ] `preview_capture(viewportWidth?)` tool over Electron `webContents.capturePage()`. Returns base64 PNG for vision-capable models, plus accessibility-tree snapshot for non-vision models
- [ ] `check_token_compliance(artifactId)` reads `{workspace}/.codesign/tokens.{css,json}` (W3C DTCG or Tailwind config), returns list of literal colors/spacings that bypass tokens
- [ ] `query_artifact(cssSelector)` + `replace_artifact_fragment(selector, html)` — operates on the artifact HTML AST, not live DOM
- [ ] Renderer: click-to-select in preview iframe → compute stable CSS selector (prefer `data-testid`, then `id`, fall back to structural path) → inject as scope hint into next user prompt
- [ ] System prompt: when `scope` is present in user message, prefer `edit_file` + `replace_artifact_fragment` over regeneration
- [ ] Lightweight error-recovery UI: on tool failure, show "Try to fix" button that crafts a follow-up prompt with the error payload

Exit criteria: user generates a hero, clicks the CTA button in preview, types "make it bolder", agent modifies only the CTA (not the whole page) and re-verifies via preview capture.

### M4 — v0.2.x: Multi-artifact orchestration + assets (2+ weeks, post-GA)

Goal: one session produces a consistent suite (landing + pricing + email).

- [ ] `search_icons` — fork `marcoripa96/i0`, ship local SQLite icon index (MIT); lazy-download on first use to respect the no-bundled-runtime constraint
- [ ] `export_artifact(format)` tool wrapping `packages/exporters/` — agent can finalize deliverables
- [ ] Project-level shared-context pattern (monkilabs `project-consistency` skill): Phase 1 agent writes `project.tokens.json` + base `Layout.tsx`; Phase 2 agents import, cannot invent new tokens
- [ ] Multi-design history view in renderer; cross-design preview

Exit criteria: user says "build me a landing, pricing, and onboarding email", ends session with three consistent artifacts sharing tokens and voice, exports as ZIP.

## 8. Backwards compatibility

- Quick mode is fully preserved. Existing Vitest test `'injects every loaded skill body into the system prompt (progressive disclosure level 1)'` stays green for Quick mode.
- Per-design workspace binding (Roy's shape) continues to work. A design without a project is auto-wrapped in a "default" project at M1 migration time.
- `TextEditorFsCallbacks` interface is preserved; new fs tools go through a parallel `PathGuardedFs` interface. Both write through Roy's `persistMutation`.
- Schema migrations: every table change adds a new column or table with `schemaVersion` bumped, never drops. Roll-back only requires previous binary to work with new DB shape.

## 9. Streaming parser sketch (historical alternative, rejected for current v0.2 mainline)

Status update: the current direction is to stay on pi-agent-core function tools plus a host-side workspace delta bus. We keep this section only as a historical alternative that was considered before the current harness stabilized.

Adapt Bolt's `StreamingMessageParser` onto pi-agent-core streaming. Key idea: we feed the parser the **cumulative** stream text; it advances a position cursor and emits events on complete tags.

```ts
interface ParseState {
  position: number;
  insideArtifact: boolean;
  insideAction: boolean;
  currentArtifact?: { id: string; title: string };
  currentAction?: { id: string; type: 'file' | 'image'; filePath?: string; content: string };
}

function parse(state: ParseState, cumulativeText: string, callbacks: {
  onArtifactOpen(id: string, title: string): void;
  onActionOpen(action: { id: string; type: string }): void;
  onActionStream(id: string, contentSoFar: string): void;
  onActionClose(id: string): void;
  onArtifactClose(id: string): void;
}): ParseState { /* ~150 lines */ }
```

Our tag grammar is simpler than Bolt's — we don't need `shell` or `start`. Three action types only: `file` (write virtual or real fs), `image` (invoke `generate_image_asset`), and `note` (chat narration). System prompt will teach the model these tags.

Why it is not the chosen v0.2 mainline: it would fork the runtime protocol away from pi-agent-core's tool events, duplicate state handling, and make preview/update persistence harder to reason about under multi-design concurrency. The chosen architecture is function tools + compact tool-result persistence + per-design delta handling.

## 10. Revision UX mechanics

When user clicks in preview iframe:

1. Renderer receives click coordinates, runs `document.elementFromPoint`
2. Compute stable selector: `data-testid` → `id` → class chain (rejecting Tailwind utility chains as noise) → structural `nth-child` fallback
3. Extract element's outer HTML (to show in the chat input as a chip)
4. Next user message is sent with a `scope` metadata field: `{ selector, outerHtml, viewportWidth }`
5. System prompt instruction: "When `scope` is present, use `query_artifact` and `replace_artifact_fragment` with the given selector; do not regenerate the whole file."

## 11. Open questions

These are deliberately not answered in this doc; resolve before M3:

- Should `preview_capture` default to accessibility-tree (free) or screenshot (vision tokens) for vision-capable models? The cost/fidelity tradeoff needs an experiment.
- Revision UX: is `data-testid` a reasonable ask for generated code, or do we rely on structural selectors? Likely the former, but costs prompt tokens.
- Should `generate_image_asset` results be cached by prompt hash to prevent accidental double-billing on retries? Probably yes; tracks memory feedback on silent fallback concerns.
- For compaction, do we keep `pi-coding-agent`'s default `summary` prompt, or author a design-specific one ("Keep decisions about color, typography, and voice; drop file-level diffs")? Worth an A/B.
- Does Figma MCP plug in as an optional data source at M4, or wait for v0.3? Many users don't have Figma.

## 12. Risks

- **pi-agent-core loop hold-up**: our M2 introduces a custom streaming parser on top of pi-agent-core's tool-call stream. If pi-agent-core's internals change between minor versions, we break. Mitigation: pin minor version, maintain adapter layer isolated to one file.
- **Token cost blow-up**: multi-turn Project mode with a 50-file workspace can easily eat 100k tokens/turn if compaction misbehaves. Mitigation: telemetry-less (local only) token counters shown to user; hard cap with user-override.
- **Permission fatigue**: too many `ask` dialogs will annoy users. Mitigation: `Always` action persisted per-project; the first 5 operations of a session can carry a "trust for this session" bulk-approve.
- **Skill miss**: Tier-1 index might fail to trigger the right skill lookup (Anthropic docs explicitly warn about this). Mitigation: write precise one-line descriptions; include representative task examples in skill frontmatter; ship a test suite that asserts the model picks the correct skill on sample prompts.
- **Scope creep into coding-agent territory**: users will ask for `bash`, `git`, `npm`. We say no in v0.2. Mitigation: clear docs on what Project mode is and is not. The differentiation is "agent for design artifacts", not "VS Code replacement".

## 13. Success metrics

Measured locally (no telemetry). Report in the v0.2 release notes.

- Median tokens per turn drops ≥30% (skill progressive disclosure)
- Median revision task completes ≥2× faster (scope hint + targeted edit)
- Agent retrieves correct skill on ≥85% of sample prompts (offline test set)
- No P0 regressions in Quick mode per existing Vitest suites

## 14. References

Research reports archived under this plan's directory (append as needed):

- opencode architecture — tool registry, permission rule engine, compaction
- pi-coding-agent tool surface — ready-to-import fs tools
- Bolt.new streaming parser + ActionRunner + snapshot history
- Agent Skills progressive disclosure (Anthropic, Cursor data)
- Design-specific tool landscape (Playwright MCP, uselayout, marcoripa96/i0, Caliper, Figma MCP)

Key sources:
- https://www.anthropic.com/engineering/equipping-agents-for-the-real-world-with-agent-skills
- https://www.cursor.sh/blog/dynamic-context-discovery
- https://github.com/sst/opencode/tree/HEAD/packages/opencode/src/tool
- https://github.com/badlogic/pi-mono/tree/main/packages/coding-agent/src/core/tools
- https://github.com/stackblitz-labs/bolt.diy/blob/main/app/lib/runtime/message-parser.ts

---

## File: docs/plans/2026-05-05-agent-run-protocol.md

# Agent run protocol hardening

Status: implementation started on 2026-05-05.

## User intent

The agent loop should feel like a visible design collaborator, not a silent one-shot generator.
For open-ended design creation, the desired rhythm is:

1. Ask the user a small number of high-impact questions when the brief leaves material choices open.
2. Present a concrete plan with `set_todos` before the main build work.
3. Interleave short assistant text with tool calls so the user sees phase changes: inspect, write, preview, repair, finish.
4. Use `set_title` proactively so new designs do not remain as `Untitled design N`.

This is a product behavior contract, not just prompt flavor. The runtime and prompt should make the happy path easy for the model and observable in logs.

## Current evidence

Recent desktop logs for generation `moshk0qh-lqddh6` showed:

- `generate-title` succeeded in the renderer/main side path.
- The agent tool list included `set_title`, `set_todos`, `ask`, file edit, preview, and done.
- The actual agent sequence skipped `set_title`, then called `view frames/watch.jsx`, `set_todos`, `create App.jsx`, `preview`, and `done`.
- The session row and `design-store.json` still showed `Untitled design 1`.

So the gap is not tool availability. The gap is protocol strength:

- The agent did not know that the current design title was still an auto-generated placeholder.
- Existing source/scaffold guidance made the run look like continuation work, which weakened the `set_title` requirement.
- UI auto-title was asynchronous and could leave the design visibly untitled while the agent worked.
- `ask()` was available, but only prompt-encouraged; only the separate run-preferences router asked deterministic preference questions.

## Protocol decisions

### Naming

When the current design title is `Untitled design` or `Untitled design N`, the agent must call `set_title` once as the first tool call. This applies even if a scaffold, frame, or starter source already exists in the workspace.

The renderer should also apply a local fallback title immediately from the first prompt, then optionally replace it with the model-generated title. The visible app state should not wait on a network title request before leaving `Untitled`.

### Questions

Use `ask()` for high-impact ambiguity: visual direction, artifact type, audience, content source, reusable-system vs one-off, or expensive optional controls/assets.

Do not ask about details that can be inferred safely or revised cheaply. For narrow, fully specified briefs, proceed without a question.

### Planning

For any multi-step design creation, call `set_todos` early after title/clarification. The checklist should be concrete enough to explain the build sequence, not a generic "implement / polish / finish" list.

### Visible interleaving

The system prompt should continue requiring a short assistant sentence before major phase shifts. The testable signal is event order in session JSONL: assistant text or tool groups should make the loop legible without dumping source code into chat.

Host-generated phase notes remain allowed, but only as a restrained fallback:

- emit one note only when the current turn has not produced model text yet;
- use them for high-signal transitions such as `ask`, `set_todos`, first write, `preview`, and `done`;
- do not rely on them for state; they are visibility aids, not memory.

### Stream isolation

`fs_updated` handling must be keyed by `designId + generationId + path`, not by one global pending slot. A background run may update its own preview pool entry, but it must never overwrite another design's visible preview during the throttle window.

`agent_end` should flush only the ending generation's pending preview updates before snapshot persistence.

### Tool-result persistence

Session JSONL remains the source of truth for chat/tool rows, but persisted tool results must stay compact:

- keep visible text at or under the chat budget;
- strip or summarize large `details` payloads, especially `preview` screenshots and verbose `done` results;
- preserve structured fields needed for replay: tool name, command, path, status, duration, counts, and a short error preview.

### Unified scoped edits

Inline comment / point edits should use the same main generate path as ordinary follow-up prompts. Scope metadata (selector, tag, outerHTML, parent context when available) belongs in the user prompt/context pack, not in a separate weak-history revise pipeline.

## Next hardening targets

- Add a deterministic preflight policy for `ask()` when the router marks high-impact ambiguity, instead of relying only on model discretion.
- Add log/session tests that assert `set_title` appears before file edits for auto-named designs.
- Add evaluation fixtures covering concurrent design runs, compact tool-result persistence, and scoped point edits on top of existing source.

---

## File: docs/v0.2-plan.md

# v0.2 Agent Loop & Harness Plan

> 这份文档是 v0.2 的实施参考，由 2026-04-23~24 多轮讨论整理。
> 已基于 pi-coding-agent spike 结果（2026-04-24, `docs/spike-pi-results.md`）更新。
> Spike 结论：✅ pi-coding-agent 满足全部 v0.2 硬需求，session / bash / capability / provider 全交给 pi。

## 0. 总原则

**默认抄 coding agent 约定，只在 design-specific 场景做针对性扩展**。

具体来说：
- pi-coding-agent / Claude Code / Cursor 有共识的做法 → 直接抄
- 三家不一致 → 挑最简单的
- 三家都没有，我们真有独特需求 → 才讨论发明

YAGNI 原则：早期 v0.x 可随意 breaking change，v1.0 才承诺向前兼容。

---

## 1. 非目标（v0.2 明确不做）

- Video / 3D / logo system / 矢量编辑（不是 design agent 本质）
- Bundle model runtime（Ollama / llama.cpp / 浏览器等）
- Cloud sync / telemetry / 用户账户
- 多人协作
- MCP 支持
- 社区 skill / scaffold 安装（`pi install` 式）
- Session branching UI（引擎层 pi 支持，UI 不暴露）
- 消息队列 / steering（用户打字时 agent 跑）
- Undo / 版本回退（用户可停止，但不能回退 agent 步骤）
- Verifier subagent（有 preview 自检就够）
- Working memory agent-written（用户写 AGENTS.md / DESIGN.md）
- Snip 工具（coding agent 没有，靠 pi auto-compact）
- Per-design meta.json（session header 够）
- Sealed / Open mode split（统一 workspace model）
- 权限 mode toggle（单一模式 + 四层 Tier）

---

## 2. 核心架构

### 2.1 存储模型：去 SQL，走 JSONL + filesystem

```
~/Library/Application Support/open-codesign/
  config.toml              # BYOK 配置（provider / API key）
  sessions/
    <session-uuid>.jsonl   # 每个 session（= design）一个 JSONL
  thumbnails/              # 缩略图 cache
  settings.json            # 全局 allowedTools + 偏好
  allowed-commands.json    # 全局 bash allowlist（也可以合进 settings.json）

/          # 用户的真 workspace（由 Settings 默认根配置）
  (用户文件)
  AGENTS.md                # 用户写的项目指令（可选）
  DESIGN.md                # 用户写的品牌 token（可选，Google spec）
  .codesign/
    settings.json          # per-design allowlist + 偏好
    settings.local.json    # 个人偏好（默认 gitignore）
```

**砍掉的 SQLite 内容**：

- `designs` 表 → session JSONL header 的 `cwd` + `name` 字段
- `design_files` 表 → workspace 磁盘（真源）
- `snapshots` / `snapshot_files` → 不做版本引擎（v0.3+）
- `chat_messages` → session JSONL message entries
- `comments` → session JSONL 里带 anchor 的 user message
- `diagnostic_events` → 可选 append-only log 文件

### 2.2 Design == Session

没有"project"概念。Design 就是 pi session，一个 JSONL 文件。

- session header 格式 100% 用 pi v2 原生，**不加字段**（包括不加 designId）
- `cwd` 字段 = workspace 路径
- `name` 字段 = 用户给的 design 名（pi 的 `/name` 命令）
- 多个 session 可共 cwd（= "对同一 codebase 的多个对话"）
- Sidebar 扁平展示 session，按 `lastOpenedAt` 排
- Fork = 新 session（pi 的 `/fork`，我们引擎层支持但 UI 暂不暴露）

### 2.3 Workspace 统一模型

- 每个 design **必有** workspace（无 sealed mode）
- Settings 里一个配置：**默认 workspace 根目录**（默认 `~/Documents/CoDesign/`）
- New Design 时默认路径 `<默认根>/<design名>/`，用户可自定义
- PR #173 的 Skip 按钮去掉

---

## 3. 工具清单（15 个，spike 后修订）

**总计 15 个工具暴露给 agent**：pi-coding-agent 自带 7 个 built-in（执行层我们不写，只 hook 拦截）+ 我们写 8 个（设计 domain 6 + 生命周期 2）。

### Pi 自带 7（spike 验证白送）

| 名称 | 我们做啥 |
|---|---|
| `read` | 直接用，pi 自带类似 view_budget 机制 |
| `write` | 直接用 |
| `edit` | str_replace 风格 |
| `bash` | 直接用，**通过 `tool_call` hook 拦截做权限**，不写新 bash 工具 |
| `grep` | 白送 |
| `find` | 白送 |
| `ls` | 白送 |

**Bash 权限拦截（spike 验证的实现）**：

```ts
pi.on("tool_call", async (event) => {
  if (isToolCallEventType("bash", event)) {
    const allowed = await askUserPermission(event.input.command);
    if (!allowed) return { block: true, reason: "user denied" };
  }
});
```

异步、可 await Electron IPC 弹窗。同 hook 也覆盖 read/edit/write/grep/find/ls，按需扩权限粒度。`event.input` 可 mutate，未来 SSH 远程执行不用换工具。

### Design domain 6（我们写）

| 名称 | 行为 |
|---|---|
| `scaffold(kind, path)` | 把预装 starter JSX / CSS 片段复制到 workspace（enum kind） |
| `skill(name)` | 懒加载 skill prompt 文本（manifest 在 system prompt 里列名字） |
| `ask(questions)` | 渲染结构化问卷；end turn 等用户答（5 种题型：text-options / svg-options / slider / file / freeform） |
| `preview(path)` | 渲染 artifact source（默认 `App.jsx`）→ `{screenshot?, consoleErrors, assetErrors, domOutline, metrics}`；vision model 才返 screenshot |
| `gen_image(prompt, path)` | 文生图，落盘；**capability-based 暴露**（仅 OpenAI key 配了才给 agent） |
| `tweaks(blocks)` | 声明 EDITMODE 块 + 生成 UI 控件；**跨文件**支持；全量覆盖语义 |

### Lifecycle 2

| 名称 | 行为 |
|---|---|
| `todos(items)` | 任务列表；system prompt 强制 >3 tool call 任务首调；runtime 5-call 后软提醒；UI 钉顶展示 |
| `done(path)` | 终止本轮；默认检查 `App.jsx`；有错返给 agent 修，干净则 turn 结束 |

### 已砍

- `verify` subagent（preview 自检够）
- `snip`（pi auto-compact）
- ~~独立 `list_files`、自写 bash~~（pi 自带，spike 后改主意）
- `read_design_system`（DESIGN.md 直接注入 system prompt）
- `read_url`（reference URL 由 host 预取、限流/限大小后作为 untrusted context 注入；不作为 agent 默认工具暴露）

### Capability-based 暴露规则

Session 启动时探测 `capabilities`（直接读 `Model<T>.input` / `.reasoning` / `.cost.cacheRead`，spike 验证字段齐全）：
- `gen_image` 只在 imageGen provider 配了时暴露
- `preview` 对 vision model 返截图（`Model.input.includes("image")`），对纯文本 model 返 DOM outline + metrics
- `read` 图像模式仅 vision model

---

## 4. Loop 结构

**Agentic，无硬相位**。

当前主线不是 tag-parser / custom streaming grammar，而是 pi function-tool loop + workspace delta stream。推荐把 harness 理解成四层：

- **Run Controller**：绑定 `designId` + `generationId`，执行 preflight ask、title/todos 约束、timeout/cancel、host phase notes。
- **Workspace Delta Bus**：把 `fs_updated`、preview pool、snapshot persist 作为按 design/generation/path 隔离的增量事件处理。
- **Context Pack / Session Memory**：brief、run preferences、workspace state、memory sections 进入 prompt；tool/artifact/error rows 不进入 LLM history。
- **Verification Gate**：`preview(path)` 提供中途检查，`done(path)` 负责最终 gate 和 repair loop。

```
SESSION_START
  ↓
  system prompt 组装（见 §5）
  ↓
TURN_START (user message + 可选 content blocks)
  ↓
AGENT_LOOP (pi-agent-core 原生)
  ├─ agent 思考 / 说话 / 调 tool（可并行）
  ├─ 工具 result 回流
  └─ 终止任一满足：
     · 调 done
     · 调 ask（等答）
     · 60 次 tool call 上限（软询问继续）
     · 10 分钟 wall clock
     · 用户 abort
  ↓
TURN_END
  ↓
  if done 被调：
    runtime 跑 preview(path)
    errors → 喂回 agent → 回 AGENT_LOOP
    clean → turn 结束，UI 显示成果
```

**软约束（写进 system prompt，不是 loop 强制）**：
- 新 / 模糊任务优先调 `ask`（10+ 问）
- 写代码前在 chat 里 declare aesthetic（palette / type / rhythm）
- 复杂任务（>3 step）首调 `todos` 规划
- 完成用 `done`，它自动 preview + 你看 console / 404 后修
- 暴露 2-5 个 tweaks（"big-rock" values，不是细枝末节）

### Multi-screen 视觉一致性（baton pattern）

借鉴 [Google Stitch](https://stitch.withgoogle.com/) 的 baton pattern——多屏 / 多 page 项目（landing + dashboard + settings 等）保证视觉一致：

```
生成屏 1
  ↓
从产物抽 token（colors / typography / spacing / radius）
  ↓
更新 DESIGN.md（agent 调 edit）
  ↓
注入下次生成 system prompt 的 [3] 层
  ↓
生成屏 2 自动用同 token system
  ↓
... 第 N 屏
```

不是新工具，是 prompt loop 设计：每生成一屏，agent 自检"DESIGN.md 是否需要更新"，更新了下一屏自然继承。配合 §5 Brand Acquisition Protocol 形成完整 token 一致性闭环。

### 中断语义（对齐 Claude Code）

```
用户 Esc / Stop：
├─ LLM streaming → AbortSignal
├─ 当前 tool call → 级联 abort
│  └─ bash：SIGTERM → 3s → SIGKILL
├─ queued user messages → 回 editor 供重编辑
└─ 后台进程（dev server）不杀，走单独 "Processes" 面板管
```

**二次 Esc（2s 内）**：弹撤销菜单（恢复到 turn 前 / 删除本 turn / 什么都不做）。

**半成品文件**：write/edit 用 atomic temp + rename，**不回滚**，中断只影响未完成的写。

### 后台进程（tab 模型）

```
design tab 打开 → background process 活
design tab 关闭 → SIGTERM 进程（关前弹确认）
切换 design tab → 什么都不做，进程继续
app 退出 → TERM → KILL 所有
```

- 每 design ≤3 进程，全局 ≤10
- Port 检测：起进程后 2s 扫 stdout 匹配 vite/next/astro/webpack 端口模式
- Processes 面板（design sidebar 固定）列活进程 + 一键 stop + 看 logs

---

## 5. System Prompt 层叠

```
[1] 主 system prompt                  产品级（抄 Claude Design 骨架）
    ├─ Identity（"expert designer, user as manager, filesystem-based project"）
    ├─ Workflow（软指引 7 步）
    ├─ Output 规则（filename / revisions / 避坑）
    ├─ React + Babel pinned（SRI 整段抄 Claude Design）
    ├─ Content Guidelines（反 AI slop 核心）
    ├─ Aesthetic direction（无品牌时如何承诺）
    ├─ Typography 默认（Bunny Fonts / Fontshare）
    ├─ Tools 一览（12 个每个一行）
    ├─ Tweaks EDITMODE 协议
    ├─ Ask 规则（10+ 问 + 5 种题型）
    ├─ Preview / done 协议
    └─ Do not divulge

[2] project_info                      workspace stack 探测结果（~200 字节）

[3]                  用户项目级
      ...
      <design_system source="DESIGN.md">
         YAML front matter 保留原样（token 不 truncate）
         Prose 部分 truncate 到 2000 字
      </design_system>

[4] Available scaffolds (enum)         从 scaffold tool schema 的 kind 自动生成

[5] Available skills (manifest)        技法 + brand refs 两段
    ## Techniques
    - oklch_color_system: ...
    - bento_grid: ...
    ## Brand references (skill("brand:<name>"))
    linear, vercel, stripe, figma, arc, ...

[6] [对话历史]                        pi auto-compact 兜底

[7] 本轮 user message
```

**总字符目标**：base 9-10K 字符（~2.7K tokens），比 Claude Design 的 30K 小三分之二。

**DESIGN.md 生命周期**：协作式，agent 和用户都可编辑。
- Session 启动读，session prompt 包含
- Agent 第一次声明 aesthetic → 主动 `write("DESIGN.md", ...)` 生成初版
- 用户外部编辑 → FSWatcher 捕捉 → 下轮重读
- 用户持续调整某 EDITMODE 值 → agent 主动 propose "promote to DESIGN.md"

**Google DESIGN.md spec 完全采纳**（YAML front matter + markdown body，基于 W3C DTCG），不发明自己 schema。

### Brand Acquisition Protocol

灵感来自 [alchaincyf/huashu-design](https://github.com/alchaincyf/huashu-design)（A/B 测结果显示降低输出方差 5×）。写进 system prompt：

```
## Brand acquisition (never invent brand values from memory)

When user mentions a specific brand and DESIGN.md doesn't yet exist:

1. Ask the user for brand guidelines / DESIGN.md / brand site URL
2. If they give a URL: bash `curl` the /brand or /press route
3. Download SVG / HTML / screenshots as fallback (via bash + workspace storage)
4. Extract hex values programmatically from CSS / SVG, NOT from memory
5. Codify into DESIGN.md with YAML token block

NEVER write brand color hex values from memory. Always extract from
authoritative source. If the source is unavailable, ask the user.
```

理由：LLM 对 brand color 的 "记忆" 错误率高（即使 Linear / Stripe 这种知名品牌也有偏差），凭记忆生成的产物会"形似而神离"。强制走 acquisition protocol 把这个错误源头 close 掉。

---

## 6. 权限模型（4-Tier，抄 Claude Code）

### 分层

```
Tier 0  无感通过（不弹窗）
Tier 1  首次弹窗 + 用户选 allowlist
Tier 2  每次必弹窗（不能 suppress）
Tier 3  硬拦截（UI 拒绝，无 override）
```

### 具体归类

| 操作 | Tier |
|---|---|
| 读 workspace 内文件 | 0 |
| 写 / 改 / 删 workspace 内文件 | 0 |
| `ls` / `pwd` / `cat` / `grep` / `find` / `stat`（cwd 内） | 0 |
| 只读 git (`git status/log/diff`) | 0 |
| `pnpm install *` / `pnpm run *` / write-git | 1 |
| `curl` / `wget` 非本机 URL | 1 |
| cwd 外的任何命令 | 1 |
| `git push` / `npm publish` / `sudo` | 2 |
| `rm -rf /` / `rm -rf ~` / `curl \| sh` / 系统目录写 | **3** |

### 弹窗 UX（三按钮）

```
┌─────────────────────────────┐
│ 🟡 Agent 想运行              │
│                              │
│    pnpm install              │
│                              │
│   [拒绝]  [允许]  [总是允许]  │
└─────────────────────────────┘
```

- 默认 scope = per-design + 命令前缀（`pnpm install *`）
- 想更宽 / 更窄去 Settings 编辑 allowlist

### Allowlist 存储

`<workspace>/.codesign/settings.json`（per-design，可 commit）：
```json
{
  "schemaVersion": 1,
  "allowedTools": [
    "Bash(pnpm install *)",
    "Bash(pnpm run *)",
    "Bash(git status)"
  ]
}
```

全局：`~/.codesign/settings.json`（同格式）。加载顺序：global → project → local（settings.local.json，gitignore 默认）。

---

## 7. Progressive Disclosure

三层独立机制：

### 源头 budget（预防膨胀）

- `read`: view_budget（首次全文，重复摘要 + 强制 view_range，mtime 变化重置）
- `bash`: stdout tail-cap 10KB + exit code
- `preview`: screenshot 压缩 + console ≤50 条 + 404 ≤20 条
- `grep`: head_limit 250

### 按需披露

- **Skill manifest** 在 system prompt 列名字（~500 字节）
- `skill(name)` 调用时返全文（~500-2000 字节/次）
- **Scaffold enum** 在 tool schema（~200 字节）
- `scaffold(kind, path)` 执行时写磁盘 + 返短路径确认
- 一个 session 内重复 `skill(name)` → 返短"already loaded"，不重复灌

### Tool result 不做类型特定剪枝

（coding agent 都不做，我们也不）pi auto-compact 兜底。

### Tweak / Inline-edit / Comment delta

直接操纵的 delta 攒 buffer，下次 user chat 时附带到 content block：
- `<tweak_changes>`
- `<direct_edits>`（inline text edit）
- 评论立即发，不攒

---

## 8. UI 集成

### 已有的（PR #173 / v0.1 带来）

- `HubView` → Hub 页面
- `DesignSwitcher` / `DesignsView` → session list
- `ModelSwitcher` → 模型切换（mid-session 可用）
- `FilesPanel` / `FilesTabView` / `CanvasTabBar` → 右 pane
- `PreviewPane` / `PhoneFrame` → 预览
- `InlineCommentComposer` → 评论带 anchor
- `Settings/` + `AddCustomProviderModal` → BYOK 配置
- `RenameDesignDialog` / `DeleteDesignDialog` → CRUD
- Runtime `tweaks-bridge.ts` → EDITMODE postMessage 基础

### 要新增的

| UI 组件 | 用途 | 工作量 |
|---|---|---|
| `AskModal` | `ask` 工具弹的结构化问卷 | M |
| `PermissionDialog` | bash 三按钮弹窗 | S |
| `TweakDeltaChip` | Chat input 里的 tweak 变更附件 chip | S |
| `TweaksPanel` | artifact 里的 slider / color picker 面板 | M |
| `ProcessesPanel` | design sidebar 的后台进程列表 | M |
| `MigrationDialog` | v0.1 → v0.2 迁移弹窗 | S |
| `ScaffoldPicker`（optional） | `scaffold()` 调用时的可视化挑选 | M |

### 事件流到 React

**两条独立通道**：

```
pi event stream (tool calls / messages / thinking)
  ↓ IPC
  Chat pane + activity feed

Workspace FSWatcher (chokidar)
  ↓ IPC
  Files tab + preview tab（热刷新）
```

Files tab **不**跟 tool call 事件关联——只看磁盘真实状态。外部编辑（VSCode）自然生效。

---

## 9. Gap Analysis（已有 vs 要做）

### 工具层

| 现有 / 来源 | 对应 v0.2 | 状态 |
|---|---|---|
| pi-coding-agent 自带 read/write/edit/bash/grep/find/ls | 7 个 built-in | ✅ 直接用，**只写 `tool_call` hook 加权限** |
| 现有 set-todos | todos | ✅ 保留 |
| 现有 done | done | ✅ 保留（含 runtime verifier hook） |
| 现有 declare-tweak-schema | tweaks | ✅ + 改跨文件 |
| 现有 generate-image-asset | gen_image | ✅ + capability gate |
| 现有 read-url | - | ❌ 砍（Reference URL 走 host 预取 + untrusted context） |
| 现有 text-editor | - | ⚠️ 当前保留为 `str_replace_based_edit_tool`；pi 自带 read/write/edit 后可砍 |
| 现有 list-files | - | ❌ 砍（pi 自带 ls / edit tool directory view 覆盖） |
| 现有 read-design-system | - | ❌ 砍（DESIGN.md 直接注入） |

### 要新建的工具（**3 个**，spike 后大幅精简）

1. `ask` + 结构化问卷 + AskModal UI
2. `scaffold` 工具 + 预装目录 `packages/core/src/scaffolds/`
3. `skill` (invoke_skill) + manifest 生成 + 懒加载 + 去重
4. `preview` 从 `done` 里拆出独立工具（半个新 + 半个改造）
5. ~~`bash`~~ → spike 后改为只写 hook（不算独立工具）

### 存储层（spike 后大幅简化）

| 之前计划 | spike 后 |
|---|---|
| ~~SQLite → JSONL 自写 writer / parser~~ | ✅ 直接用 pi 的 `SessionManager`（spike 验证 sessionDir 完全可指定） |
| ~~`model-caps.ts` capability 表~~ | ✅ 直接读 `Model<T>.input/reasoning/cost`（spike 验证字段齐全） |
| ~~providers thin wrapper~~ | ✅ 直接用 `pi.registerProvider()`（spike 验证 baseUrl override 可用） |
| **v0.1 → v0.2 迁移脚本** | ✅ 仍要写：扫旧 SQLite → 转 JSONL via SessionManager.appendXXX |
| **config.toml → pi.registerProvider 翻译层** | ✅ 仍要写：BYOK 配置注入 |

### 集成层

1. ✅ Pi-coding-agent 集成 spike — **已完成**（见 `docs/spike-pi-results.md`）
2. System prompt 主体内容写满
3. Progressive disclosure：read view_budget pi 已有，bash tail-cap 在 hook 里加，preview 压缩自写

### 仍要写的代码（v0.2 实际工作量）

- ✅ Electron IPC 桥（wrap `createAgentSession()`，单 session 一个 BrowserWindow）
- ✅ Permission Dialog UI（被 `tool_call` async hook 调）
- ✅ config.toml → `pi.registerProvider()` 翻译 shim
- ✅ Sandbox 渲染器（packages/runtime，已有，扩展）
- ✅ Artifact / exporter（packages/artifacts, packages/exporters，已有）
- ✅ FSWatcher → Files tab（独立通道）
- ✅ 4 个工具：scaffold / skill / ask / preview
- ✅ tweaks 改跨文件
- ✅ v0.1 → v0.2 迁移脚本

---

## 10. Pi-coding-agent 集成（已完成 spike）

✅ **已通过**——见 `docs/spike-pi-results.md`（2026-04-24）。

### Spike 结论摘要

| 验证 | 结果 | 关键 API |
|---|---|---|
| A. bash 拦截 hook | ✅ Pass | `pi.on("tool_call", async (event) => { return { block, reason } })` |
| B. Session storage | ✅ Pass | `SessionManager.create(cwd, sessionDir)` 完全扁平，文件名 `_.jsonl` |
| C. Model capability | ⚠️ Partial（实际 Pass） | `Model<T>` 有 `reasoning / input / cost / contextWindow / maxTokens` |

### v0.2 架构落地（基于 spike 结论）

- **Session**：`SessionManager.create(cwd, "/sessions")`，扁平存储
- **Bash 权限**：`tool_call` hook + 我们 Permission UI（不写新 bash 工具）
- **Capability**：`Model<T>` 直读，无 fallback 表
- **Provider**：`pi.registerProvider()` 从 config.toml 翻译注入
- **AuthStorage**：`AuthStorage.create(authPath)` 指向我们的 userData，配合 config.toml 双轨

### Spike 中发现的几个坑（写进实施 checklist）

- session 文件名是 `_.jsonl`，不是纯 uuid
- `Model.provider` 运行时是 string，不是 object（类型说谎）
- `ModelRegistry.getAll()` 不是 `getAllModels()`
- pi-ai 要 pin `^0.69.0`，不要让 pnpm 默认装 0.67.x
- 自定义 gateway 用 `pi.registerProvider("anthropic", { baseUrl })`，不靠 env

### Bonus 发现（v0.3+ 可白嫖）

- `SessionManager.forkFrom()` — 程序化 fork session
- `session.navigateTree(targetId)` — 内置版本/分支 UX
- 19+ 事件（before_provider_request / after_provider_response / compaction_start_end / auto_retry_*）
- OAuth provider 支持（未来 Claude Code OAuth 续接零代码）
- `--mode rpc` 子进程 escape hatch

---

## 11. v0.1 → v0.2 迁移

### 策略

v0.2 首次启动：

1. 检测 `app.getPath('userData')/designs.db` 存在 → 弹框"检测到 X 个 v0.1 designs，迁移吗？"
2. 一键迁移：
   - SQLite 读 `designs` / `design_files` / `chat_messages` / `comments`
   - 每 design 在 `~/Documents/CoDesign/<slug>/` 创 workspace
   - 转 chat_messages → session JSONL
   - 转 design_files → workspace 磁盘文件
   - 转 comments → JSONL 里 content block
3. 跳过：旧 SQLite 备份为 `designs.db.v0.1.backup`，不读
4. 迁移完 + backup 保留，允许用户手动清

### 保留不碰

- `config.toml`（API key）继续读，只新增 `defaultWorkspaceRoot` 字段
- 用户 workspace 里的 web artifact source（劳动成果）不动

---

## 12. 资源清单

### 12.1 Scaffolds（预装 starter templates）

**目标 ~30 个精品**。Bundle 预算 ~150-200KB 总内嵌代码（gzip 后 40-50KB）。

#### P0 — v0.2 必装（9 个，核心视觉独特）

| kind | 来源 | License | 工程量 | 独特度 |
|---|---|---|---|---|
| `neubrutalism-kit` | [OshekharO/Neubrutalism](https://github.com/OshekharO/Neubrutalism) 40+ 组件 70KB CSS，CDN 可引 | MIT | S (link) | 4/5 |
| `aurora-mesh-bg` | [ibelick/background-snippets](https://github.com/ibelick/background-snippets) 2K⭐，CSS+Tailwind | MIT | S | 4/5 |
| `glassmorphism-surface` | ibelick/background-snippets（同仓，已合 PR） | MIT | S | 3/5 |
| `bento-grid` | [Kishan-shr/bento-grid-ui](https://github.com/Kishan-shr/bento-grid-ui) 纯 HTML+CSS，无 JS | MIT | S | 4/5 |
| `terminal-mockup` | [ramazancetinkaya/terminal-simulation](https://github.com/ramazancetinkaya/terminal-simulation) 单文件 HTML+CSS+JS | MIT | S | 4/5 |
| `vscode-mockup` | **DIY** ~200 行 JSX（现成方案都要 xterm.js+node-pty） | — | L | 5/5 |
| `arc-browser-chrome` | **DIY** ~180 行 JSX（所有现成都是浏览器扩展） | — | L | 5/5 |
| `toast-notification` + `drawer-sheet` | [emilkowalski/sonner](https://github.com/emilkowalski/sonner) 12K⭐ + [vaul](https://github.com/emilkowalski/vaul) 8K⭐，esm.sh CDN 可引（待实测） | MIT | S | 4/5 |
| `slide-deck-16-9` | reveal.js CDN + ~60 行 wrapper | MIT | S | 3/5 |

#### P0 — Device frames（已有升级）

| kind | 状态 | 来源 |
|---|---|---|
| `iphone-frame` | 现有 `iphone.jsx` 保留 | 自写 |
| `iphone-16-pro-frame` | 升级：devices.css（picturepan2/devices.css MIT）+ 手加 2024 notch | MIT |
| `ipad-frame` / `watch-frame` / `android-frame` / `macos-safari-frame` | 现有保留 | 自写 |
| `macbook-pro-16-2024` | 基于 devices.css + notch override | MIT |
| `chrome-browser-chrome` | [magnitce-browser-mockup](https://github.com/catapart/magnitce-browser-mockup) Web Component | CC0 | S |
| `vision-pro-spatial` | **DIY** ~150 行 JSX | — | L |
| `foldable-phone-frame` | **DIY** ~100 行 JSX（Galaxy Fold / Pixel Fold 两态切换） | — | M |

#### P1 — 产品常见（v0.2 做 5-7 个）

| kind | 来源 | License | 工程量 |
|---|---|---|---|
| `kanban-board` | [janhesters/shadcn-kanban-board](https://github.com/janhesters/shadcn-kanban-board) 零依赖纯 React DnD | MIT | M |
| `cmdk-palette` | 自写轻量版（pacocoursey/cmdk 要 Radix 不适 srcdoc） | MIT ref | M |
| `skeleton-loader` | 纯 CSS 动画模板集，~5 种变体 | — | S (DIY) |
| `empty-states-kit` | 自写 5-10 种不同风格 | — | M (DIY) |
| `landing-hero` | [launch-ui/launch-ui](https://github.com/launch-ui/launch-ui) 739⭐，section 可独立抽取 | MIT | M |
| `stepper-wizard` | 自写 ~80 行 | — | S (DIY) |
| `file-tree` | [pansinm/react-file-tree](https://github.com/pansinm/react-file-tree) | MIT | M |

#### P2 — 美学 / 背景层（v0.2 做 2-3 个）

| kind | 来源 | License | 工程量 |
|---|---|---|---|
| `noise-grain-overlay` | SVG `feTurbulence` inline data URI，~5 行 CSS | 技术通用 | S |
| `dot-grid-bg` | CSS `radial-gradient` 1px dot | 技术通用 | S |
| `animated-gradient-bg` | [codse/animata](https://github.com/codse/animata) 80+ 动画组件，抽取 | MIT | S |

#### P2 bonus — 惊喜发现

| kind | 来源 | 说明 |
|---|---|---|
| `voxcss-scene` | [LayoutitStudio/voxcss](https://github.com/LayoutitStudio/voxcss) 419⭐ MIT CDN 可用 HTML voxel 引擎 | 非常独特，可选 |

#### 待实测 / 推后

- **esm.sh CDN 在 Babel Standalone srcdoc iframe 的兼容性**（sonner / vaul 要验证）
- `motion-primitives` / `data-table` / `settings-panel` / `chat-ui` / `pricing-table` / `blog-editorial` / `doc-page` / `portfolio-grid` / `type-specimen` 等推后 v0.3+

#### Bundle 结构

```
packages/core/src/scaffolds/
  manifest.json            # kind → {description, path, size, license, source}
  device-frames/
    iphone.jsx             # 现有保留
    iphone-16-pro.jsx      # 新
    ipad.jsx
    watch.jsx
    android.jsx
    macos-safari.jsx
    macbook-pro-16-2024.jsx
    vision-pro.jsx         # DIY
    foldable.jsx           # DIY
  browser/
    chrome.js              # magnitce Web Component
    safari.jsx             # DIY
    arc.jsx                # DIY
  dev-mockups/
    terminal.html          # ramazancetinkaya 单文件
    vscode.jsx             # DIY
    claude-code-tui.jsx    # DIY (optional v0.3)
  ui-primitives/
    cmdk-palette.jsx       # 自写
    kanban-board.jsx       # janhesters 改写
    toast.jsx              # sonner 包装
    drawer.jsx             # vaul 包装
    skeleton-set.jsx       # DIY
    empty-states.jsx       # DIY
    stepper.jsx            # DIY
    file-tree.jsx          # pansinm 改写
  backgrounds/
    aurora-mesh.css
    glassmorphism.css
    bento-grid.css
    noise-grain.css
    dot-grid.css
    animated-gradient.css
  surfaces/
    neubrutalism.css       # OshekharO CDN wrapper
  decks/
    slide-16-9.html        # reveal.js 骨架
  landing/
    hero.jsx               # launch-ui 抽取
```

**合计约 30 个 scaffold**，工程量分布：~12 个 S（直接 bundle/CDN link），~12 个 M（改写、包装），~6 个 L（DIY 100-200 行）。

### 12.2 Skills（v0.2 目标 12 现有 + 5 新增 P0）

#### 格式：抄 agentskills.io / Anthropic SKILL.md spec

```yaml
---
name: form-layout
  Apply when building any form with 3+ fields, multi-step wizards,
  onboarding flows, checkout flows, or settings screens.
version: 0.1.0
authors: [open-codesign]
tags: [design, form, ux]
license: MIT
---

## When to use
## Rules
## Do / Don't
## Code patterns
```

**内部 skill() 调用名使用 snake_case**（e.g. `skill("form_layout")`），SKILL.md 文件名 / `name` 字段用 kebab-case（e.g. `form-layout/SKILL.md`）。别名映射层处理。

#### 现有 12 个 skill — 保留并升级

| skill | 升级内容 | 源 |
|---|---|---|
| `dashboard` | 加 Vercel Geist scale (label-14/copy-14)、APCA contrast rule、4-tier surface、nested radii | [vercel-labs/web-interface-guidelines](https://github.com/vercel-labs/web-interface-guidelines) + vercel.com/geist/typography |
| `landing-page` | 加 blueprint grid 模式、View Transitions for scroll reveal、APCA for hero text | Vercel blueprint article |
| `glassmorphism` | **合并进 `surface-elevation`**（保留 alias 向后兼容） | — |
| `editorial-typography` | 加 Swiss grid spec、pull-quote grid-break、drop-cap、APCA body | Bringhurst + Swiss typography |
| `chart-svg` | 加 APCA 调色板、色盲友好 palette（形状冗余） | Vercel guidelines |
| `heroes` | 加 View Transitions、scroll-linked reveal、CJK `text-autospace` | CSS scroll-driven |
| `slide-deck` | 加 investor deck ratio + Geist dark variant | mblode `presentation-creator` |
| `pricing` / `footers` / `chat-ui` / `data-table` / `calendar` | 保持，加 APCA contrast rule 提醒 | — |

#### v0.2 新增 P0（5 个）

| skill | 何时用 | 关键规则（3-5 条） |
|---|---|---|
| `form-layout` | 任何 3+ 字段表单 / onboarding / 结账 / 设置 | 单列为主；label 在字段上方（禁用 placeholder 当 label）；inline validation 在 blur 后而非打字时；多步在逻辑接缝切分 + progress；44px 最小触摸目标 |
| `empty-states` | Dashboard panel / 搜索结果 / 首次使用 | 三类：first-use（教育+CTA）/ no-results（reframe+建议）/ error（原因+重试）；必带 action button；不准出现裸 "No data" |
| `loading-skeleton` | 任何形状可预测的异步内容 | 骨架仅在形状可预测时用；匹配元素几何；progressive（先文本后可变）；形状不可预测时转 spinner；10-30s 超时转 error+retry；不做全屏 spinner |
| `surface-elevation`（扩 glassmorphism） | 卡片 / 模态 / 下拉 / 层级 UI | 层级靠 lightness 而非单一阴影；4-tier: base/raised/overlay/scrim；dark mode 每层 L +5-8%；layered shadow（ambient+direct 至少 2 层）；nested radius（child ≤ parent） |
| `cjk-typography` | 任何含中/日/韩的页面 | `line-height: 1.7-1.8` for CJK body；`word-break: normal` 简中；`line-break: strict` 日文；font stack: PingFang SC → Noto Sans SC → system；**禁**给 CJK 加 letter-spacing；CJK+拉丁混排用 `text-autospace` 或 U+2009；body 16-18px |

#### P1 延后（v0.3 候选，~5-7 个）

`oklch_color_system` / `micro_motion` / `bento_grid` / `neo_brutalist` / `scroll_narrative` / `investor_deck` / `navigation-patterns` / `whitespace-rhythm` / `icon-system` / `page-transitions` / `color-accessibility`

#### P1 — 借鉴 huashu-design 的两个 skill

灵感来自 [alchaincyf/huashu-design](https://github.com/alchaincyf/huashu-design)：

| skill | 何时用 | 内容 |
|---|---|---|
| `direction-advisory` | 用户没明确方向 / "随便给 3 个看看" | 从 5 个设计学派 × 20 哲学中抽 3 个不同风格生成 demo，让用户选。Taxonomy 直接抄 huashu-design 的清单 |
| `expert-review` | 用户明确说"review 一下"或 agent 想自检 | 5 维评分：philosophical consistency / hierarchy / execution / functionality / innovation。LLM 对 preview screenshot 做 critique（仅 vision model） |

`expert-review` 是**轻量级 verifier 的复活路径**——不是 v0.2 的硬 loop subagent，是用户主动 / agent 主动调的 skill。代码量 = 一段 prompt，没有架构改动。

#### 外部 skill 资源（供升级内容源）

| 源 | URL | License | 用途 |
|---|---|---|---|
| `anthropics/skills` | github.com/anthropics/skills | Apache-2.0 | 官方 frontend-design，基线参考 |
| `mblode/agent-skills` | github.com/mblode/agent-skills | MIT | ui-design / ui-animation / typography-audit / presentation-creator 质量高 |
| `vercel-labs/web-interface-guidelines` | github.com/vercel-labs/web-interface-guidelines | public | dashboard / landing-page 升级源 |
| `PatrickJS/awesome-cursorrules` | 39K⭐ | CC0 | CSS/styling 规则 pattern 挖掘 |
| Evil Martians oklch 文章 | evilmartians.com | public | oklch skill 内容源 |
| neubrutalism.com | MIT | — | neo-brutalist skill 内容源 |
| Muzli dark mode guide | medium.muz.li | public | dark-mode-done-right 源 |

### 12.3 Brand References（DESIGN.md 集合）

**我们 deliver 的文件 = Google DESIGN.md spec 合规**（YAML front matter + markdown body，基于 W3C DTCG）。**source 是什么格式无所谓**——任何描述品牌的素材（prose、CSS、截图、官方风格指南）都可以用来构造我们的合规文件。

#### 主素材源

| 源 | 内容 | License | 怎么用 |
|---|---|---|---|
| [VoltAgent/awesome-design-md](https://github.com/VoltAgent/awesome-design-md) (62K⭐) | 69 个品牌的 9 段精写 prose（Visual Theme / Color Palette / Typography / Components / Layout / Depth / Do's-Don'ts / Responsive / Agent Prompt Guide）| MIT, 明示 "extracted from public CSS" | 直接用作我们 DESIGN.md 的 markdown body 部分 |
| 官方品牌网站 CSS | 真实 hex / px / font-family | public | 程序化抽取 token 填 YAML front matter |
| [brandmd](https://github.com/yuvrajangadsingh/brandmd) | URL → prose DESIGN.md 自动生成 | MIT | 教用户后续自助生成新品牌 |

注：VoltAgent 和 brandmd 自身都是 prose-only（无 YAML），不能直接 `npx @google/design.md lint` 通过。但这不是问题——我们用他们的内容**作素材**，自己组装合规文件。

#### 我们的产出

`packages/core/src/brand-refs//DESIGN.md`，每个文件结构：

```markdown
---
# YAML front matter（机读 token，我们组装）
colors:
  primary: "#0070F3"
  ...
typography:
  display:
    fontFamily: "..."
    ...
spacing:
  ...
components:
  ...
---

## Visual Theme & Atmosphere
（来自 VoltAgent prose）

## Color Palette & Roles
...

（其余 prose 来自 VoltAgent）

---
*Inspired by [Brand]. Tokens derived from publicly available CSS.
Not affiliated with brand owners. Source: VoltAgent/awesome-design-md (MIT).*
```

#### 工程量

- 25 brand × ~30 分钟 = ~12 小时一次性投入
- CI 跑 `npx @google/design.md lint` 校验
- 一两天搞定，集中干

#### 推荐 25 个清单

| 品牌 | 类别 | 设计方向 |
|---|---|---|
| Vercel | Dev Tools | 极简 monochrome |
| Linear | Productivity | 工程师审美深色 |
| Stripe | Fintech | 渐变 premium |
| Figma | Design Tools | 黑白 + 产品色 |
| Notion | Productivity | 温暖衬线编辑器 |
| Apple | Consumer | 留白电影感 |
| Airbnb | E-commerce | 珊瑚暖色摄影 |
| Spotify | Media | 深色 + 绿 neon |
| Shadcn / Cursor | Dev Tools | 深色 IDE |
| Supabase | Backend | 翠绿开发者 |
| PostHog | Analytics | 刺猬玩味 |
| Framer | Design Tools | 黑蓝运动感 |
| RunwayML | AI/Creative | 电影暗色 |
| Mistral AI | AI | 法式紫调极简 |
| ElevenLabs | AI/Audio | 暗色听觉美学 |
| Coinbase | Fintech | 机构信任蓝 |
| Revolut | Fintech | 深色渐变卡 |
| Nike | E-commerce | 全黑大写 Futura |
| Ferrari | Luxury | 黑白稀疏 + 红 |
| SpaceX | Tech | 极简全黑白 |
| Starbucks | Retail | 大地绿 |
| Shopify | E-commerce | 深色霓虹绿 |
| IBM | Enterprise | Carbon 结构化 |
| Raycast | Dev Tools | 深色 + 渐变 accent |
| Cal.com | SaaS | 中性简洁 |

**`skill("brand:<name>")`** 懒加载，system prompt manifest 里列 25 个 brand 名字（~300 字节）。

#### License / 合规

- VoltAgent 内容 MIT，我们用作素材没问题
- 我们 deliver 的文件加 attribution（"Inspired by [Brand]. Source: VoltAgent (MIT)."）
- 大品牌（Apple / Nike / Ferrari）理论上有商标灰区——属行业惯例（Figma plugins / Style Dictionary 都这么做）
- 不主张所有权，标注来源即可

#### 推荐用户路径（v0.2 里写进文档）

用户想要**预装清单外**的品牌：
1. `npx brandmd https://yourbrand.com` 生成 prose 草稿
2. `npx @google/design.md lint` 校验 + 手补 YAML
3. 落到自己 workspace 根目录的 `DESIGN.md`

#### DESIGN.md 是双向 artifact（借鉴 Stitch）

不只是 system prompt 注入材料，也是**生成物之一**：

- **输入**：workspace 根的 DESIGN.md 自动注入 system prompt（Brand acquisition / brand skill 路径）
- **输出**：agent 可以 `done("DESIGN.md")` 产出合规 DESIGN.md（YAML + prose），用户可导出或让其它工具消费
- **跨工具兼容**：我们生成的 DESIGN.md 可以被 Stitch / Cursor / Claude Code 直接读
- **Stitch DESIGN.md 反向导入**：用户从 Stitch 导出的 DESIGN.md 拖进 workspace，我们 agent 立刻"懂"该品牌系统

`packages/artifacts` 加 `design-system` artifact 类型，schema 100% 兼容 [google-labs-code/design.md](https://github.com/google-labs-code/design.md)。CI 跑 `npx @google/design.md lint`。

---

## 13. Phase 规划（基于 spike 结论重估）

### Phase 1 — Foundation（3-5 天，spike 后大幅缩减）

- [x] Pi-coding-agent 集成 spike — **已完成**
- [ ] 等 PR #173 merge **OR** 直接 branch dev/v0.2 from main 并行（推荐后者）
- [ ] 从 main checkout `dev/v0.2`
- [ ] `packages/core` 重构骨架：包 `createAgentSession()`，暴露 IPC
- [ ] config.toml → `pi.registerProvider()` 翻译层
- [ ] AuthStorage 路径替换到 userData

### Phase 2 — 工具 + 存储（1-2 周，spike 后大幅缩减）

- [ ] `tool_call` hook + Permission Dialog UI（bash 权限流）
- [ ] FSWatcher → Files tab 通道
- [ ] v0.1 → v0.2 迁移脚本（SQLite scan → SessionManager.appendXXX）
- [ ] 删除 SQL 相关 IPC（snapshots-db / chat-messages-db / comments-db）
- [ ] Session JSONL 接通现有 chat pane 渲染

### Phase 3 — Design-domain 工具（1-2 周）

- [ ] `ask` 工具 + AskModal UI（5 种题型）
- [ ] `scaffold` 工具 + 预装清单组装（Phase 2 并行准备 starter 文件）
- [ ] `skill` 工具 + manifest 生成 + 懒加载 + 去重
- [ ] `preview` 工具拆分（从 `done` 拆，加 capability 分支：vision → screenshot, 否则 → DOM outline）
- [ ] `tweaks` 改跨文件 + scaffold 集成 EDITMODE 块

### Phase 4 — System prompt + 资源预装（3-5 天）

- [ ] 主 system prompt 内容按 §5 写满（含 Brand Acquisition Protocol）
- [ ] Scaffold bundle（~30 个，按 §12.1 优先级）
- [ ] Skill bundle（5 新增 + 现有升级）
- [ ] Brand refs bundle（~25 个 reformat，按 §12.3 清单）

### Phase 5 — UX 抛光 + 测试（3-5 天）

- [ ] 中断 / 后台进程精细化（`tool_call` event 已是基础，加 SIGTERM 流程）
- [ ] Capability-based tool exposure（spike 已验证，集成）
- [ ] Progressive disclosure 兜底
- [ ] E2E 测试 + bug bash
- [ ] Release note + upgrade doc

**重估总计**：~4-5 周单人，2-3 周双人。比 spike 前估的 6-8 周缩减 1/3。

主要节省来自：
- bash 不用自写（节省 1-2 周）
- session 存储不用自写（节省 1 周）
- model capability 不用维护表（节省几天）

---

## 14. 开放问题 / 风险

### 必须 spike 验证的

- [x] pi-coding-agent 的 bash hook 接口是否存在 — **已验证 Pass**
- [x] pi 的 Model 类型是否暴露 vision capability — **已验证 Partial→Pass**
- [x] pi SessionManager 能否指定 storage 目录 — **已验证 Pass**

### 设计未完全定的

- [ ] Preview 工具对非 web artifact source（SVG / 图像）的渲染策略
- [ ] Agent 外部 workspace（未绑 workspace 的 edge case）：其实已决"必有 workspace"，但 app 首次启动 + 无默认根路径时的降级
- [ ] Export / Claude Code 手递 bundle 具体 schema（v0.2 可先简化 zip + README）
- [ ] **轻量 visual verify**：v0.2 砍了 verifier subagent；huashu-design 用 Playwright 跑视觉验证。是否在 v0.2.x 加一个 `expert-review` skill（agent 自调，对 preview screenshot 做 5 维评）？

### 产品 / 业务风险

- [ ] Brand refs license 合规：VoltAgent repo 自身合规性 + 我们 bundle 的 attribution（待调研结果）
- [ ] Google DESIGN.md spec alpha 期可能 breaking change → 我们跟进策略
- [ ] pi-ai / pi-agent-core 版本追踪：pin 死会错过更新，追 latest 可能炸

### 性能 / scalability（暂不处理）

- 大 session（500+ turns）UI 虚拟化
- 大 workspace（5000+ files）FSWatcher 开销
- 多 design 并发 dev server 资源

---

## 15. 附录：关键决策快速查表

| 决策 | 选项 | 结果 |
|---|---|---|
| 存储 | SQL / JSONL | **JSONL + filesystem** |
| Design 模型 | 独立实体 / session | **session** |
| Workspace | 分 sealed/open / 统一 | **统一，默认根目录** |
| 工具数量 | 55 (Claude Design) / 12 | **12** |
| Loop 结构 | 相位 / agentic | **agentic，软引导** |
| 权限 | 无 (pi) / 多 mode (Claude Code) / 单 mode 4-tier | **单 mode 4-tier** |
| Verifier subagent | 有 (Claude Design) / 没有 | **没有** |
| Working memory | 有 / 没有 | **没有，用 AGENTS.md** |
| Snip 工具 | 有 / 没有 | **没有** |
| DESIGN.md | 自发明 / 抄 Google | **抄 Google spec** |
| Skill 格式 | 自发明 / 抄 agentskills.io | **抄 agentskills.io** |
| Brand refs | 无 / 抄 awesome-design-md | **抄并预装 25-30 个** |
| JSX 默认 | 每任务判断 / 默认 JSX | **默认 JSX + 代码简洁规则** |
| 向前兼容 | 严格 schemaVersion / 早期宽松 | **v0.x 宽松** |
| Screenshot 截图 | 每次评论自动截 / 用户主动 | **用户主动粘** |
| Verifier 代替 | preview 自检 | **preview 自检** |
| 消息队列 | 抄 pi / 不做 | **不做** |
| Session 分支 UI | 暴露 / 隐藏 | **隐藏（引擎支持，UI 不给）** |
| Undo | 做 / 不做 | **不做（只 Stop/Esc）** |

---

*Last updated: 2026-04-24. 待后台 3 个调研（scaffolds / skills / brand refs）全部完成后补充资源清单具体条目。*

---

## File: docs/VISION.md

# Vision — Open CoDesign

Locked product decisions. Update via PR, not in passing.

## One-line pitch

Open-source desktop design agent. It turns prompts, local files, skills, and brand systems into polished design artifacts on your laptop, with the model you choose.

## What we are building

Open CoDesign is a local-first Electron app for creating design artifacts with an agent that can see and edit a workspace. Each design is a long-running session backed by JSONL history and real files on disk.

The app serves founders, PMs, marketers, designers, and design engineers who want to make:

- Interactive web artifacts authored as HTML/JSX/CSS/SVG sources across mobile, desktop, tablet, and custom artifact sizes
- Slide decks, one-page reports, case studies, marketing pages, and export bundles
- Multi-artifact projects such as landing page + pricing page + onboarding email
- Brand-aware mockups driven by `DESIGN.md`, local files, and built-in brand references
- Design systems that can be exported, edited, and reused by other tools

The product started as an open-source counterpart to Anthropic's [Claude Design](https://www.anthropic.com/news/claude-design-anthropic-labs). The v0.2 direction is broader: a local design agent that borrows proven coding-agent mechanics, then adds design-specific tools for scaffolds, skills, preview, tweaks, images, and brand acquisition.

## What we are NOT building

- Not a general software engineering agent. The agent may read, edit, run commands, and manage files, but the product boundary is design artifacts and design-system handoff.
- Not a Figma replacement — we don't do collaborative vector editing.
- Not a Canva replacement — we don't ship a stock asset library or template marketplace.
- Not hosted SaaS. No account, cloud sync, or telemetry is required.
- Not a plugin marketplace in v0.2. Community skill/scaffold installation is deferred.
- Not a bundled local-model distribution. Local models can be used through system installs or compatible endpoints.

## Locked decisions

| Decision | Choice | Rationale |
|---|---|---|
| Form factor | Electron desktop (Mac + Win) | Local file access, codebase scan privacy, complements open-cowork |
| Agent runtime | `pi-coding-agent` + `pi-ai` | Use proven session, tool, provider, bash, and capability primitives instead of rebuilding them |
| Model layer | `pi-ai` | Multi-provider coverage for Anthropic, OpenAI, Gemini, DeepSeek, local, and compatible gateways |
| Authentication | BYOK, no hosted account | No backend, no liability for user keys |
| Storage | JSONL sessions + workspace filesystem | Design history is inspectable, backup-friendly, and aligned with pi sessions |
| Workspace model | Every design has a workspace | No sealed/open split; files are the source of truth |
| Design system format | Google `DESIGN.md` spec | Portable, editable by users, and usable by other tools |
| Design resources | Built-in skills, scaffolds, and brand refs | Improve taste through progressive disclosure rather than a huge prompt |
| Design language | Aligned with open-cowork and local `packages/ui` tokens | Keeps the shell coherent while artifacts bring their own style |
| Package manager | pnpm + Turborepo | Workspace, caching, fast |
| Lint/format | Biome (single tool) | Lessons learned from open-cowork's ESLint+Prettier complexity |
| License | MIT | Matches the public repo and keeps reuse simple |
| Contributor agreement | DCO (`Signed-off-by`) | Lower friction than CLA |

## Product pillars

### 1. Design as Session

A design is a pi session with a workspace. The sidebar shows sessions, not abstract projects. `cwd` points at the workspace; the session name is the design name. Multiple sessions can share one workspace.

### 2. Files Are Real

The agent writes source files such as `App.jsx`, CSS, `DESIGN.md`, assets, and exports to disk. The preview runtime turns source files into rendered web documents; the Files tab watches the filesystem rather than trusting tool-call logs. External edits from VS Code or Finder are first-class.

### 3. Agentic Loop, Soft Phases

The agent can plan, read files, edit files, run allowed commands, call design tools, preview output, ask structured questions, and finish through `done()`. The system prompt guides the loop; the runtime does not hard-code design phases.

The harness architecture for this loop is:

- **Run Controller** — owns `designId` + `generationId`, preflight questions, title/todo protocol, cancellation, timeout, and phase events.
- **Workspace Delta Bus** — streams file mutations, preview updates, and snapshot persistence per design/generation instead of through one global pending slot.
- **Context Pack / Session Memory** — workspace files plus compact brief are authoritative; model history stays bounded and excludes bulky tool payloads.
- **Verification Gate** — `preview(path)` is the mid-turn visual/runtime check, and `done(path)` is the finalization gate that either passes or returns compact repairable errors.

### 4. Progressive Disclosure

Skills and scaffolds are indexed in the prompt and loaded on demand. The base prompt stays small. Brand references and design techniques become tools the agent can pull when needed.

### 5. Brand Systems as Artifacts

`DESIGN.md` is both input and output. Users can bring one from another tool, edit it by hand, or ask Open CoDesign to create one. Brand values are extracted from authoritative files or URLs, not invented from model memory.

### 6. Local Control

The user owns model choice, API keys, workspace files, sessions, allowed commands, and exports. Networking is visible and tied to user intent.

## v0.2 Success Criteria

v0.2 is the shift from single-prompt generator to local design agent:

1. A new design creates or binds a workspace under the user's default workspace root.
2. Sessions persist as JSONL files through pi's `SessionManager`.
3. The app migrates v0.1 SQLite designs into workspaces and session history.
4. The agent uses pi built-ins for read, write, edit, bash, grep, find, and ls, with our permission hook.
5. Design-specific tools cover `ask`, `scaffold`, `skill`, `preview`, `gen_image`, `tweaks`, `todos`, and `done`.
6. `DESIGN.md` is loaded into context and can be produced as a design-system artifact.
7. Built-in scaffolds, skills, and brand references ship with license metadata and lazy loading.
8. Preview self-checks console errors, missing assets, DOM outline, and screenshots when the model supports vision.

## v1.0 Success Criteria

The v1.0 bar remains demo-driven, but the demos should run through the agentic workspace model:

1. Mobile app prototype with a device frame and real navigation
2. Client case study one-pager exportable as PDF
3. B2B SaaS pitch deck exportable as PPTX
4. Point-and-prompt revision through preview selection or comments
5. AI-emitted tweak controls across one or more files
6. Codebase or `DESIGN.md` driven design-system inheritance
7. Web or brand capture through the acquisition protocol
8. Handoff ZIP with artifacts, assets, `DESIGN.md`, and an intent README

## Differentiation vs Claude Design

| Axis | Claude Design | open-codesign |
|---|---|---|
| Model | Opus 4.7 only | Multi-provider via pi-ai and compatible gateways |
| Form | Web SaaS | Local desktop |
| Storage | Cloud-stored | JSONL sessions + local workspace files |
| Backend | Anthropic + Canva | None |
| Agent mechanics | Closed | pi-coding-agent primitives plus design tools |
| Brand systems | Internal | Portable `DESIGN.md` |
| Source | Closed | MIT |
| Cost | Subscription | BYOK token cost only |

## Non-goals (explicit)

- Real-time multi-user collaboration
- Built-in stock photo / icon library (link out instead)
- Mobile companion app
- Self-hosted server mode
- Custom in-house models
- MCP support in v0.2
- Session branching UI in v0.2
- Undo / version rollback in v0.2

## Ecosystem positioning (deferred)

Several axes stay deferred until the workspace agent is solid:

- **Claude ecosystem compat**: parse Claude Artifacts `<artifact>` tag protocol; expose ourselves as MCP server for Claude Code
- **open-cowork ecosystem**: shared `packages/ui`, shared sandbox runtime, artifact handoff conventions, and optional plugin integration
- **Stitch / DESIGN.md ecosystem**: import and export `DESIGN.md` cleanly enough that other tools can consume our design systems
- **Community resources**: user-installable skills, scaffolds, and brand refs

## Versioning milestones

- `0.1` — single-prompt design generation, local persistence, model setup, preview, comments, tweaks, and exporters
- `0.2` — agentic workspace loop using pi sessions, JSONL, permissioned tools, scaffolds, skills, preview, and `DESIGN.md`
- `0.3` — multi-artifact orchestration, richer brand/design-system workflows, and optional session branching UI
- `0.5` — all v1.0 demos work on the agentic workspace model
- `1.0` — installer budget green, distribution polished, migration reliable, all demos pass smoke tests

---

## File: examples/calm-spaces/README.md

# Demo · Calm Spaces meditation app

The "Calm Spaces" mobile prototype is the headline first demo for Open CoDesign,
mirroring the marquee Claude Design example (see `docs/research/01-claude-design-teardown.md`).

## What it generates

A single self-contained HTML artifact rendering a phone-frame mockup of a
meditation app home screen — meditation list, play button, soft greens/blues
palette, and tunable design tokens via CSS custom properties on `:root`.

## Run it

```bash
# 1. Provide a dev API key (Anthropic key works out of the box).
export VITE_OPEN_CODESIGN_DEV_KEY=sk-ant-...

# 2. Boot the desktop app from the repo root.
pnpm install
pnpm --filter @open-codesign/desktop dev
```

Then in the app:

1. Click the **Calm Spaces meditation app** starter in the left sidebar.
2. Press **Send** (or `Enter`).
3. Within ~30 s the iframe on the right renders the design.
4. Open the **Export** menu in the preview toolbar → choose **HTML** → pick a
   destination → **Save**.
5. `open <chosen-path>` in the browser shows the same design without the app.

## Expected behaviour

- The model emits exactly one `<artifact identifier="design-1" type="html" …>`
  block. The orchestrator extracts it via `@open-codesign/artifacts` and feeds
  the HTML into the sandbox iframe.
- Tailwind is loaded via the official CDN (`https://cdn.tailwindcss.com`). The
  HTML exporter inlines the CDN tag if the model forgot to.
- All colors, spacing, and font sizes are CSS variables — that's what the slider
  tier (Phase 2) will hook into.

## Failure modes (loud, by design)

- **No key** → assistant message tells you to set `VITE_OPEN_CODESIGN_DEV_KEY`.
- **PDF / PPTX / ZIP export** → throws `CodesignError` with code
  `EXPORTER_NOT_READY` and the toast reads "PDF export ships in Phase 2".
- **Network / provider error** → propagates as a `CodesignError` with code
  `PROVIDER_ERROR`; surfaced as the assistant's reply prefixed with `Error:`.

There are deliberately no silent fallbacks anywhere in this path
(see PRINCIPLES §10).

---

## File: packages/core/src/frames/README.md

# Device Frame Snippets

Device frames are JSX runtime snippets that the desktop host seeds into the
agent virtual filesystem as `frames/<name>.jsx`.

They are different from scaffold presets:

- Frames are read with `view("frames/iphone.jsx")` and adapted into `App.jsx`.
- Scaffolds are copied into the workspace with `scaffold(kind, destPath)`.
- Workspace `DESIGN.md` remains the design-system baton; frames are only visual
  chrome helpers.

## Available Frames

- `iphone.jsx` - iPhone frame.
- `ipad.jsx` - iPad frame.
- `watch.jsx` - watch frame.
- `android.jsx` - Android phone frame.
- `macos-safari.jsx` - macOS Safari window frame.

## How The Agent Uses Them

The host loads files from `/templates/frames/` and exposes them under
`frames/` in the virtual filesystem. The agent may view a frame when the brief
explicitly benefits from device or browser chrome, then copy the relevant
component structure into `App.jsx`.

Frames should not be final artifacts by themselves. The agent still needs to
adapt the screen content, tokens, interactions, accessibility, and any
`DESIGN.md` baton.

## Adding A New Frame

1. Drop `<name>.jsx` in `apps/desktop/resources/templates/frames/`.
2. Append the filename to `FRAME_FILES` in `packages/core/src/frames/index.ts`.
3. Keep `TWEAK_DEFAULTS` valid JSON when the frame has tweakable values.
4. Add focused tests if the loader contract or virtual path changes.

Conventions:

- JSX source compatible with the preview runtime.
- No external network assets or CDN scripts.
- Stable outer dimensions and clear inner screen/content region.
- Tunable values exposed through `TWEAK_DEFAULTS` only when useful.