oh-my-design-cli 0.1.3 → 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (77) hide show
  1. package/.claude/hooks/post-edit-watch.cjs +99 -0
  2. package/.claude/hooks/session-end-foldin.cjs +96 -0
  3. package/.claude/hooks/session-state-loader.cjs +64 -0
  4. package/.claude/hooks/skill-activation.cjs +75 -0
  5. package/.claude/settings.json +55 -0
  6. package/AGENTS.md +111 -0
  7. package/README.ja.md +1 -1
  8. package/README.ko.md +1 -1
  9. package/README.md +76 -203
  10. package/README.zh-TW.md +1 -1
  11. package/agents/AGENT.md +53 -0
  12. package/agents/omd-3d-blender.md +269 -0
  13. package/agents/omd-a11y-auditor.md +97 -0
  14. package/agents/omd-asset-curator.md +260 -0
  15. package/agents/omd-critic.md +181 -0
  16. package/agents/omd-master.md +548 -0
  17. package/agents/omd-microcopy.md +63 -0
  18. package/agents/omd-persona-tester.md +118 -0
  19. package/agents/omd-ui-junior.md +129 -0
  20. package/agents/omd-ux-engineer.md +265 -0
  21. package/agents/omd-ux-researcher.md +62 -0
  22. package/agents/omd-ux-writer.md +181 -0
  23. package/data/opt-out-corpus.json +141 -0
  24. package/data/reference-fingerprints.json +1495 -0
  25. package/dist/bin/oh-my-design.js +3 -818
  26. package/dist/bin/oh-my-design.js.map +1 -1
  27. package/dist/install-skills-GQPTQF5S.js +420 -0
  28. package/dist/install-skills-GQPTQF5S.js.map +1 -0
  29. package/package.json +22 -21
  30. package/scripts/context.cjs +91 -0
  31. package/scripts/postinstall.cjs +54 -0
  32. package/skills/omd-apply/SKILL.md +64 -53
  33. package/skills/omd-harness/SKILL.md +271 -0
  34. package/skills/omd-init/SKILL.md +1 -1
  35. package/skills/omd-learn/SKILL.md +56 -36
  36. package/skills/omd-remember/SKILL.md +94 -16
  37. package/skills/omd-sync/SKILL.md +141 -17
  38. package/dist/chunk-6YNSV3VY.js +0 -35
  39. package/dist/chunk-6YNSV3VY.js.map +0 -1
  40. package/dist/chunk-MHFYGZSO.js +0 -337
  41. package/dist/chunk-MHFYGZSO.js.map +0 -1
  42. package/dist/chunk-N2JG6N4Q.js +0 -264
  43. package/dist/chunk-N2JG6N4Q.js.map +0 -1
  44. package/dist/chunk-OOQQEUGX.js +0 -46
  45. package/dist/chunk-OOQQEUGX.js.map +0 -1
  46. package/dist/chunk-OR5DHENY.js +0 -250
  47. package/dist/chunk-OR5DHENY.js.map +0 -1
  48. package/dist/customizer-CM76752R.js +0 -8
  49. package/dist/customizer-CM76752R.js.map +0 -1
  50. package/dist/index.d.ts +0 -559
  51. package/dist/index.js +0 -3113
  52. package/dist/index.js.map +0 -1
  53. package/dist/init-UMM4XIV5.js +0 -675
  54. package/dist/init-UMM4XIV5.js.map +0 -1
  55. package/dist/install-skills-CM6VXFZJ.js +0 -152
  56. package/dist/install-skills-CM6VXFZJ.js.map +0 -1
  57. package/dist/learn-33LHKEJA.js +0 -140
  58. package/dist/learn-33LHKEJA.js.map +0 -1
  59. package/dist/reference-YMNAOXJQ.js +0 -47
  60. package/dist/reference-YMNAOXJQ.js.map +0 -1
  61. package/dist/reference-parser-TM3CJPNE.js +0 -10
  62. package/dist/reference-parser-TM3CJPNE.js.map +0 -1
  63. package/dist/remember-UAFA5B2O.js +0 -78
  64. package/dist/remember-UAFA5B2O.js.map +0 -1
  65. package/dist/sync-FDYRKNFE.js +0 -417
  66. package/dist/sync-FDYRKNFE.js.map +0 -1
  67. package/dist/templates/templates/design-md.hbs +0 -44
  68. package/dist/templates/templates/partials/agent-prompt-guide.hbs +0 -28
  69. package/dist/templates/templates/partials/color-palette.hbs +0 -49
  70. package/dist/templates/templates/partials/component-stylings.hbs +0 -28
  71. package/dist/templates/templates/partials/depth-elevation.hbs +0 -31
  72. package/dist/templates/templates/partials/dos-donts.hbs +0 -13
  73. package/dist/templates/templates/partials/layout.hbs +0 -30
  74. package/dist/templates/templates/partials/responsive.hbs +0 -25
  75. package/dist/templates/templates/partials/shadcn-tokens.hbs +0 -64
  76. package/dist/templates/templates/partials/typography.hbs +0 -43
  77. package/dist/templates/templates/partials/visual-theme.hbs +0 -26
