Shell/Node tooling to drive the Open Design daemon headlessly — no GUI, no clicking. It gives you a tiny MCP stdio client, a reproducible design-generation wrapper, a component-gallery preview builder, and Playwright-based screenshot / diagram-injection helpers. Everything runs from the shell so it can live in CI, build scripts, or an agent loop.
The Open Design desktop app ships an Electron-bundled daemon and an
open-design-mcp server. This repo is the glue that lets you:
- start the daemon headlessly using the app's bundled Electron runtime,
- call MCP tools (
od_generate_design, etc.) over stdio from a script, - bring your own model key (BYOK) at runtime, and
- turn the output into previews, screenshots, and injected SVG diagrams.
Nothing here stores your API keys — they are read from the environment at call time and never written to disk by these scripts.
- Node.js ≥ 18 (uses ESM, top-level
await,node:imports). - The Open Design desktop app installed (for the daemon + bundled Electron).
- The
open-design-mcpserver available on disk (Homebrew global install by default — seeOD_MCP_SERVERbelow). - Playwright (only for
shoot.cjs/render-diagram.cjs):npm i -D @playwright/testthennpx playwright install chromium.
The daemon must run on the app's bundled Electron runtime, because the app's
native better-sqlite3 is compiled for that runtime's ABI — system node will
fail to load it. ELECTRON_RUN_AS_NODE=1 makes the Electron binary behave as a
plain Node interpreter while still exposing the correct native modules.
ELECTRON_RUN_AS_NODE=1 \
"/Applications/Open Design.app/Contents/MacOS/Open Design" \
"/Applications/Open Design.app/Contents/Resources/app/prebundled/daemon/daemon-cli.mjs" \
--port 4321 --host 127.0.0.1 --no-openscripts/start-daemon.sh wraps exactly this and is configurable via env vars
(OD_APP, OD_DAEMON_CLI, OD_PORT, OD_HOST). Run it in the background:
bash scripts/start-daemon.sh & # serves http://127.0.0.1:4321Once it is up, point tooling at it with OD_DAEMON_URL=http://127.0.0.1:4321.
scripts/od-mcp-call.mjs is a minimal JSON-RPC / MCP stdio client. It spawns the
open-design-mcp server, performs the initialize handshake, calls one tool,
prints the tool's text content to stdout, and exits non-zero on tool error.
node scripts/od-mcp-call.mjs <toolName> '<argsJSON>'Examples:
# A tool that talks to the running daemon:
OD_DAEMON_URL=http://127.0.0.1:4321 \
node scripts/od-mcp-call.mjs od_list_components '{}'
# Generate a design (see BYOK below for the required env):
node scripts/od-mcp-call.mjs od_generate_design \
'{"prompt":"a hero section using od-* tokens","kind":"other","maxTokens":8000}'Env it honors:
| Var | Purpose | Default |
|---|---|---|
OD_DAEMON_URL |
Daemon base URL (required by most tools) | — |
OD_MCP_SERVER |
Path to the open-design-mcp server.js |
/opt/homebrew/lib/node_modules/open-design-mcp/dist/src/server.js |
OD_TIMEOUT_MS |
Per-call timeout in milliseconds | 600000 |
BYOK_* |
Model credentials for generation tools | see below |
Generation tools (od_generate_design) call an OpenAI-compatible chat
endpoint that you supply. Configure it entirely through the environment; the keys
are sourced at runtime and never stored by this repo:
| Var | Meaning | Example |
|---|---|---|
OD_DAEMON_URL |
Running daemon URL | http://127.0.0.1:4321 |
BYOK_PROVIDER |
Provider id (OpenAI-compatible) | openai |
BYOK_BASE_URL |
Provider base URL | https://api.mistral.ai/v1 |
BYOK_API_KEY |
Your API key (read from env at call time) | $MISTRAL_API_KEY |
BYOK_MODEL |
Model id | codestral-latest |
Typical setup — keep keys in a git-ignored file and export them just for the run:
# ~/api_keys.sh (NOT in this repo)
export MISTRAL_API_KEY="sk-..."
export OD_DAEMON_URL=http://127.0.0.1:4321
export BYOK_PROVIDER=openai
export BYOK_BASE_URL=https://api.mistral.ai/v1
export BYOK_API_KEY="$MISTRAL_API_KEY"
export BYOK_MODEL=codestral-latestscripts/generate.sh will source such a file automatically if it exists
(OD_KEYS_FILE, default ~/api_keys.sh); otherwise export the BYOK_* vars
yourself. Any OpenAI-compatible provider works — point BYOK_BASE_URL,
BYOK_API_KEY, and BYOK_MODEL at OpenAI, Mistral, a local gateway, etc.
# 1. start the daemon headlessly (background)
bash scripts/start-daemon.sh &
# 2. export your BYOK env (or put it in ~/api_keys.sh)
export OD_DAEMON_URL=http://127.0.0.1:4321
export BYOK_PROVIDER=openai BYOK_BASE_URL=https://api.mistral.ai/v1 \
BYOK_API_KEY="$MISTRAL_API_KEY" BYOK_MODEL=codestral-latest
# 3. reproducibly generate a fragment from a prompt file
bash scripts/generate.sh examples/hero-prompt.txt examples/hero.out.html other 8000See USAGE.md for every script's purpose and example invocations, and examples/ for a sample prompt and the expected artifact shape.
| Script | What it does |
|---|---|
scripts/start-daemon.sh |
Launch the Open Design daemon headlessly (bundled Electron). |
scripts/od-mcp-call.mjs |
Minimal MCP stdio client — call one tool, print its output. |
scripts/generate.sh |
Reproducible od_generate_design wrapper (prompt file → artifact). |
scripts/build-preview.mjs |
Build per-brand component-gallery preview HTML (light + dark). |
scripts/shoot.cjs |
Screenshot preview HTML to light + dark PNGs via Chromium. |
scripts/inject-diagrams.mjs |
Inline generated SVG diagrams into pages by data-slug. |
scripts/render-diagram.cjs |
Render one SVG to light + dark PNGs via Chromium. |
MIT — see LICENSE.