Only executes verifiable Open Design atomic operations, and does not make visual direction, narrative, or template trade-off decisions on behalf of the client. Upper-layer design workflows can use this skill as the foundation for the daemon, catalog, design system, and export capabilities.
Client-readable description
What this skill can do
| Client wants | Skill will do | Client can see |
|---|---|---|
| Check or start Open Design | First determine which route is installed (CLI / desktop version / MCP), then check according to the route | route Determination, missing items, log locations, and repair commands |
| Install OD MCP for other agents | Generate configuration according to each vendor's real format (key names and structures have been tested one by one), preview only by default | Each vendor's diff, backup path, verification command |
| Sync design back to the code repository | Archive OD artifacts into docs/design/, and compare token drift between the draft and the implementation |
File list, item-by-item drift, raw color values, and red-line context |
| Integrate design system | Distinguish the formal three-piece set from the DESIGN.md-only compatibility path, then integrate via the upstream CLI/App |
Design system id, source, verification result |
| Query capability catalog | Query functional skills and rendering templates separately | Name, description,od.mode/category list |
| Render and export | Drive the App/CLI through upstream stable entry points, export HTML, PDF, PPTX, or MP4 | Artifact path, format semantics, openability check |
| Continue an existing design session | Reuse the native session handle saved by the daemon | Follow-up results from the same session or a clear reason for degradation |
How the client uses it
Other recognizable phrasings include "query design catalog" and "export design artifacts"; when design exploration or review is required, it is orchestrated by the upper layer soia-dev-design-explorer , and this skill only executes atomic operations.
- State the goal: environment check, daemon, design system, catalog query, render/export, or resume session.
- Provide the Open Design checkout path; when integrating the design system, also provide the project path or
DESIGN.md。 - When exporting, provide the project id, source files within the project, target format, and output path; for PPTX, also specify "pixel fidelity" or "editable".
- The Agent first runs a read-only check, then executes the minimal atomic command; overwriting files, deleting systems, or writing to remote must be separately confirmed.
- After execution, check the real API response or artifact; do not use the command exit code as a substitute for acceptance.
Dependencies and installation
Install this skill:
claude plugin marketplace add soia-team/soia-open-skills
claude plugin install soia-dev-design@soia
When only this one skill is needed, the npx route can be used. Note that the skill will land in the shared source of truth ~/.agents/skills; if the plugin is also installed, the same skill will appear in two indexes and each will drift, so it is recommended to choose one of the two:
npx skills add soia-team/soia-open-dev-design-skills -g -a '*' -s soia-dev-open-design-ops -y
Open Design itself: probe first, then ask, and only install last
Do not clone or install right away. On most client machines, Open Design is already present (the desktop app or an existing checkout), so no install command should be run. Determine in the following order, and stop as soon as one matches:
-
One command determines all three routes(desktop / CLI checkout / MCP):
python3 scripts/detect_route.pyrouteIf it is notnone, that means it is already installed,stop here and do not run a single install command。desktop/desktop-mcpno checkout and no Node/pnpm are needed; go directly to sections 3 and 4 of "Environment and daemon". -
route=nonewhenthen look at the detailed evidence:routes.cli.blockersindicates what the CLI route is missing,routes.desktop.evidence.app_bundleindicates whether the App is installed. -
indeed neither is present → ask the client first, and install only after obtaining explicit consent, and let the client choose the route themselves: the desktop app (no Node/pnpm needed, recommended for daily use) or a source checkout (needed only when participating in upstream development). Before the client replies, stop workflows that need the daemon and explain what is missing; do not decide on the client's behalf.
Use the commands below only after the client has explicitly chosen the source route. The upstream prerequisites are Node.js 24.x, pnpm 10.33.x,
and Corepack (see upstream QUICKSTART.md):
git clone https://github.com/nexu-io/open-design.git <open-design-root>
cd <open-design-root>
corepack enable
corepack pnpm --version # upstream 当前 pin 10.33.2
pnpm install
This skill does not install or embed Open Design, nor does it treat Open Design as another agent skill. If any of Node/pnpm/checkout is missing, stop workflows that need the daemon and return the commands to fill the gap— return commands for the client to execute; do not execute them on the client's behalf。
WorkBuddy is loaded as role-based experts rather than plugins,npx skills add -a '*' does not cover it; it needs to be installed separately, see docs/install/workbuddy.md。
Private configuration
Copy assets/config.example.yml to:
~/.config/soia-skills/soia-dev-open-design-ops/config.yml
SOIA_DEV_OPEN_DESIGN_OPS_CONFIG_FILE=<custom-config-path>
Configure at least OPEN_DESIGN_HOME. The daemon binds to loopback by default, with the default port 7456; it can be overridden with OPEN_DESIGN_DAEMON_PORT、OPEN_DESIGN_WEB_PORT、OPEN_DESIGN_DAEMON_URL . The project's own DESIGN.md path may go in OPEN_DESIGN_PROJECT_DESIGN_MD. The local checkout and project paths go only into private config or the process environment, and are not written into public prose, repositories, or logs.
Private information and intermediate data
- Credentials: this skill holds no credentials. Open Design's login state is managed by the App itself;
OPEN_DESIGN_HOME, project paths, and other local information go only into privateconfig.ymlor the process environment, and are not written intoSKILL.md, logs, receipts, or commits. - Ports and socket paths: the desktop app's port changes on every start,
OD_SIDECAR_IPC_PATHincludes a namespace. Both areprobed only at runtime, not cached, and not hard-coded into any file. - Intermediate data:
detect_route.py/desktop_ctl.py/od_sync.py --checkare all read-only and are not written to disk.install_od_mcp.pyandod_sync.py --archivewrite to disk; before writing, show a diff or file list, and back up overwritten original files as<file>.bak-od。 - Archive artifacts:
od_sync.py --archiveare written only to the<repo>/docs/design/explicitly specified by the client, skipping.artifact.jsonand other OD internal metadata; do not touch Open Design's data directory. - On-disk locations follow this repository's
DATA_STORAGE_SPEC.md。
Logs and completion receipts
Daemon background logs and PID state are written to the user state directory; this can be changed with OPEN_DESIGN_STATE_DIR . Do not print config contents or env values. Minimum receipt:
完成:<本次原子操作及结果>。
日志摘要:
- environment/daemon: <ok、missing 或 unreachable>
- processed: <系统/技能/模板/产物数量>
- created/updated: <产物或状态类别>
- skipped/failed: <数量与原因>
文件变化:<产物路径或“未改动项目文件”>
验证:<API、文件存在、页数/时长/打开检查>
问题与下一步:<缺依赖、需客户确认或“无”>
Positioning and boundaries
- Only perform atomic operations such as installation guidance, daemon, directories, design system integration, rendering/export, and resume.
- Do not decide design direction, layout, brand language, deck narrative, or visual review; these belong to slides, visual,
soia-dev-design-explorerand other upper-layer workflows. - A functional skill is a capability in the agent's work; a design template is a rendering form. The two types of directories must not be merged into one list.
- Do not invent a headless API. When there is no stable script entry point upstream, explicitly write "the agent drives the upstream App/CLI according to the documentation".
- Credentials, provider login state, and local paths go only into the provider's own storage, private config, or process environment.
Environment and daemon
Determine the entry point once, and it must be done first: the local machine may have three mutually independent routes installed—CLI source checkout, desktop App, MCP. Which one is installed depends entirely on how the customer installed it.
python3 scripts/detect_route.py # 人读 python3 scripts/detect_route.py --json # 机读,供上层分流Output
routeascli/desktop/desktop-mcp/none, and based on that choose the corresponding subsection of this section:
route Which section to use What not to do cli1–2 — desktop3 Do not run check_env.py/daemon_ctl.pydesktop-mcp3 + 4 Same as above; prefer route 4, which has the most complete capabilities noneFix according to suggestionsFixDo not force-run any section This step cannot be skipped. Running on a machine with only the desktop version installed
check_env.pywill necessarily returnstatus=error(missingnode_24/pnpm_10_33/daemon_7456_unreachable), that is the correct conclusion of "the CLI route is not installed",not that the environment is broken. Treating it as a failure will cause the entire workflow to stop at a prerequisite that is not needed at all.
1. Detect the environment (CLI / source checkout route)
Run from this skill directory:
python3 scripts/check_env.py
The script performs an offline check of node、pnpm、OPEN_DESIGN_HOME and key repository files, and outputs status、missing、checks and suggestions JSON. When Node is not 24.x and pnpm is not 10.33.x, it returns an incompatible status and does not automatically upgrade.
2. Start/stop and health check
python3 scripts/daemon_ctl.py start
python3 scripts/daemon_ctl.py status
python3 scripts/daemon_ctl.py health
python3 scripts/daemon_ctl.py stop
start Use the pnpm tools-dev run web control plane from the upstream Quickstart, explicitly pass --daemon-port, and record the PID and logs as a detached/nohup-style background process. Do not use the removed pnpm dev、pnpm daemon or pnpm start aliases. The health check is based on GET /api/skills returning skills array;/api/health only indicates process-level liveness and does not prove that the skill directory is usable.
The default URL is http://127.0.0.1:7456. Only loopback URLs are allowed; when remote deployment, reverse proxy, or 0.0.0.0 is required, this skill stops and requires the customer to handle it according to the upstream security configuration, and does not expose the local daemon on the customer's behalf.
3. Desktop App (this is a separate system from the CLI daemon; do not mix them)
When the customer has installed /Applications/Open Design.app , the above CLI daemon route is basically not applicable:
-
Different data directories: the desktop version is in
~/Library/Application Support/Open Design/namespaces/<namespace>/data/(namespaceis usuallyrelease-stable), while the CLI is in the repository's.od/。The two cannot see each other's projects。 -
odThe CLI is not in PATH in the packaged version. The official documentation saysod status、curl od://app/..., but after packaged installation:/usr/bin/odis built into macOSoctal dump tool, directly typingod statuswill invoke the wrong program and report a bunch of unrelated errors;curldoes not recognizeod://This Electron custom scheme,curl -s od://app/api/healthreturns empty;- Tested
--daemon-url od://appalso fails to parse on the command line (even when explicitly givenOD_SIDECAR_IPC_PATH), this scheme is currently only usable in the MCP sidecar context.
Packaged version's
odequivalent call (tested and working):HELPER="/Applications/Open Design.app/Contents/Frameworks/Open Design Helper.app/Contents/MacOS/Open Design Helper" CLI="/Applications/Open Design.app/Contents/Resources/app/prebundled/daemon/daemon-cli.mjs" od(){ ELECTRON_RUN_AS_NODE=1 "$HELPER" "$CLI" "$@"; }By default it hits
http://127.0.0.1:7456(the CLI daemon's port), which is invalid for the desktop version, so every command must explicitly include--daemon-url http://127.0.0.1:<探测到的端口>。 -
the port changes on every launch, and there is no default value. Do not hardcode 7456, and do not cache the last probed port:
lsof -nP -iTCP -sTCP:LISTEN | grep -i '^Open' | awk '{print $9}' | sed 's/.*://'Probe one by one to find which is the daemon API (returns
{"projects":[...]}); the remaining ports are the Next.js UI and proxy, which return HTML. This has been scripted, prefer using it rather than typing it by hand every time:python3 scripts/desktop_ctl.py detect # 活着的 daemon API 端口 python3 scripts/desktop_ctl.py projects # 列项目,并标出谁缺 entryFile python3 scripts/desktop_ctl.py doctor # 「看不到项目」一键体检desktop_ctl.pyisread-only diagnostics: does not modify customer data, does not restart the App, does not print credentials; when the daemon is unreachable it ends with a non-zero exit code and a clear hint, without pretending everything is fine. -
Launching the desktop version takes over and stops the CLI daemon, so the two cannot be used at the same time.
Packaged version's od equivalent call, project metadata (entryFile and .artifact.json), the diagnosis of "cannot see the project", and the three places to clear when deleting a local plugin—see references/desktop-app.md。
4. MCP route (most capable, the only path to dispatch a run)
The desktop version exposes itself as an MCP server.This is the only path that can "dispatch work to Open Design and let it generate on its own, while letting the customer see the whole process in the UI"—the HTTP API can only read and write files, it cannot dispatch a run.
start_run(project, prompt) → 立刻返回 runId,OD 自己 spawn agent 去做
get_run(runId) → queued|running|succeeded|failed|canceled
Three hard constraints, violate them and it is a wasted run: the prompt must inline the full text of tokens.css (the agent inside the run reads
design-systems/ and gets a 404);toolBundle.mcpServers defaults to empty; real-time progress is only in the on-disk
<data>/runs/<runId>/events.jsonl ,get_run cannot see it.
The configuration shape, the tested matrix per agent, WorkBuddy's UI fields, and the full explanation of the above constraints—see references/mcp-hosts.md。
5. Sync the design back to the customer's code repository
The desktop version's data directory may become invisible at any time due to reinstallation, switching machines, or a daemon failure,any design asset that needs to be kept long-term must have a copy in the customer's own git repository. More importantly: the design mockup and the production implementation will drift apart on their own without anyone noticing—10px in the mockup, 13px in the implementation, and neither looks wrong on its own.
# 归档:OD 的 pages/ specs/ index.html → <repo>/docs/design/(默认预览)
python3 scripts/od_sync.py --project <id> --repo <repo-root> --archive
python3 scripts/od_sync.py --project <id> --repo <repo-root> --archive --apply
# 核对:稿 vs 实现的 :root 令牌漂移、:root 外裸色值、可选红线
python3 scripts/od_sync.py --project <id> --repo <repo-root> --check \
--design pages/<page>.html --impl <path-in-repo> [--redlines <file>]
--check Any drift means a non-zero exit, so it can be hooked into CI.
The red-line scan must strip comments, and only report context without drawing conclusions. A codebase that is well written will spell out the discipline in comments ("never do completion-rate rankings", "do not show a countdown"); if you do not strip comments, you will reportevidence of compliance as a violation—in one tested single-file app, 4 of the 5 categories of hits were comments; after stripping, 2 categories remained, and one of them was even a video filename. So the scanner outputs context for human judgment, and does not directly declare a violation.
6. Open only one design project per product
Do not create a new Open Design project for every page you make—once they are scattered into a pile, any change the customer makes to any page requires first thinking "which project is this".
Recommended structure (one project, filenames map one-to-one to online routes):
<project>/
├── index.html 入口:全路由对照表,标明哪些有稿、哪些待设计
├── pages/<route>.html 每个线上路由一个页面稿
└── specs/*.md 分层设计规范(基础体系 + 各页专项)
New pages are generated by running run inthe same project, with output landing in pages/, then in index.html move it from
"to be designed" to "design draft exists". Delete old one-off projects after confirming their assets have been merged in; don't leave them around to confuse the client.
Run run directly in an existing project from the command line (without going through MCP, available immediately after daemon restart):
od run start --project <projectId> --agent codex \
--message "$(cat brief.md)" --json --daemon-url "$DAEMON_URL"
od run watch <runId> --daemon-url "$DAEMON_URL" # ND-JSON 事件流
od run info <runId> --daemon-url "$DAEMON_URL"
Without --plugin the daemon will pick one itself (e.g. example-web-prototype);
if you need a specific template, pass it explicitly --plugin <id>(od there is no plugin list subcommand, use
GET /api/plugins to get the id). Generation usually takes 5–30 minutes, poll run info,
don't cancel just because the file mtime isn't changing.
To make a second page in the same project, you must start a new session first:run start without --conversation
will reuse the project's default session. The previous round's task is still in context, so the agent will treat the new brief as
"continuing the previous round", reply "there are currently no new change requests", and exit normally—
status=succeeded, exit=0,artifactCount: 0, no agentMessage,not a single file written.
Create a new session first, then run:
curl -s -X POST "$DAEMON_URL/api/projects/<projectId>/conversations" \
-H 'content-type: application/json' -d '{}' # 返回 conversation.id
od run start --project <projectId> --conversation <newId> --agent codex \
--message "$(cat brief.md)" --json --daemon-url "$DAEMON_URL"
When troubleshooting, look at <data>/runs/<runId>/events.jsonl: the agent's text output is in the data.type=="text" events.
run does not survive a daemon restart: after the desktop daemon disconnects or restarts, an in-progress run disappears along with its record
(run info returns NOT_FOUND), and leaves no artifacts. So don't restart the App during a long run;
if you really did restart, just re- run start, don't waste time trying to recover the original runId.
Design system management and project onboarding
The Design System Project trio
When creating or maintaining a formal Open Design Design System Project, use upstream _schema as the source; the minimum contract is:
<design-system-slug>/
├── manifest.json
├── DESIGN.md
└── tokens.css
manifest.jsonusesod-design-system-project/v1, and the folder slug matches the manifest id.DESIGN.mdis the canonical design prose for the agent;tokens.cssis the canonical compiled semantic tokens.- New systems must not treat
DESIGN.md-only as the authoring target. For the rich package's optional files and token constraints, refer to upstreamdocs/design-systems.md、design-systems/_schema/AGENTS.mdand the TypeScript schema.
Package consistency validation
Built-in packages can contradict themselves; you can't just read DESIGN.md and start working. Priority for resolving conflicts:
tokens.css > components.html > DESIGN.md / USAGE.md
Empirical evidence (warm-editorial the five conflicts), the location of built-in packages on disk, and the mount and validation commands—see
references/design-systems.md。
The user project's DESIGN.md-only compatible onboarding
Existing projects can first put design rules in <user-project>/DESIGN.md. The daemon retains DESIGN.md-only discovery for registered legacy/user-installed directories, but this is a compatibility fallback. For project onboarding, prefer the CLI/App's local import, letting the daemon scan and build an editable design system:
node <open-design-root>/apps/daemon/dist/cli.js design-systems import-local <user-project> --name "<project-name>" --json
node <open-design-root>/apps/daemon/dist/cli.js design-systems list --json
For the first instance, you can point a real product project's <product-project>/DESIGN.md to a private OPEN_DESIGN_PROJECT_DESIGN_MD, then use <product-project> to execute import-local; do not copy or hardcode the maintainer's path. If dist/cli.js does not exist, first run in the checkout pnpm --filter @open-design/daemon build。
Common management commands use od design-systems help by the actual output; v0.13.0 already has list/show/rename/download/import-local/import-github/import-shadcn. rename, delete, overwrite import, or token rebuild affect persistent state, so show the target and current state before confirming.
Directory query
Functional skills
python3 scripts/list_skills.py
python3 scripts/list_skills.py --category slides
The script calls the daemon GET /api/skills, outputting name、description、od.mode and category;--category performs local exact filtering on the API-returned results, because this route itself has no server-side category query.
Rendering templates
Rendering templates are provided by GET /api/design-templates and the checkout's design-templates/ , and do not belong to /api/skills. When templates are needed, use the App's New Project "Start from" rail or query that API directly; do not use list_skills.py to pretend to cover the template directory.
For a Deck, first choose one of the three entry categories, then hand it to the upper-layer flow for design decisions:
simple-deck: design-system-driven, single-file, tightly constrained horizontal deck;guizang-ppt: e-magazine/WebGL line, including the five directions Monocle, WIRED, Kinfolk, Domus, and Lab;html-ppt: HTML PPT Studio line, providing full-deck, theme, layout, animation, and presenter runtime directories.
Rendering and export
Submit a render task
- In the App, select runtime, design template, and design system, and submit the prompt; filesystem-capable runtimes write canonical project files, while text-only/BYOK runtimes return the complete
<artifact>。 - Open the project from the App and verify the preview; or have a daemon-spawned agent use the injected
OD_BIN、OD_DAEMON_URL、OD_PROJECT_ID、OD_PROJECT_DIR。 - Do not directly POST an undocumented chat/run payload. For automation, prefer the already-built
odCLI; for App-only interactions, have the agent drive them according to the upstream documentation.
HTML
HTML is the canonical artifact in a project. Use App Download → HTML, or read/copy the source files within the project. The v0.13.0 od export has no --format html, and that format must not be faked; use the project file API/route only when a project id and path actually exist.
PDF and PPTX
After building the daemon CLI, you can use the stable commands from upstream v0.13.0:
node <open-design-root>/apps/daemon/dist/cli.js export <project-file.html> \
--project <project-id> --format pdf --out <output.pdf>
node <open-design-root>/apps/daemon/dist/cli.js export <deck.html> \
--project <project-id> --format pptx --out <output.pptx>
The built-in PPTX is one screenshot per page, suitable for pixel-faithful delivery, not an editable shape/text deck. For editable PPTX, the recommended chain is:
- Use the HTML deck as the visual source of truth;
- Invoke the functional skill
pptx-generatorto generate editable.pptx; - Invoke
pptx-html-fidelity-auditto compare HTML/PPTX and fix footer overflow, cropping, font/italic, and rhythm drift; - Open the final PPTX and check the page count, canvas size, key text, and that nothing goes out of bounds.
MP4
MP4 uses the HyperFrames HTML renderer and does not pretend to be a general-purpose video export:
node <open-design-root>/apps/daemon/dist/cli.js media generate \
--surface video --model hyperframes-html \
--project <project-id> --composition-dir <project-relative-composition-dir> \
--output <output.mp4>
The composition directory must contain the upstream-required hyperframes.json/meta.json/index.html. The daemon actually drives npx hyperframes render; after the task is queued, use od media waitaccording to the task id returned by the CLI, and finally verify the file exists, the MIME, the duration, and playability.
Session resume (v0.13.0)
Native resume is done automatically by the daemon, not manually by the user od resume:
- Reopen the original project and the original conversation without creating a new session;
- Send a follow-up turn;
- The daemon reuses the captured native session id for supported runtimes, so that v0.13.0 supported items such as Codex, OpenCode, Pi, and Open Design Cloud continue across turns;
- Check the run result and touched files to confirm it is not a cold start.
If the session handle has expired, the runtime does not support it, or the CLI refuses to resume, explicitly report "resume unavailable/expired", then let the customer decide whether to rebuild context from historical messages; do not pass off a rebuild as a native resume. After a daemon restart, still use the actual conversation/run metadata as evidence.
Private configuration command wrapper
When a controlled upstream command needs to be executed with config explicitly loaded:
python3 scripts/run_with_env.py -- pnpm tools-dev status
python3 scripts/run_with_env.py -- pnpm --filter @open-design/daemon build
The wrapper only allows known Open Design lifecycle and build/install/version forms of Corepack/pnpm; it rejects shell,env、printenv, arbitrary executables, and pnpm exec/dlx. Do not use set -x, and do not print env values.
Security guidelines
- The daemon is a local privileged service and by default binds only to
127.0.0.1; do not expose public ports for convenience. - Do not print config, env, provider credentials, or tokens injected by the daemon; logs only indicate presence/absence.
- stop only handles PIDs recorded by this skill; if the PID does not match or the state is unclear, stop and report, do not guess at processes.
- Before import, rename, delete, download overwrite, or export overwrite, check the target's current state; deletion and overwrite must receive explicit authorization in the current request.
- Do not modify the upstream source code in
OPEN_DESIGN_HOMEto "wire up" the project; this skill only performs read-only queries or operates according to the official CLI/App.
Acceptance
- Environment:
check_env.pyreturnsstatus=ok, with no missing. - daemon:
daemon_ctl.py healthverifies that/api/skillsreturns an array. - Directory: skills and templates are fetched separately; all category filter results match.
- Design system: the full set of three is present, or it is explicitly marked as
DESIGN.md-only compatibility; after import it can be list/show. - Export: the target file exists, is non-empty, and is in an openable format; for PDF/PPTX check the page count, for MP4 check the duration and playability.
- resume: a follow-up in the same project/conversation has native resume evidence; without evidence, do not claim success.