Design Workflow (moai-workflow-design)
Unified /moai design workflow skill. Handles two complementary responsibilities:
- Design artifact import — Path A (Claude Design handoff bundle, ZIP/HTML) and Path
B1 (Figma extractor via meta-harness). Produces DTCG-validated design tokens at
.moai/design/tokens.jsonforexpert-frontendconsumption. - Design-brief context loading — Auto-loads human-authored briefs from
.moai/design/(spec.md,system.md,research.md) into the orchestrator prompt beforeexpert-frontendormoai-domain-brand-designruns.
Brand context (.moai/project/brand/) is the constitutional parent across all paths — no
path may override brand constraints (design constitution §3.1, §3.3).
Quick Reference
Reserved output paths (design constitution §3.2, must not collide with human files):
tokens.json, components.json, assets/, import-warnings.json, brief/BRIEF-*.md,
copy.json, path-selection.json — all under .moai/design/.
Path selection (presented via AskUserQuestion when /moai design needs choice):
- Path A — Claude Design (권장) — handoff bundle (ZIP or HTML)
- Path B1 — Figma — meta-harness generates
moai-harness-figma-extractordynamically
Selection persisted to .moai/design/path-selection.json.
Context-loading priority order (REQ-2 / AC-4 from absorbed design-context skill):
spec > system > research. When token budget exceeded, drop in REVERSE priority — never
drop spec. Default token_budget: 20000 from design.yaml design_docs.token_budget.
Token estimation: estimated_tokens = ceiling(char_count / 4) * 1.10.
Implementation Guide
Part 1 — Path A: Claude Design Handoff Bundle
Supported formats (Phase 1):
ZIP— Claude Design export withmanifest.json,tokens.json,components/,assets/HTML— single-file Claude Design export
Unsupported (Phase 2 roadmap): DOCX, PPTX, PDF, Canva link — return
DESIGN_IMPORT_UNSUPPORTED_FORMAT and guide to Path B.
Version whitelist: Check manifest.json format_version against
supported_bundle_versions in .moai/config/sections/design.yaml. Current default: ["1.0"].
Mismatch → DESIGN_IMPORT_UNSUPPORTED_VERSION.
Parsing flow:
- Receive bundle file path from orchestrator
- Validate file existence →
DESIGN_IMPORT_NOT_FOUNDif missing - Validate format (extension + magic bytes:
PK\x03\x04for ZIP, DOCTYPE/<htmlfor HTML) - Security scan before extraction — list ZIP entries; reject executables (
.sh,.exe,.bat,.cmd,.ps1,.py,.rb,.pl), symlinks, path traversal (../,..\), absolute paths →DESIGN_IMPORT_SECURITY_REJECT - Read
manifest.json, validate version - Extract:
tokens.json→.moai/design/tokens.json;components/→components.json;assets/**→.moai/design/assets/;copy.json→.moai/design/copy.json - Validate token structure (required keys:
colors,typography,spacing); missing keys → warning, not failure - Report extraction results
Expected ZIP structure: manifest.json (format_version, claude_design_version,
created_at) + tokens.json (colors, typography, spacing, radii, shadows) + optional
components/ (HTML or JSON specs) + optional assets/ (images, fonts, icons) + optional
copy.json (structured copy).
Output token schema (normalized to MoAI): top-level keys colors, typography,
spacing, radii, shadows, plus source: "claude-design-bundle" and bundle_version.
Field normalization (silent rename, logged in import-warnings.json):
primary_color/brand_color → colors.primary; heading_font →
typography.fontFamily.heading; base_spacing → spacing.base.
Asset safety: Validate image MIME (png, jpg, gif, webp, svg, ico) and font formats (woff2, woff, ttf, otf). Reject nested ZIPs. Strip script tags from SVG metadata.
Part 2 — Path B1: Figma Extractor (Meta-Harness)
Prerequisite: the harness policy moai-meta-harness. Path B1 does NOT ship a
static Figma skill — it is generated dynamically. When user selects Path B1, invoke
moai-meta-harness to generate .claude/skills/harness-figma-extractor/SKILL.md
(project-scoped and user-owned via harness-* prefix — moai update never
overwrites). Meta-harness Phase 5 (Customization) collects via Socratic interview:
Figma file ID, page selectors mapping pages to token categories, credential reference
(env var name like FIGMA_TOKEN; value NEVER stored in skill file). Generated extractor
produces tokens.json + components.json at .moai/design/; DTCG validation runs before
expert-frontend consumption.
Part 3 — Design-Brief Context Loading
Auto-loads human-authored briefs during Phase B2.5 of /moai design when
design_docs.auto_load_on_design_command: true. Can also be invoked standalone with
explicit dir argument.
Configuration resolution: Read design_docs from .moai/config/sections/design.yaml.
If absent, use compiled-in defaults:
dir: .moai/designauto_load_on_design_command: truetoken_budget: 20000priority: [spec, system, research]
Log design_docs not configured — using defaults when key absent.
Bare-token → filename mapping:
spec→<dir>/spec.mdsystem→<dir>/system.mdresearch→<dir>/research.md
Steps:
- Directory check: Glob
<dir>/. Missing → emit header only and logdesign docs not initialized — run /moai init or SPEC-DESIGN-DOCS-001 to create. - Auto-load gate: From Phase B2.5, check
auto_load_on_design_command. False → skip. - Parallel Read: Issue all candidate file Reads in a single batched parallel tool-call set.
- Filter
_TBD_files: A file with only scaffold content (lines blank,_TBD_, headings without bodies, or<!--/>comments) is skipped. Logskip: <token> — _TBD_ only. - Token budget enforcement: Include in priority order until cumulative
estimated_tokenswould exceed budget. Overflow → drop lowest priority (researchfirst, thensystem; neverspec). Single file too large → truncate at nearest##/###boundary and append> truncated: <filename> at char_offset=N. - Build output block — first non-empty line MUST be exactly
## Design Context (from .moai/design/). For each file, prepend> source: .moai/design/<filename>then content (or truncated). - Warnings section (when unreadable files encountered): append
> warnings: [<token1> unreadable: <reason>, ...]after the content.
All-_TBD_ case: header-only output + log
design docs present but all are _TBD_ — no content loaded.
Error Codes (Path A)
DESIGN_IMPORT_NOT_FOUND— bundle path missing → guide to Path BDESIGN_IMPORT_UNSUPPORTED_FORMAT— non-ZIP/HTML → guide to Path BDESIGN_IMPORT_UNSUPPORTED_VERSION— version not in whitelist. Required stderr (all 3 lines mandatory):Detected bundle version: v<N>;Supported versions: <list from design.yaml>;Switch to path B: run /moai design and select 'Code-based brand design'.DESIGN_IMPORT_SECURITY_REJECT— executables/symlinks/traversal/absolute paths detected. List offending entries. Do NOT create.moai/design/directory.DESIGN_IMPORT_MISSING_MANIFEST— ZIP withoutmanifest.json→ guide to Path B
Fallback guidance appended to every error: instruct user to run /moai design and
select "Code-based brand design (moai-domain-brand-design)" after ensuring
.moai/project/brand/visual-identity.md is complete.
Partial Bundle Recovery
Valid bundle missing optional components → extract what's available, log warnings to
.moai/design/import-warnings.json, proceed with partial output. Never silent failure.
Works Well With
moai-domain-brand-design (Path B fallback / context consumer), moai-domain-design-handoff
(produces claude-design-handoff/ for Path A), moai-workflow-gan-loop (uses tokens +
context as baseline), moai-meta-harness (generates figma extractor for Path B1),
expert-frontend (primary consumer), .claude/rules/moai/design/constitution.md (brand
priority + reserved paths).
Common Rationalizations
- "Skip security scan for trusted bundles" — "trusted" is unverifiable. Scan every bundle, no exceptions.
- "Drop spec.md when budget tight" — spec.md is priority 1, never dropped. Drop research → system → escalate.
- "TBD files contain useful context" —
_TBD_means scaffold-only. Skip to avoid polluting the prompt. - "Path B1 needs a hardcoded Figma extractor" — Path B1 uses meta-harness generation. Static Figma skill prohibited.
- "Brand context is one input among many" — brand context is the constitutional parent; conflicts resolve in favor of brand.
Red Flags
- Bundle parse proceeds without security scan
- ZIP entries containing
../, symlinks, or executables accepted manifest.jsonversion validation bypassed- Design context block missing canonical header
## Design Context (from .moai/design/) spec.mddropped when budget exceeded (priority violation)- Figma API token value stored inside skill file (only env var name allowed)
- Output written outside
.moai/design/reserved path set
Verification
- Path A security scan rejects fixture with
..and symlinks - Path A produces
.moai/design/tokens.jsonwith normalized schema - Path B1 invocation triggers
moai-meta-harness(no static skill) - Context-load output starts with
## Design Context (from .moai/design/) - Budget truncation appends
> truncated: <filename> at char_offset=N - All-
_TBD_case emits header + log only - DTCG validation runs on Path A and Path B1 outputs
- the DTCG frozen-guard CI test references this skill name
REQ coverage: (internal provenance omitted)..003, (Path A); REQ-1..16 (context).