skills/open-design-mcp/SKILL.md
Use this skill whenever the user mentions open-design, od_generate_design, OD daemon, BYOK design generation, generating HTML mockups from a PRD, creating or managing Open Design projects, saving design artifacts, linting generated HTML, or any of the 10 `od_*` MCP tools (od_list_projects, od_get_project, od_create_project, od_update_project, od_delete_project, od_save_artifact, od_save_project_file, od_lint_artifact, od_compose_brief, od_generate_design). Also trigger on phrases like "generate a design", "create a mockup", "make a landing page", "list my OD projects", "the design daemon", "the streaming design tool", and on any 401/404/422 error coming from an `od_*` tool call. Covers env-var setup (`OD_DAEMON_URL`, auth modes, BYOK), the full PRD → generate → save → lint workflow, error diagnosis, and the safety rails (lint before save, never commit BYOK keys). Triggers even if the user doesn't explicitly say "open-design-mcp" — keyword matches on `od_*` tool names or "design generation" workflows are enough.
npx skillsauth add nano-step/skill-manager open-design-mcpInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Skill for using the open-design-mcp server — an MCP wrapper around the Open Design daemon. Teaches an LLM how to pick the right tool, set the right env vars, and recover from common errors.
open-design-mcp exposes 10 tools that fall into 5 workflows:
| Workflow | Tools | When |
|---|---|---|
| Read | od_list_projects, od_get_project | Exploring what exists. Read-only. Safe by default. |
| Manage | od_create_project, od_update_project, od_delete_project | CRUD on projects. Delete is permanent — no undo. |
| Format | od_compose_brief | Pure helper — combines Turn-1 form answers + brand-spec + page brief into a Turn-3 prompt string. No network, no env vars. |
| Validate | od_lint_artifact | Cheap sanity-check on HTML before saving. |
| Generate | od_generate_design, od_save_artifact, od_save_project_file | Streams an HTML design from a PRD using a Bring-Your-Own-Key LLM, then persists it to the global artifact store (od_save_artifact) or inside a project (od_save_project_file). |
All tools require OD_DAEMON_URL. Only od_generate_design additionally needs BYOK env vars (BYOK_BASE_URL, BYOK_API_KEY, BYOK_MODEL). That asymmetry matters — see references/environment-setup.md.
Trigger on any of these:
| User intent | Recognize from | First tool to call |
|---|---|---|
| "Show me my projects" | "list projects", "what designs exist", "show all OD projects" | od_list_projects |
| "Look at this project" | "get project X", "show artifacts for Y", "what's in this project" | od_get_project |
| "Make a new project" | "create project", "start a new design project" | od_create_project |
| "Rename / update project" | "change name", "update kind", "set fidelity to mid" | od_update_project |
| "Delete project" | "remove project", "delete X" — confirm intent first | od_delete_project |
| "Generate a design / mockup" | PRD provided + "make a design", "generate UI", "build a mockup" | od_generate_design |
| "Compose a multi-page brief" | User answered discovery questions + has a brand spec + wants per-page prompts | od_compose_brief (then pass result to od_generate_design) |
| "Save this HTML to a project" | "save inside the project", "show in OD viewer", "attach to project X" | od_save_project_file (after lint) |
| "Save this HTML globally" | "persist", "save artifact", "store this design", standalone shareable URL | od_save_artifact (after lint) |
| "Validate this HTML" | "lint", "check for issues", "is this valid?" | od_lint_artifact |
| Any 401/403/404/422 from an od_* tool | Error message contains "od_" or "Open Design" | See references/errors.md |
Descriptions are verbatim from src/tools/*.ts — do not paraphrase when responding to users.
| Tool | Description | Env vars required |
|---|---|---|
| od_list_projects | List all projects from the configured Open Design daemon. Read-only; requires only OD_DAEMON_URL. | OD_DAEMON_URL |
| od_get_project | Fetch a project + its artifact files. Read-only; requires only OD_DAEMON_URL. Output includes customInstructions if set on the project (user-supplied content). | OD_DAEMON_URL |
| od_create_project | Create a new project on the Open Design daemon. Returns the project details and an auto-seeded conversation ID. Requires only OD_DAEMON_URL. | OD_DAEMON_URL |
| od_update_project | Update a project on the Open Design daemon. At least one mutable field (name, customInstructions, kind, fidelity, linkedDirs) must be provided. Requires only OD_DAEMON_URL. | OD_DAEMON_URL |
| od_delete_project | PERMANENTLY delete a project. The Open Design daemon removes the database row AND the on-disk project directory. This cannot be undone. Requires only OD_DAEMON_URL. | OD_DAEMON_URL |
| od_save_artifact | Persist an HTML artifact to the daemon under a slug identifier. Writes to the global artifact store — NOT project-scoped. Requires only OD_DAEMON_URL. | OD_DAEMON_URL |
| od_save_project_file | Persist a file (typically HTML from od_generate_design) INSIDE a project so it appears in od_get_project.files[] and renders in the daemon UI. Wraps POST /api/projects/:id/files. Daemon limit: ~5 MB content. | OD_DAEMON_URL |
| od_lint_artifact | Validate an HTML artifact for structural issues. Returns text findings + optional agent message. | OD_DAEMON_URL |
| od_compose_brief | Format a Turn 3 prompt for od_generate_design. Combines Turn 1 form answers, Turn 2 brand-spec, and the page brief into a single string that upstream Open Design recognizes. Pure function: no network, no env vars. | none |
| od_generate_design | Generate a design artifact using BYOK. Composes the upstream Open Design system prompt and proxies through OD's /api/proxy/<provider>/stream endpoint. Requires BYOK_BASE_URL, BYOK_API_KEY, BYOK_MODEL env vars in addition to OD_DAEMON_URL. | OD_DAEMON_URL + BYOK_* |
od_list_projects # see what exists
→ pick a project id
od_get_project {id} # get details + artifact list
No BYOK needed. Use this any time the user asks "what's in OD?" before doing any writes.
od_create_project { # body: name + kind required
name: "Pricing page",
kind: "prototype", # one of: prototype | deck | template | image | doc | research | site
fidelity: "mid" # one of: low | mid | high
}
→ returns project id + auto-seeded conversationId
od_update_project {id, name: "...", customInstructions: "..."} # partial update
od_delete_project {id} # PERMANENT — always confirm with user first
The customInstructions field is how you bake design preferences ("dark mode", "rounded corners", "Tailwind v4") into all future generations on this project. Set it once on create or update — od_generate_design reads it.
This is the workflow most users actually want. Order matters:
1. (optional) od_create_project # if no existing project
2. od_generate_design { # the streaming one — takes 10–60s
projectId: "...",
prompt: "<the PRD or refinement instruction>",
kind: "prototype" # match the project's kind
}
→ returns { html: "<!doctype html>..." } # full HTML string
3. od_lint_artifact { html } # CHEAP — always do this before saving
→ returns findings; if any are "error" severity, fix and regenerate
4. Save the result — pick ONE based on where you want the file to live:
**Option A — global artifact store** (standalone, shareable URL):
od_save_artifact {
identifier: "pricing-v1", # URL-safe slug, /^[a-z0-9-]+$/, 3–64 chars
title: "Pricing Page v1", # human-readable, 1–200 chars
html
}
→ returns saved path + URL under /app/.od/artifacts/<timestamp>-<identifier>/
**Option B — inside the project** (appears in od_get_project.files[], renders in daemon UI):
od_save_project_file {
projectId, # the project you created in step 1
name: "index.html", # no path separators, 1–255 chars
content: html # max ~5 MB
}
→ file shows up in the project's viewer at /api/projects/<id>/files/<name>
Why lint before save: Saving bad HTML costs nothing technically, but linting catches malformed <head> or missing <!doctype> before you tell the user "done" — much better UX than silently shipping broken artifacts.
od_save_artifact vs od_save_project_file: Different storage scopes, not interchangeable. od_save_artifact writes to the daemon's global store (project-unaware) and is right when you want a standalone shareable URL. od_save_project_file writes inside a project's directory so it appears in od_get_project.files[] and renders under the project's UI. Use the project-scoped one when the design is meant to live with the project.
Streaming progress: od_generate_design emits MCP progress notifications every ~25 events. If you're driving from an LLM that exposes those, surface them to the user — generation can take a full minute and silent waits feel broken. See references/byok-providers.md for timeout tuning.
od_get_project {id} # find existing artifact slug
→ read current html via the artifact list
od_generate_design { # pass a refinement prompt
projectId,
prompt: "Fix the broken nav: it should be sticky and use the project's brand colors",
kind: "prototype"
}
→ returns new html
od_lint_artifact { html }
# Save with the SAME identifier (od_save_artifact) or SAME name (od_save_project_file)
# as last time — both are upsert / last-writer-wins on their respective key.
od_save_artifact { identifier: "pricing-v1", title: "Pricing Page v1", html }
# OR
od_save_project_file { projectId, name: "index.html", content: html }
od_save_artifact is upsert-by-identifier — same identifier overwrites (with a fresh <timestamp>-<identifier> directory). od_save_project_file is upsert-by-name within the project — same name overwrites in place.
See references/workflows.md for fully worked examples with sample tool args.
These all look reasonable and waste real time. Avoid them.
| Don't | Why | Do instead |
|---|---|---|
| Set BYOK_API_KEY in committed config or .env checked into git | Secrets leak. The proxy URL also identifies your provider account. | Export in shell session only, or use a secret manager. The .gitignore doesn't catch every variant of .env. |
| Call od_generate_design before checking OD_DAEMON_URL reaches the daemon | Generation fails 30s in with a confusing error after streaming has already started. | od_list_projects first — it's a 50ms smoke test. |
| Pick auth mode manually when you don't know the daemon's setup | Mode-aware 401 hints will tell you. | Leave OD_AUTH_MODE unset — src/config.ts infers from which creds you set. Only override when inference is wrong. |
| Skip od_lint_artifact because "the LLM produced HTML so it must be valid" | LLM output frequently misses <!doctype>, has unclosed tags, or wraps the doc in markdown fences. | Always lint before save. Two extra seconds, prevents broken artifacts. |
| Use od_delete_project to "clean up test data" without confirming | Daemon removes DB row AND filesystem dir. No undo. | Always show the user the project name + id and ask "delete this permanently? (y/n)" before calling. |
| Pass a huge PRD as prompt and hope for the best | Generation is single-turn, no conversation memory. Long prompts get truncated or produce muddled output. | Set persistent design preferences via od_update_project { customInstructions }, then send focused page-specific prompts. |
| Ignore OD_API_TOKEN errors on hosted OD | Hosted OD almost always sits behind nginx basic auth — OD_API_TOKEN (bearer) is the wrong mode. | Use OD_AUTH_MODE=basic + OD_BASIC_USER + OD_BASIC_PASS. See references/environment-setup.md. |
| Treat od_generate_design streaming output as "almost done" | The HTTP request stays open the whole time — abort kills the generation. | Wait for the tool result. Don't issue a follow-up tool call until od_generate_design returns. |
| Ask the user "what's your OD_DAEMON_URL?" before trying anything | The user already configured env vars in their MCP client's env block — re-asking is friction. | Just call the tool. The error message will tell you exactly what's missing (OD_DAEMON_URL errors fail at server startup, not at call-time). |
| Try to point a single tool call at a different daemon ("just this one, hit the hosted URL") | OD_DAEMON_URL is read once at server startup from the MCP client's env block (#49). There is no per-call override and no tool accepts a daemonUrl arg. Trying to override mid-session wastes time. | Register two MCP server entries in ~/.config/opencode/opencode.json (or your client's equivalent) — e.g. open-design-local (env → http://ai-open-design:7456) and open-design-hosted (env → https://od.thnkandgrow.com/ + basic auth). Pick which one to call from the tool name prefix. See references/environment-setup.md §"Running against multiple daemons". |
Minimal setup for local Docker OD (no auth):
export OD_DAEMON_URL="http://localhost:7456"
# That's it. od_list_projects works now.
Adding BYOK so od_generate_design works:
export BYOK_BASE_URL="https://api.openai.com/v1" # or your proxy
export BYOK_API_KEY="sk-..."
export BYOK_MODEL="gpt-4o-mini" # or "claude-sonnet-4-6", etc.
export BYOK_PROVIDER="openai" # default; one of: openai | anthropic | azure | google | ollama
Hosted OD behind basic auth:
export OD_DAEMON_URL="https://od.example.com"
export OD_AUTH_MODE="basic"
export OD_BASIC_USER="..."
export OD_BASIC_PASS="..."
# + BYOK_* as above for generation
Verification (does NOT need BYOK):
Call od_list_projects with no args.
→ If it returns projects (even empty array): daemon connection works.
→ If it returns 401: see references/errors.md
→ If it returns ECONNREFUSED: daemon isn't running at OD_DAEMON_URL.
README.md — human-facing tool list + installationdocs/architecture/generate-design-flow.md — deep technical reference (8-phase sequence diagram, system-prompt composition stack) for contributors. Surface to users only if they want internals.tools
Humanization layer for LLM conversation — makes the model sound and respond like a real, thoughtful, embodied human rather than an assistant or chatbot. Use whenever the reply will be read by a human and warmth, presence, or texture matter more than machine-readability. Triggers on any of: "human", "humans", "humanize", "humanization", "be human", "more human", "feel human", "people", "person", "real person", "real human", "friend", "friendly", "like a friend", "respond like a friend", "buddy", "talk", "talking", "talk to me", "talk like a person", "chat", "chatting", "conversation", "converse", "discuss", "discussion", "communication", "communicate", "listen", "just listen", "sit with me", "vent", "venting", "I just want to vent", "company", "presence", "stop being an AI", "stop sounding like a bot", "less corporate", "less robotic", "less formal", "warmer", "warm tone", "empathy", "empathetic", "comfort", "support me", "emotional support", "be honest with me", "be real with me", "real talk", "heart-to-heart", "deep conversation", "casual", "casual chat", "small talk", "chitchat", "say something", "tell me something", and on any emotional / relational / personal-decision / interpersonal context — grief, joy, anger, fear, shame, doubt, loneliness, dating, breakup, conflict, family, parents, sibling, friendship, marriage, divorce, in-laws, kids, parenting, work stress, burnout, career decision, quitting, firing, layoff, anxiety, depression, panic, sleep, dreams, identity, faith, doubt, meaning, mortality, celebration, milestone, achievement, gratitude, apology, forgiveness. Also loads when the user writes in non-English (any language) with emotional weight, when the user's message is shorter than 8 words and affect-laden, when the user types in lowercase fragments, when the user types in ALL CAPS with excitement, or when the user explicitly asks for a friend / mentor / older-sibling / wise-listener voice. Do NOT use for code generation, tool calls, structured data output, SQL, API contracts, or any task where machine-readability matters more than human warmth.
tools
Use this skill whenever a user wants the **full Open Design experience** — discovery questions asked first, brand-spec extraction from URLs/files, TodoWrite planning with live updates, 5-dimensional self-critique, polished artifact at the end. Trigger phrases include "design with questions first", "OD-style workflow", "full interactive design brief", "make me a complete landing page" (when the user wants quality over speed), "design my pitch deck", "brand-aware multi-page site", "follow the Open Design playbook", or any request where the user is starting a new design project rather than tweaking an existing artifact. Also trigger on any request that mentions wanting brand consistency across multiple pages or that provides a brand URL/spec. Pair with the `open-design-mcp` tool-reference skill — both loaded together give an LLM the full picture (this skill = workflow choreography; that skill = tool catalog + errors). This skill explicitly does NOT trigger for one-off tweaks ("make the nav stickier", "swap slide 3 image") — use od_generate_design directly for those.
development
Sync a locally-developed OpenCode skill to the skill-manager npm package and (if private) the private-skills GitHub repo. Handles per-skill version bumps, public/private classification, build verification, and conventional-commit-style git push. Auto-publish to npm is handled downstream by nano-step/shared-workflows@v1 when the push to master lands. Use this skill whenever the user says 'sync skill', 'publish skill', 'push skill to manager', '/sync-skill-to-manager <name>', or asks to release/distribute a skill they just edited.
testing
--- name: rri-t-testing description: RRI-T QA methodology skill. Execute 5-phase testing: PREPARE, DISCOVER, STRUCTURE, EXECUTE, ANALYZE. Use before release, creating test cases, QA review, or when asked to 'test this feature', 'create test cases for', 'run QA on', 'check coverage for', 'find edge cases in', or 'does this feature work correctly'. Covers 7 dimensions and 5 personas with Vietnamese-specific locale testing built in. --- # RRI-T Testing Skill Execute comprehensive QA testing using