package/package.json CHANGED
@@ -1,45 +1,48 @@
1
1
  {
2
2
  "name": "oh-my-design-cli",
3
- "version": "0.1.3",
4
- "description": "Interactive CLI to generate DESIGN.md files for AI coding agents",
3
+ "version": "1.0.1",
4
+ "description": "Bootstrap oh-my-design skills + agents into your project. After install, talk to your AI coding agent in natural language — no other CLI commands.",
5
5
  "type": "module",
6
6
  "bin": {
7
7
  "oh-my-design": "dist/bin/oh-my-design.js",
8
8
  "omd": "dist/bin/oh-my-design.js"
9
9
  },
10
- "main": "dist/index.js",
11
- "types": "dist/index.d.ts",
12
- "exports": {
13
- ".": {
14
- "import": "./dist/index.js",
15
- "types": "./dist/index.d.ts"
16
- }
17
- },
18
10
  "files": [
19
11
  "dist",
20
- "templates",
21
- "skills",
12
+ "skills/omd-apply",
13
+ "skills/omd-init",
14
+ "skills/omd-harness",
15
+ "skills/omd-learn",
16
+ "skills/omd-remember",
17
+ "skills/omd-sync",
18
+ "agents",
22
19
  "data",
23
- "references/**/DESIGN.md"
20
+ "references/**/DESIGN.md",
21
+ ".claude/hooks/*.cjs",
22
+ ".claude/settings.json",
23
+ "AGENTS.md",
24
+ "scripts/postinstall.cjs",
25
+ "scripts/context.cjs"
24
26
  ],
25
27
  "scripts": {
26
- "build": "tsup && cp -r src/templates dist/templates",
28
+ "build": "tsup",
27
29
  "dev": "tsup --watch",
28
30
  "start": "node dist/bin/oh-my-design.js",
29
31
  "test": "vitest run",
30
32
  "test:watch": "vitest",
31
33
  "lint": "tsc --noEmit",
32
34
  "prepare": "npm run build",
33
- "prepublishOnly": "npm run build"
35
+ "prepublishOnly": "npm run build",
36
+ "postinstall": "node scripts/postinstall.cjs"
34
37
  },
35
38
  "keywords": [
36
39
  "design-system",
37
40
  "design-md",
38
- "shadcn",
39
- "cli",
40
41
  "ai-agent",
42
+ "claude-code",
43
+ "codex",
44
+ "skills",
41
45
  "google-stitch",
42
- "design-tokens",
43
46
  "vibe-coding"
44
47
  ],
45
48
  "license": "MIT",
@@ -53,9 +56,7 @@
53
56
  "dependencies": {
54
57
  "@clack/prompts": "^0.9.1",
55
58
  "commander": "^13.1.0",
56
- "handlebars": "^4.7.8",
57
- "picocolors": "^1.1.1",
58
- "zod": "^3.24.2"
59
+ "picocolors": "^1.1.1"
59
60
  },
60
61
  "devDependencies": {
61
62
  "@types/node": "^22.13.10",
@@ -0,0 +1,91 @@
1
+ #!/usr/bin/env node
2
+ // scripts/context.cjs — minimal, deterministic project scan invoked by the
3
+ // omd-harness skill / omd-master agent when they want a fast .omd/context.json
4
+ // without doing a full Glob+Read pass in prose.
5
+ //
6
+ // Output: writes .omd/context.json with { kind, framework, css_files,
7
+ // package_name, deps_summary, ts }, and prints the path to stdout.
8
+ //
9
+ // Pure node — no deps. ~80 lines. Optional helper, not load-bearing: master
10
+ // can also just Glob+Read inline, but this preserves determinism for repeat
11
+ // scans across runs.
12
+
13
+ const fs = require('node:fs');
14
+ const path = require('node:path');
15
+
16
+ const cwd = process.argv[2] || process.cwd();
17
+ const out = path.join(cwd, '.omd', 'context.json');
18
+
19
+ function safeRead(p) {
20
+ try {
21
+ return fs.readFileSync(p, 'utf8');
22
+ } catch {
23
+ return null;
24
+ }
25
+ }
26
+
27
+ function listFiles(dir, exts, max = 50) {
28
+ const found = [];
29
+ function walk(d, depth) {
30
+ if (depth > 4 || found.length >= max) return;
31
+ let entries;
32
+ try {
33
+ entries = fs.readdirSync(d, { withFileTypes: true });
34
+ } catch {
35
+ return;
36
+ }
37
+ for (const e of entries) {
38
+ if (e.name.startsWith('.') || e.name === 'node_modules' || e.name === 'dist') continue;
39
+ const full = path.join(d, e.name);
40
+ if (e.isDirectory()) walk(full, depth + 1);
41
+ else if (exts.some((ext) => e.name.endsWith(ext))) {
42
+ found.push(path.relative(cwd, full));
43
+ if (found.length >= max) return;
44
+ }
45
+ }
46
+ }
47
+ walk(dir, 0);
48
+ return found;
49
+ }
50
+
51
+ const pkgRaw = safeRead(path.join(cwd, 'package.json'));
52
+ const pkg = pkgRaw ? JSON.parse(pkgRaw) : null;
53
+ const deps = pkg ? Object.assign({}, pkg.dependencies, pkg.devDependencies) : {};
54
+
55
+ let framework = 'unknown';
56
+ if (deps['next']) framework = 'next';
57
+ else if (deps['vite']) framework = 'vite';
58
+ else if (deps['react']) framework = 'react';
59
+ else if (deps['vue']) framework = 'vue';
60
+ else if (deps['svelte']) framework = 'svelte';
61
+ else if (deps['solid-js']) framework = 'solid';
62
+
63
+ let kind = 'unknown';
64
+ if (pkg) kind = 'node';
65
+ if (fs.existsSync(path.join(cwd, 'index.html')) && !pkg) kind = 'static-html';
66
+
67
+ const cssFiles = listFiles(cwd, ['.css', '.scss', '.sass'], 20);
68
+ const componentFiles = listFiles(cwd, ['.tsx', '.jsx', '.vue', '.svelte'], 30);
69
+
70
+ const ctx = {
71
+ kind,
72
+ framework,
73
+ package_name: pkg?.name ?? null,
74
+ deps_summary: {
75
+ has_tailwind: !!deps['tailwindcss'],
76
+ has_shadcn: !!deps['@shadcn/ui'] || !!deps['shadcn-ui'],
77
+ has_recharts: !!deps['recharts'],
78
+ has_chartjs: !!deps['chart.js'] || !!deps['chartjs'],
79
+ has_d3: !!deps['d3'],
80
+ has_lucide: !!deps['lucide-react'] || !!deps['lucide-vue'] || !!deps['lucide'],
81
+ has_heroicons: !!deps['@heroicons/react'] || !!deps['@heroicons/vue'],
82
+ has_framer_motion: !!deps['framer-motion'],
83
+ },
84
+ css_files: cssFiles,
85
+ component_files: componentFiles.slice(0, 10),
86
+ ts: new Date().toISOString(),
87
+ };
88
+
89
+ fs.mkdirSync(path.dirname(out), { recursive: true });
90
+ fs.writeFileSync(out, JSON.stringify(ctx, null, 2), 'utf8');
91
+ process.stdout.write(out + '\n');
@@ -0,0 +1,54 @@
1
+ #!/usr/bin/env node
2
+ // Friendly post-install nudge — only when the user explicitly installed
3
+ // oh-my-design-cli (global or as a top-level dependency).
4
+ //
5
+ // Suppressed when:
6
+ // - running inside CI
7
+ // - this package is being installed as a sub-dependency
8
+ // - npm is in production mode
9
+ //
10
+ // Plain CommonJS so it runs on any Node version without build deps.
11
+
12
+ 'use strict';
13
+
14
+ if (
15
+ process.env.CI ||
16
+ process.env.NODE_ENV === 'production' ||
17
+ // Sub-dep install: npm sets npm_command but no INIT_CWD pointing here
18
+ process.env.npm_config_global !== 'true' && !process.env.INIT_CWD
19
+ ) {
20
+ process.exit(0);
21
+ }
22
+
23
+ const c = {
24
+ bold: (s) => `\x1b[1m${s}\x1b[0m`,
25
+ cyan: (s) => `\x1b[36m${s}\x1b[0m`,
26
+ green: (s) => `\x1b[32m${s}\x1b[0m`,
27
+ dim: (s) => `\x1b[2m${s}\x1b[0m`,
28
+ };
29
+
30
+ const lines = [
31
+ '',
32
+ `${c.green('✓')} ${c.bold('oh-my-design installed.')} ${c.dim('(commands: omd, oh-my-design)')}`,
33
+ '',
34
+ ` ${c.bold('Next')} in any project:`,
35
+ '',
36
+ ` ${c.cyan('cd')} ${c.dim('<your project>')}`,
37
+ ` ${c.cyan('omd install-skills')} ${c.dim('# one time per project — installs the design harness')}`,
38
+ '',
39
+ ` ${c.bold('Then open Claude Code (or Codex). Just say what you want:')}`,
40
+ '',
41
+ ` ${c.dim('"토스 스타일 가족 식단 공유 앱 메인 화면 디자인해줘"')}`,
42
+ ` ${c.dim('"Linear-clone B2B SaaS dashboard 만들고 싶어"')}`,
43
+ ` ${c.dim('"이 카드 좀 더 세련되게"')}`,
44
+ '',
45
+ ` ${c.bold('하네스가 알아서 호출됨')} ${c.dim('— Claude Code hook이 디자인 요청 감지해서 자동 라우팅. 별도 슬래시 안 쳐도 됩니다.')}`,
46
+ '',
47
+ ` ${c.dim('Power user shortcut: ')} ${c.cyan('/omd-harness <task>')} ${c.dim('— hook 우회하고 즉시 진입.')}`,
48
+ '',
49
+ ` ${c.bold('⚠ Already running Claude Code?')} ${c.dim('Quit (Cmd+Q on macOS) and relaunch — subagents only load at session start.')}`,
50
+ '',
51
+ ];
52
+
53
+ console.log(lines.join('\n'));
54
+
@@ -1,85 +1,96 @@
1
1
  ---
2
2
  name: omd:apply
3
- description: "프로젝트 루트의 DESIGN.md를 UI/스타일링/마이크로카피/모션 작업의 authoritative brand context로 적용합니다. 컴포넌트 만들기, CSS 수정, 카피 작성, 애니메이션 튜닝, 디자인 시스템 질문에 트리거됩니다. 사용자 교정이 발생하면 자동으로 omd remember를 호출해 preference log에 기록합니다."
3
+ description: "프로젝트 DESIGN.md를 UI/시각 작업의 brand context로 적용. 컴포넌트·색상·폰트·레이아웃 수정 같은 구체적 요청과 톤·분위기 표현 KR '좀 따뜻하게', EN 'make it warmer/cooler', 日本語「もう少し暖かく」, 繁體中文「更溫暖一點」 — 모두에 트리거. DESIGN.md 부재 시 omd:init 우선. 화면 전체 신규 디자인은 omd:harness, 교정 기록은 omd:remember."
4
4
  ---
5
5
 
6
- # omd:apply — Brand Context Injection
6
+ # omd:apply — Brand Context Injection + Dispatch Router
7
7
 
8
- 프로젝트 루트의 `DESIGN.md`를 읽고, UI 관련 모든 작업의 authoritative brand context로 사용한다. 작업 도중 사용자가 디자인 선택을 교정하면 `.omd/preferences.md`에 자동 기록한다.
8
+ DESIGN.md 모든 UI/디자인 작업의 권위 있는 컨텍스트로 사용한다. 단일 책임은 가지:
9
+
10
+ 1. **인라인 처리** — 작은 단일 변경 (1 component, 1 token, 1 카피 라인)은 직접 Edit 툴로 처리
11
+ 2. **Dispatch** — 복합 작업은 적합한 서브에이전트로 즉시 라우팅 (master 거치지 않음)
12
+
13
+ 복합 작업을 인라인으로 처리하면 안 된다. 이 스킬의 가장 중요한 책임은 *언제 dispatch할지 정확히 판단하는 것*.
9
14
 
10
15
  ## 트리거 조건
11
16
 
12
17
  다음 중 하나가 감지되면 SKILL 전체를 로드한다.
13
- - 새 컴포넌트 생성 (button, card, dialog, nav, form 등)
14
- - 기존 컴포넌트 스타일 변경 (Tailwind 클래스, CSS, 토큰 값)
15
- - 마이크로카피 작성/수정 (버튼 라벨, empty state, 에러 메시지, tooltip)
16
- - 모션/트랜지션 추가
17
- - 색상·타이포그래피·스페이싱 조정
18
- - 디자인 시스템 관련 질문
19
-
20
- ## Phase 1 — DESIGN.md 로드
21
18
 
22
- 작업 시작 전:
19
+ - 컴포넌트 생성 / 수정 (button, card, dialog, nav, form 등)
20
+ - 스타일 변경 (Tailwind 클래스, CSS, 토큰 값)
21
+ - 마이크로카피 작성 / 수정 (버튼 라벨, empty state, 에러, tooltip)
22
+ - 모션 / 트랜지션 추가
23
+ - 색상 · 타이포그래피 · 스페이싱 조정
24
+ - 에셋 (아이콘, 차트, 일러스트, 3D 렌더) 요청
25
+ - 디자인 시스템 관련 질문
23
26
 
24
- 1. 프로젝트 루트의 `DESIGN.md`를 **전체 읽는다**. 요약하지 말고 실제 파일 내용을 Read 툴로 로드.
25
- 2. `.omd/preferences.md`가 있으면 함께 읽는다. `status: pending` 엔트리들은 아직 DESIGN.md에 반영 안 된 교정사항 — **이들을 DESIGN.md보다 우선** 적용한다.
26
- 3. Precedence 순서:
27
- ```
28
- .omd/preferences.md (pending) > DESIGN.md > framework defaults
29
- ```
27
+ ## Phase 0 Dispatch decision tree (가장 먼저)
30
28
 
31
- DESIGN.md가 없으면 사용자에게 알리고 `omd init` 제안. 임의 생성하지 것.
29
+ 작업 시작 전에 어떤 처리 경로인지 결정한다. 다음 표를 위에서부터 순차 매칭, 첫 번째 매칭 행으로 진행:
32
30
 
33
- ## Phase 2 Brand Context 적용
31
+ | 사용자 요청 패턴 | 처리 경로 | 이유 |
32
+ |---|---|---|
33
+ | "에셋 / 아이콘 / 일러스트 / 차트 / 사진 / 로고 / 그래프 / SVG 만들어" | dispatch `omd-asset-curator` | 매체 선택 + 스택 매칭이 전문 영역 |
34
+ | "3D / 렌더 / 블렌더 / 목업" 명시 | dispatch `omd-3d-blender` | Blender MCP 필요 |
35
+ | "메인 화면 / landing / 전체 디자인 / 처음부터 / 와이어프레임" | 사용자에게 `/omd-harness` 추천 | 10-phase 파이프라인이 적합 |
36
+ | "접근성 / a11y / 색약 / 키보드 네비" 감사 | dispatch `omd-a11y-auditor` | 전문 감사 |
37
+ | "마이크로카피만 다듬어 / 카피 톤 정리 / empty state 문구 전부" 복수 | dispatch `omd-microcopy` | voice 일관성 |
38
+ | "사용자 시나리오 / 페르소나 walk through / 4명 입장에서 검토" | dispatch `omd-persona-tester` | adversarial 4-페르소나 |
39
+ | "이 카피 좋은지 / hero 카피 약점 / 섹션별 카피 전문가 의견 / A/B 후보" | dispatch `omd-ux-writer` | UX writing 분석 + 대안 + 근거 |
40
+ | "이 인터랙션 / 모션 / 포커스 / 모바일 / 지각 성능 / 섹션별 UX 약점" | dispatch `omd-ux-engineer` | 코드 레벨 인터랙션 감사 + fix |
41
+ | "랜딩 / 메인 화면 / 페이지 *전체*를 전문가 의견으로 개선" | dispatch `omd-ux-writer` + `omd-ux-engineer` (병렬) | 두 트랙 동시 — writing + engineering |
42
+ | "이게 왜 안 좋은지 critique / postmortem / root cause" | dispatch `omd-critic` | 비판적 분석 |
43
+ | "DESIGN.md 만들어 / reference 골라 / 67개 중 추천" | dispatch `omd-init` skill (또는 omd-add-reference) | reference 매칭 |
44
+ | "preference 정리 / 누적된 교정 반영 / DESIGN.md 업데이트" | dispatch `omd-learn` skill | fold-in 로직 |
45
+ | "이 한 줄 / 이 컬러 / 이 spacing 좀" 단발 명확 | **인라인 처리** | 분명한 단일 변경 |
46
+ | 위 어디에도 안 맞는 자유로운 디자인 작업 | 인라인 처리 후 Phase 3 (교정 캡처) | 일반 케이스 |
34
47
 
35
- 작업 전체에서 다음 규칙 강제:
48
+ dispatch가 정해지면 즉시 Agent 툴 호출 (master 경유 X — 우리가 omd-apply로 트리거됐다는 건 master 컨텍스트 밖이라는 의미). 그 후 인라인 처리는 하지 않고, 서브에이전트가 반환한 결과를 사용자에게 정리만 해서 전달.
36
49
 
37
- - **Token 값은 DESIGN.md에서만 인용한다.** 임의 hex, 임의 spacing 값, 임의 radius 사용 금지.
38
- - **Voice 섹션을 마이크로카피에 적용한다.** 문장 길이, 어휘 register, 은유 밀도를 DESIGN.md의 Voice 섹션에 맞춘다.
39
- - **Component 섹션에 명시된 규칙을 따른다.** 해당 컴포넌트 섹션이 있으면 variant / state / sizes를 그대로 사용.
40
- - **없는 토큰을 지어내지 않는다.** DESIGN.md에 없는 스펙이 필요하면 사용자에게 "이건 DESIGN.md에 없는데, 어떻게 할까요?" 물어본다.
50
+ ## Phase 1 DESIGN.md 로드 (인라인 처리 분기 한정)
41
51
 
42
- ## Phase 3 교정 캡처 (Self-Report)
52
+ dispatch가 아니라 인라인 처리로 분기됐을 때만 진행:
43
53
 
44
- **이것이 omd:apply의 차별화 포인트다. 반드시 수행.**
54
+ 1. 프로젝트 루트의 `DESIGN.md`를 **전체 읽는다**. 요약 금지, Read 툴로 직접 로드.
55
+ 2. `.omd/preferences.md`가 있으면 같이 읽는다. `status: pending` 엔트리는 아직 DESIGN.md에 반영 안 된 교정 — DESIGN.md보다 **우선** 적용.
56
+ 3. 우선순위:
57
+ ```
58
+ .omd/preferences.md (pending) > DESIGN.md > framework defaults
59
+ ```
45
60
 
46
- 턴을 끝내기 전, 이번 턴에 다음 하나라도 발생했는지 확인한다:
61
+ DESIGN.md 없으면 사용자에게 알리고 omd:init 스킬 트리거. 임의 생성 금지.
47
62
 
48
- 1. 사용자가 당신의 디자인 선택을 명시적으로 교정 ("no, use X", "actually, Y", "don't use Z", "we never do W")
49
- 2. 사용자가 당신이 쓴 토큰/값을 revert하거나 다른 값으로 교체
50
- 3. 사용자가 "우리는 ~한다/하지 않는다" 형태의 디자인 원칙을 언급
63
+ ## Phase 2 Brand Context 적용
51
64
 
52
- 감지되면 종료 전에 **반드시** 다음 커맨드를 Bash 툴로 실행:
65
+ - 토큰 값은 DESIGN.md에서만 인용. 임의 hex / spacing / radius 금지.
66
+ - Voice 섹션을 마이크로카피에 적용. 문장 길이, 어휘 register, 은유 밀도 일치.
67
+ - Component 섹션 명시된 규칙 따름 (variant / state / sizes).
68
+ - 없는 토큰 지어내지 않음. 필요 시 사용자에게 "이건 DESIGN.md에 없는데, 어떻게 할까요?" 묻기.
53
69
 
54
- ```bash
55
- omd remember "<교정 내용을 한 문장으로 요약>" --context "<수정된 파일 경로 또는 사용자 발화 요약>"
56
- ```
70
+ ## Phase 3 — 교정 캡처
57
71
 
58
- `--agent` 플래그는 생략한다. CLI가 환경변수(`CLAUDECODE`, `CODEX_SESSION_ID`, `OPENCODE` 등)로 자동 감지한다. 명시 override가 필요한 경우만 `--agent <name>`.
72
+ 종료 전에 다음 하나가 있었는지 확인:
59
73
 
60
- 예시:
61
- - 사용자: "CTAs는 절대 uppercase 쓰지 마"
62
- `omd remember "CTA buttons must never use uppercase text"`
63
- - 사용자가 `bg-brand-600`을 `bg-brand-500`으로 직접 바꿈
64
- → `omd remember "primary CTA background should be brand-500, not brand-600" --context "src/components/Button.tsx"`
65
- - 사용자: "우리는 4pt grid가 아니라 8pt 써"
66
- → `omd remember "spacing scale uses 8pt base, not 4pt"`
74
+ 1. 사용자가 디자인 선택을 명시적 교정 ("no, use X", "actually, Y", "don't use Z", "we never do W")
75
+ 2. 사용자가 토큰/값을 revert 또는 교체
76
+ 3. 사용자가 "우리는 ~한다/하지 않는다" 형태 원칙 언급
67
77
 
68
- scope는 note 내용에서 자동 추론된다 (keyword-based). 명시적으로 override가 필요하면 `--scope <value>` 추가 (e.g. `components.button`, `color`, `spacing`, `typography`, `voice`, `motion`, `layout`, `visualTheme`).
78
+ 감지되면 **omd:remember 스킬을 트리거**한다 (CLI 호출 X `.omd/preferences.md`에 직접 append). 트리거 메서드: omd-remember SKILL.md의 Step 1-6 절차를 따라 Edit 툴로 파일 수정.
69
79
 
70
- ## Phase 4 — 확인 메시지 (간결)
80
+ ## Phase 4 — 확인 메시지
71
81
 
72
- 교정을 기록했을 때만 턴 끝에 한 줄로 알린다:
82
+ 교정 기록 턴 끝에 한 줄:
73
83
 
74
84
  ```
75
- 📝 Logged to .omd/preferences.md — run `omd learn` to review, `omd learn --apply` to fold into DESIGN.md.
85
+ Logged to .omd/preferences.md — say "preference 정리해줘" later to fold into DESIGN.md.
76
86
  ```
77
87
 
78
- 일반 작업에서는 이 메시지 불필요. 과하게 알리지 말 것.
88
+ 일반 작업에는 불필요. 과한 알림 금지.
79
89
 
80
- ## 금지 사항
90
+ ## 금지
81
91
 
82
- - DESIGN.md 없는데 임의로 생성하지 (사용자에게 `omd init` 제안).
83
- - preferences.md에 직접 쓰지 것. 항상 `omd remember` 커맨드를 경유.
84
- - 교정 감지 시 사용자에게 "기록할까요?" 묻지 말 것. 자동 기록 사후 한 줄 알림.
85
- - 같은 턴 내에서 같은 교정을 중복 기록하지 말 것.
92
+ - DESIGN.md 없는데 임의 생성 금지 (사용자에게 omd:init 제안)
93
+ - 복합 작업을 인라인으로 처리 금지 (Phase 0 dispatch table 따라 라우팅)
94
+ - 교정 감지 시 "기록할까요?" 묻지 말 자동 기록 + 한 줄 알림
95
+ - 같은 턴 같은 교정 중복 기록 금지
96
+ - CLI 호출 (`omd remember`, `omd learn` 등) 금지 — 1.0.0부터 모두 스킬 prose
@@ -0,0 +1,271 @@
1
+ ---
2
+ name: omd:harness
3
+ description: "화면 전체나 신규 surface를 처음부터 디자인할 때의 진입점 — Discovery→Wireframe→Components→Microcopy→Validation 파이프라인을 omd-master 오케스트레이터로 실행. '랜딩 처음부터', 'production-ready', 'wireframe to production', 「一からデザイン」, 「從頭設計」류의 요청에 트리거. 단일 컴포넌트 수정은 omd:apply."
4
+ ---
5
+
6
+ # omd:harness — Design Harness Entry
7
+
8
+ 이 스킬은 **omd-master 오케스트레이터**를 호출하는 단일 진입점이다. 본 스킬은 launcher + 사전체크 + run 디렉토리 부트스트랩 책임만 가지고, phase 로직은 `agents/omd-master.md`에 있다.
9
+
10
+ CLI 의존 없음. 모든 부트스트랩은 Bash + Write 툴로 직접 실행한다.
11
+
12
+ ## 트리거
13
+
14
+ - `/omd-harness <task>` 명시 호출
15
+ - 사용자가 자연어로 "디자인 하네스 / 시니어 디자이너처럼 / 알아서 디자인" 요청
16
+
17
+ ## Step 0 — task 추출
18
+
19
+ 슬래시에 task 같이 적었으면 (`/omd-harness 물 음용 유도 메인 화면`) 그 자연어 부분이 task. 빈 슬래시면 한 번 묻기:
20
+
21
+ ```
22
+ 어떤 디자인 작업을 진행할까요?
23
+ shape: "[도메인] + [톤/스타일] + [핵심 화면]" — 예: "토스 스타일 가족용 식단 앱 메인 화면"
24
+ ```
25
+
26
+ ## Step 1 — Subagent registration 사전체크 (CRITICAL)
27
+
28
+ `omd-master` subagent가 이 세션에 dispatch 가능한지 verify. Agent tool의 사용 가능 subagent 목록에 `omd-master`가 있으면 진행. 없으면:
29
+
30
+ ```
31
+ omd-master subagent가 이 세션에 등록되어 있지 않아요. Claude Code는 세션 시작 시점에만 .claude/agents/*.md를 로드합니다 — install-skills를 세션 띄운 후에 돌렸으면 이 케이스.
32
+
33
+ 해결 (가장 빠른 순서):
34
+ 1. 현재 세션에서 /agents 실행 — Claude Code가 .claude/agents/*.md 강제 재스캔. omd-* 8개가 목록에 나타나면 /omd-harness 재호출.
35
+ 2. 안 되면: Claude Code 앱 완전 종료 (Cmd+Q / 터미널 자체 quit) → 새 터미널 → claude 재실행 → /omd-harness <task> 재호출.
36
+ ```
37
+
38
+ ## Step 2 — Run 디렉토리 부트스트랩 (인라인 Bash)
39
+
40
+ 이전엔 `omd harness "<task>" --internal` CLI를 호출했지만 1.0.0부터는 스킬이 직접 한다. 결정론적 hard verify gate:
41
+
42
+ ### 2.1 기존 run 재사용 체크
43
+
44
+ ```bash
45
+ ls -t .omd/runs 2>/dev/null | head -1
46
+ ```
47
+
48
+ 출력 있으면 그 디렉토리의 `task.md`를 Read해서 사용자 task와 의미적으로 일치하는지 확인. 일치하면 그 run 재사용 — Step 3으로 점프.
49
+
50
+ ### 2.2 신규 run 부트스트랩
51
+
52
+ 다음을 **반드시 정확히 이 순서로** Bash 툴로 실행:
53
+
54
+ ```bash
55
+ # 2.2.1 — timestamp + slug 결정 (한국어 보존)
56
+ TS=$(node -e "console.log(new Date().toISOString().replace(/[:.]/g,'-'))")
57
+ SLUG=$(node -e "
58
+ const s = process.argv[1].toLowerCase().trim()
59
+ .replace(/[^a-z0-9가-힣\s-]+/g,'')
60
+ .replace(/\s+/g,'-')
61
+ .replace(/-+/g,'-')
62
+ .replace(/^-|-$/g,'');
63
+ console.log(s.slice(0,40) || 'untitled');
64
+ " "<EXTRACTED_TASK>")
65
+ RUN_ID="run-${TS}-${SLUG}"
66
+ RUN_DIR=".omd/runs/${RUN_ID}"
67
+
68
+ # 2.2.2 — 표준 서브폴더 생성
69
+ mkdir -p "${RUN_DIR}"/{wireframes,components,assets/briefs,assets/fallback,assets/pinterest-refs,eval/screenshots,persona-feedback,handoff,checkpoints}
70
+
71
+ # 2.2.3 — task.md
72
+ cat > "${RUN_DIR}/task.md" <<EOF
73
+ # Harness Task
74
+
75
+ <EXTRACTED_TASK>
76
+
77
+ ---
78
+
79
+ - run_id: \`${RUN_ID}\`
80
+ - started_at: $(date -u +%Y-%m-%dT%H:%M:%SZ)
81
+ - cwd: \`$(pwd)\`
82
+ EOF
83
+
84
+ # 2.2.4 — run.log
85
+ echo "[$(date -u +%Y-%m-%dT%H:%M:%SZ)] run initialized" > "${RUN_DIR}/run.log"
86
+
87
+ # 2.2.5 — .omd/.gitignore (idempotent)
88
+ mkdir -p .omd
89
+ [ -f .omd/.gitignore ] || printf "runs/\ncache/\n" > .omd/.gitignore
90
+
91
+ # 2.2.6 — INDEX.md (idempotent header + append)
92
+ INDEX=".omd/runs/INDEX.md"
93
+ [ -f "${INDEX}" ] || cat > "${INDEX}" <<EOF
94
+ # Harness Runs Index
95
+
96
+ One line per run. Append-only.
97
+
98
+ EOF
99
+ TASK_ONELINE=$(echo "<EXTRACTED_TASK>" | tr '\n' ' ' | cut -c1-120)
100
+ echo "- $(date -u +%Y-%m-%dT%H:%M:%SZ) \`${RUN_ID}\` — ${TASK_ONELINE}" >> "${INDEX}"
101
+
102
+ # 2.2.7 — 결과 출력 (이 스킬이 파싱)
103
+ echo "RUN_DIR=${RUN_DIR}"
104
+ echo "RUN_ID=${RUN_ID}"
105
+ ```
106
+
107
+ ### 2.3 Hard verify gate (master spawn 차단 조건)
108
+
109
+ 부트스트랩 다음, master spawn 전에 반드시:
110
+
111
+ ```bash
112
+ test -d "${RUN_DIR}" && test -f "${RUN_DIR}/task.md" && echo "OK" || echo "FAIL"
113
+ ```
114
+
115
+ `OK`가 출력되지 않으면 master는 절대 spawn하지 않는다. 사용자에게:
116
+
117
+ ```
118
+ 하네스 부트스트랩이 실패했어요 (run dir or task.md 누락). 디스크 권한·경로 문제일 수 있어요. 다시 시도하거나 .omd/ 디렉토리를 정리해주세요.
119
+ ```
120
+
121
+ 이 gate를 통과해야만 Step 3로.
122
+
123
+ ## Step 3 — DESIGN.md 존재 확인 + reference 의미 매칭
124
+
125
+ 프로젝트 루트에 DESIGN.md 없으면 reference를 직접 추천한다. 외부 API 호출 없음.
126
+
127
+ ### 3.1 카탈로그 로드
128
+
129
+ 다음 파일을 Read 툴로 전체 로드:
130
+
131
+ - `.claude/data/reference-fingerprints.json` — 67개 reference의 fingerprint (tone keywords, visual theme, antipatterns, signature motion, has_personas, category)
132
+ - `.claude/data/reference-tags.md` — 사람-읽기용 keyword 매트릭스
133
+ - `.claude/data/vocabulary.json` — controlled vocab
134
+
135
+ `.claude/data/`에 없으면 `node_modules/oh-my-design-cli/data/` 또는 패키지 root `data/` 에서 fallback.
136
+
137
+ ### 3.2 사용자 task 분석 (silent)
138
+
139
+ - controlled-vocab 키워드 추출 (예: "헬스/웰니스 / calm-blue / 차분" → `[calm, minimal, approachable, warm]`)
140
+ - 명시 brand hint (예: "토스 같은" → `["toss"]`)
141
+ - 카테고리 추측 (Consumer / Productivity / Fintech / AI / Developer Tools / Design Tools / Automotive / Aerospace / SaaS / Enterprise)
142
+
143
+ ### 3.3 점수 계산 (in-head, 결정론적)
144
+
145
+ - 각 ref의 `tone_keywords` ∩ task keywords → 1점/매칭
146
+ - brand hint match → +5점
147
+ - 카테고리 일치 → +1점
148
+ - top 5 정렬
149
+
150
+ ### 3.4 검증 (hallucination 방지)
151
+
152
+ 추천하는 모든 id는 `reference-fingerprints.json`의 `items[].id`에 **반드시** 존재해야 한다. 없는 id는 만들어내지 않는다.
153
+
154
+ ### 3.5 사용자에게 제시 (자연어 prose)
155
+
156
+ 라벨 없이, 추천을 statement로:
157
+
158
+ ```
159
+ DESIGN.md가 없어서 reference 한 개를 골라 부트스트랩할게요. <task 핵심 한 줄>을 보니 <top1.id>가 가장 잘 맞을 것 같아요 — <visual_theme 핵심 + 매칭 키워드 1-2개를 한 줄로>.
160
+
161
+ 이대로 가시려면 go (또는 <top1.id>).
162
+ 다른 후보: <top2.id> (한 줄 이유) · <top3.id> (...) · <top4.id> (...) · <top5.id> (...)
163
+ 본인이 아는 다른 reference면 한 줄로 id만 (예: vercel) — 67개 카탈로그에 없으면 알려드립니다.
164
+ ```
165
+
166
+ ### 3.6 사용자 응답 처리
167
+
168
+ - `go` 또는 reference id (top-5 안) → 그 id로 master spawn
169
+ - 다른 reference id (top-5 밖이지만 카탈로그 안) → 동일하게 진행
170
+ - 카탈로그에 없는 id → "해당 id는 67개 카탈로그에 없어요. top-5 중에서 골라주세요."
171
+ - `중단` → 종료
172
+
173
+ ## Step 4 — Master 호출 (handoff loop)
174
+
175
+ Subagent (master)는 AskUserQuestion 직접 호출 불가 (main-thread 전용). file-based handoff 패턴으로 돌린다.
176
+
177
+ ### 루프 의사코드
178
+
179
+ ```
180
+ spawn_count = 0
181
+ prompt = "<RUN_DIR + task + chosen_ref_id>. Phase 1부터 시작."
182
+
183
+ while spawn_count < 12 (safety cap):
184
+ result = Agent({
185
+ subagent_type: "omd-master",
186
+ description: "Run design harness round N",
187
+ prompt: prompt
188
+ })
189
+ spawn_count += 1
190
+
191
+ handoff_path = "<RUN_DIR>/.handoff.json"
192
+ if not exists(handoff_path):
193
+ relay result text to user; halt
194
+
195
+ handoff = JSON.parse(Read(handoff_path))
196
+
197
+ if handoff.user_prose:
198
+ print handoff.user_prose to user
199
+
200
+ if handoff.status == "done": halt
201
+ if handoff.status == "error": halt + show
202
+ if handoff.status == "ask_user":
203
+ questions = JSON.parse(Read(handoff.questions_file))
204
+ answers = AskUserQuestion({ questions: questions.questions })
205
+ answers_file = "<RUN_DIR>/checkpoints/<handoff.checkpoint_id>.answers.json"
206
+ Write(answers_file, JSON.stringify({checkpoint_id, answers}))
207
+ prompt = "continue checkpoint:" + handoff.checkpoint_id + " — answers at " + answers_file
208
+ ```
209
+
210
+ ### Safety cap
211
+
212
+ 한 번의 `/omd-harness` 호출에 최대 12 spawn. 초과 시 사용자에게 escalate ("master가 12 spawn 초과, 멈춥니다 — run dir 보존").
213
+
214
+ ### 재진입
215
+
216
+ 사용자가 자연어로 "go" / "fix X" 답하면 동일 loop 재시작. master는 `.handoff.json` 보고 어디까지 갔는지 파악.
217
+
218
+ ## 사용자 체크포인트 처리
219
+
220
+ Master가 체크포인트에서 turn을 종료한 후 다음 사용자 메시지가:
221
+
222
+ - **하네스 컨텍스트 안의 응답** (예: "go", "fix the home screen IA", "stop") → master 재spawn + 그대로 전달
223
+ - **다른 작업으로 바뀐 메시지** → run 디렉토리에 `paused.flag` 생성. 나중에 `/omd-harness resume` 하면 재개
224
+
225
+ ## 산출물 위치 (master가 emit, 이 스킬은 안내만)
226
+
227
+ ```
228
+ .omd/runs/run-<ts>-<slug>/
229
+ ├── task.md
230
+ ├── brief.md
231
+ ├── references-cited.md
232
+ ├── journey.mmd
233
+ ├── wireframes/
234
+ ├── DESIGN.md.patch
235
+ ├── components/
236
+ │ ├── manifest.json
237
+ │ └── microcopy.json
238
+ ├── assets/
239
+ │ ├── brief.md
240
+ │ ├── manifest.json
241
+ │ ├── briefs/
242
+ │ ├── fallback/
243
+ │ └── pinterest-refs/
244
+ ├── eval/
245
+ │ ├── deterministic.json
246
+ │ ├── jury.json
247
+ │ └── screenshots/
248
+ ├── persona-feedback/
249
+ │ └── <persona>.json
250
+ ├── critique.md
251
+ ├── handoff/
252
+ │ ├── v0.zip
253
+ │ ├── cursor.zip
254
+ │ └── subframe.zip
255
+ ├── run.log
256
+ └── postmortem.md
257
+ ```
258
+
259
+ ## 이 스킬이 하지 않는 것
260
+
261
+ - Phase 로직 실행 (master)
262
+ - Sub-agent 직접 spawn (master)
263
+ - 사용자 응답 해석/라우팅 (master)
264
+ - DESIGN.md 직접 수정 (Phase 5에서 master)
265
+
266
+ ## 금지
267
+
268
+ - Master 없이 phase를 직접 수행하지 말 것
269
+ - 사용자 체크포인트를 자동 승인하지 말 것
270
+ - Run 디렉토리를 임의로 정리/삭제하지 말 것
271
+ - Step 2.3 verify gate 통과 전에 master spawn 절대 금지
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: omd:init
3
- description: "프로젝트 루트에 DESIGN.md를 생성합니다. 사용자가 프로젝트를 묘사하면 67개 레퍼런스 중 가장 맞는 것을 추천하고, 사용자가 고른 레퍼런스의 톤&매너를 preserve하면서 프로젝트 맥락 delta만 반영한 variation을 생성합니다. '디자인 시스템 만들어줘', 'DESIGN.md 세팅', 'brand 초기화', 'omd init' 같은 요청에 트리거됩니다. CLAUDE.md / AGENTS.md / Cursor rule shim도 함께 설치."
3
+ description: "프로젝트 루트에 DESIGN.md를 부트스트랩 67개 실제 기업 레퍼런스 중 컨텍스트 매칭으로 추천하고 선택된 레퍼런스의 톤&매너를 보존한 variation을 생성. DESIGN.md 부재 상태에서의 UI 작업 또는 '디자인 시스템 세팅', 'set up our design system', 「デザインシステムを作って」, 「建立設計系統」류의 요청에 트리거. CLAUDE.md / AGENTS.md / Cursor rule shim도 함께 설치."
4
4
  ---
5
5
 
6
6
  # omd:init — DESIGN.md Bootstrap