open-codesign Documentation

Open-source Claude Design alternative. One-click import your Claude Code / Codex API key. Prompt → prototype / slides / PDF.

RAW Doc

File: README.md

Open CoDesign

简体中文: 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 · Quickstart · What's new · Changelog · Discussions · Docs · Contributing · Security

Open-source alternative to: Claude Design · v0 by Vercel · Lovable · Bolt.new · Figma AI


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. Refs #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 → · Changelog →


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:

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.

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.

    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.

    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.

  • 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 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 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 or feature request template.
  4. For security vulnerabilities, see SECURITY.md.

More from OpenCoworkAI

If you like Open CoDesign, you may also want to check out our earlier project, 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 community — thanks to everyone there for the early feedback and discussion.

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 and we will refresh the image in-repo.

See also the Chinese README: README.zh-CN.md#社群.

Contributing

Read 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.

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:

text
/*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

text
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:


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

text
~/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。
text
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 的 baton pattern——多屏 / 多 page 项目(landing + dashboard + settings 等)保证视觉一致:

text
生成屏 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)

text
用户 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 模型)

text
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 层叠

text
[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(A/B 测结果显示降低输出方差 5×)。写进 system prompt:

text
## 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)

分层

text
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(三按钮)

text
┌─────────────────────────────┐
│ 🟡 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

两条独立通道:

text
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 40+ 组件 70KB CSS,CDN 可引 MIT S (link) 4/5
aurora-mesh-bg 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 纯 HTML+CSS,无 JS MIT S 4/5
terminal-mockup 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 12K⭐ + 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 Web Component CC0
vision-pro-spatial DIY ~150 行 JSX —
foldable-phone-frame DIY ~100 行 JSX(Galaxy Fold / Pixel Fold 两态切换) —

P1 — 产品常见(v0.2 做 5-7 个)

kind 来源 License 工程量
kanban-board 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 739⭐,section 可独立抽取 MIT M
stepper-wizard 自写 ~80 行 — S (DIY)
file-tree 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 80+ 动画组件,抽取 MIT S

P2 bonus — 惊喜发现

kind 来源 说明
voxcss-scene 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 结构

text
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 + 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:

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 (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 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。CI 跑 npx @google/design.md lint。


13. Phase 规划(基于 spike 结论重估)

Phase 1 — Foundation(3-5 天,spike 后大幅缩减)

  • 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 验证的

  • pi-coding-agent 的 bash hook 接口是否存在 — 已验证 Pass
  • pi 的 Model 类型是否暴露 vision capability — 已验证 Partial→Pass
  • 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. 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.