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
@@ -0,0 +1,99 @@
1
+ #!/usr/bin/env node
2
+ // PostToolUse hook — runs after Edit/Write on .tsx/.jsx/.css/.scss files.
3
+ // Detects if the change introduced a hex/spacing value that's NOT in
4
+ // DESIGN.md tokens, and surfaces a one-line suggestion to capture as preference.
5
+ //
6
+ // Hook input shape (Claude Code hook contract):
7
+ // stdin = JSON with toolName / args / etc.
8
+
9
+ 'use strict';
10
+
11
+ const fs = require('node:fs');
12
+ const path = require('node:path');
13
+
14
+ const projectDir = process.env.CLAUDE_PROJECT_DIR || process.cwd();
15
+ const designMd = path.join(projectDir, 'DESIGN.md');
16
+
17
+ let input = '';
18
+ process.stdin.setEncoding('utf8');
19
+ process.stdin.on('data', (c) => (input += c));
20
+ process.stdin.on('end', () => {
21
+ let payload = {};
22
+ try {
23
+ payload = JSON.parse(input || '{}');
24
+ } catch {
25
+ process.exit(0);
26
+ }
27
+ const toolName = payload.toolName || payload.tool_name || '';
28
+ if (!['Edit', 'Write', 'MultiEdit'].includes(toolName)) {
29
+ process.exit(0);
30
+ }
31
+ const filePath = payload.toolInput?.file_path || payload.toolInput?.filePath || '';
32
+ if (!/\.(tsx|jsx|ts|js|css|scss)$/i.test(filePath)) {
33
+ process.exit(0);
34
+ }
35
+
36
+ const newText =
37
+ payload.toolInput?.content ||
38
+ payload.toolInput?.new_string ||
39
+ '';
40
+ if (!newText) process.exit(0);
41
+
42
+ // Normalize a hex to canonical 6-char lowercase form (#abc → #aabbcc)
43
+ function normHex(h) {
44
+ let s = h.toLowerCase();
45
+ if (s.length === 4) {
46
+ // #abc → #aabbcc
47
+ s = '#' + s[1] + s[1] + s[2] + s[2] + s[3] + s[3];
48
+ } else if (s.length === 9) {
49
+ // #aarrggbb (8-char includes alpha) — strip alpha for comparison
50
+ s = s.slice(0, 7);
51
+ }
52
+ return s;
53
+ }
54
+
55
+ // Extract hexes from new content
56
+ const rawHexes = newText.match(/#[0-9a-f]{3,8}\b/gi) || [];
57
+ const hexes = [...new Set(rawHexes.map(normHex))];
58
+ if (hexes.length === 0) process.exit(0);
59
+
60
+ // Read DESIGN.md hexes — also handle CSS vars and oklch (Tailwind v4) by
61
+ // signaling N/A when DESIGN.md is purely token-driven (no inline hex).
62
+ let designHexes = new Set();
63
+ let designUsesTokenSystem = false;
64
+ if (fs.existsSync(designMd)) {
65
+ try {
66
+ const text = fs.readFileSync(designMd, 'utf8');
67
+ const lower = text.toLowerCase();
68
+ for (const h of (lower.match(/#[0-9a-f]{3,8}\b/g) || [])) {
69
+ designHexes.add(normHex(h));
70
+ }
71
+ // If DESIGN.md mostly uses oklch() / CSS vars / token names, hex-only
72
+ // comparison is unreliable — skip warning to avoid noise.
73
+ const hexCount = designHexes.size;
74
+ const oklchCount = (lower.match(/oklch\(/g) || []).length;
75
+ const cssVarCount = (lower.match(/var\(--/g) || []).length;
76
+ if ((oklchCount + cssVarCount) > hexCount * 2) {
77
+ designUsesTokenSystem = true;
78
+ }
79
+ } catch {
80
+ // ignore
81
+ }
82
+ }
83
+
84
+ if (designUsesTokenSystem) process.exit(0); // skip — too noisy
85
+ const introduced = hexes.filter((h) => !designHexes.has(h));
86
+ if (introduced.length === 0) process.exit(0);
87
+
88
+ const lines = [
89
+ '',
90
+ 'OMD WATCH:',
91
+ `방금 ${path.basename(filePath)} 에 DESIGN.md에 없는 색이 들어갔어요: ${introduced.slice(0, 3).join(', ')}`,
92
+ '의도된 거면 \`omd remember "<설명>" --context "' + filePath + '"\` 으로 preference 캡처 추천.',
93
+ '',
94
+ ];
95
+
96
+ // Hook contract: write to additionalContext via JSON stdout
97
+ process.stdout.write(JSON.stringify({ additionalContext: lines.join('\n') }));
98
+ });
99
+
@@ -0,0 +1,96 @@
1
+ #!/usr/bin/env node
2
+ // Stop hook — at session end, run fold-in algorithm on .omd/preferences.md.
3
+ // If proposals exceed threshold, append a note to .omd/timeline.md so the
4
+ // next SessionStart hook surfaces it as "fold-in proposals ready: N".
5
+
6
+ 'use strict';
7
+
8
+ const fs = require('node:fs');
9
+ const path = require('node:path');
10
+
11
+ const projectDir = process.env.CLAUDE_PROJECT_DIR || process.cwd();
12
+ const preferencesMd = path.join(projectDir, '.omd', 'preferences.md');
13
+ const timelineMd = path.join(projectDir, '.omd', 'timeline.md');
14
+ const configJson = path.join(projectDir, '.omd', 'config.json');
15
+
16
+ if (!fs.existsSync(preferencesMd)) process.exit(0);
17
+
18
+ let config = {
19
+ fold_in_score_threshold: 60,
20
+ recurrence_window_days: 7,
21
+ };
22
+ try {
23
+ if (fs.existsSync(configJson)) {
24
+ config = { ...config, ...JSON.parse(fs.readFileSync(configJson, 'utf8')) };
25
+ }
26
+ } catch {
27
+ // ignore
28
+ }
29
+
30
+ let prefText;
31
+ try {
32
+ prefText = fs.readFileSync(preferencesMd, 'utf8');
33
+ } catch {
34
+ process.exit(0);
35
+ }
36
+
37
+ // Parse pending entries (very rough)
38
+ const blocks = prefText.split(/^### /m).slice(1);
39
+ const now = Date.now();
40
+ const windowMs = config.recurrence_window_days * 24 * 3600 * 1000;
41
+ const byScope = new Map();
42
+
43
+ for (const block of blocks) {
44
+ const tsMatch = /^- ts:\s*(.+)$/m.exec(block);
45
+ const scopeMatch = /^- scope:\s*(.+)$/m.exec(block);
46
+ const statusMatch = /^- status:\s*(\w+)$/m.exec(block);
47
+ const importanceMatch = /^- importance:\s*([1-5])$/m.exec(block);
48
+ if ((statusMatch?.[1] || 'pending') !== 'pending') continue;
49
+ if (!tsMatch || !scopeMatch) continue;
50
+ const ts = new Date(tsMatch[1]).getTime();
51
+ if (Number.isNaN(ts) || now - ts > windowMs) continue;
52
+ const scope = scopeMatch[1];
53
+ const importance = parseInt(importanceMatch?.[1] || '3', 10);
54
+ const list = byScope.get(scope) || [];
55
+ list.push({ ts, importance });
56
+ byScope.set(scope, list);
57
+ }
58
+
59
+ const proposals = [];
60
+ for (const [scope, entries] of byScope.entries()) {
61
+ if (entries.length < 3) continue;
62
+ const importanceAvg = entries.reduce((s, e) => s + e.importance, 0) / entries.length;
63
+ // Hard floor matches src/core/memory.ts — keep these in sync.
64
+ if (importanceAvg < 2.5) continue;
65
+ const lastTs = entries.reduce((m, e) => Math.max(m, e.ts), 0);
66
+ const daysSince = (now - lastTs) / (24 * 3600 * 1000);
67
+ const recency = Math.exp(-daysSince / 7);
68
+ const score = entries.length * importanceAvg * recency * 10;
69
+ if (score >= config.fold_in_score_threshold) {
70
+ proposals.push({ scope, count: entries.length, score: Math.round(score) });
71
+ }
72
+ }
73
+
74
+ if (proposals.length === 0) process.exit(0);
75
+
76
+ // Append to timeline.md
77
+ const ts = new Date().toISOString();
78
+ const block =
79
+ `## ${ts} — fold_in_proposal\n\n` +
80
+ `${proposals.length} fold-in proposals ready (top: ${proposals[0].scope}, score ${proposals[0].score}).\n\n` +
81
+ '```json\n' +
82
+ JSON.stringify(proposals.slice(0, 5), null, 2) +
83
+ '\n```\n\n';
84
+
85
+ if (!fs.existsSync(path.dirname(timelineMd))) {
86
+ fs.mkdirSync(path.dirname(timelineMd), { recursive: true });
87
+ }
88
+ if (!fs.existsSync(timelineMd)) {
89
+ fs.writeFileSync(timelineMd, '# OMD TIMELINE — per-session journal\n\n' + block);
90
+ } else {
91
+ fs.appendFileSync(timelineMd, block);
92
+ }
93
+
94
+ // Optional: print one-line confirmation to stdout
95
+ process.stdout.write(JSON.stringify({}) || '');
96
+
@@ -0,0 +1,64 @@
1
+ #!/usr/bin/env node
2
+ // SessionStart hook — load .omd/state.md (and a recent timeline tail) into the
3
+ // session as additionalContext. If state.md is missing or stale, recompute
4
+ // best-effort from preferences.md + timeline.md.
5
+
6
+ 'use strict';
7
+
8
+ const fs = require('node:fs');
9
+ const path = require('node:path');
10
+
11
+ const projectDir = process.env.CLAUDE_PROJECT_DIR || process.cwd();
12
+ const stateMd = path.join(projectDir, '.omd', 'state.md');
13
+ const timelineMd = path.join(projectDir, '.omd', 'timeline.md');
14
+ const preferencesMd = path.join(projectDir, '.omd', 'preferences.md');
15
+
16
+ function safeRead(p) {
17
+ try {
18
+ return fs.readFileSync(p, 'utf8');
19
+ } catch {
20
+ return null;
21
+ }
22
+ }
23
+
24
+ const lines = [];
25
+
26
+ if (fs.existsSync(stateMd)) {
27
+ const content = safeRead(stateMd);
28
+ if (content) {
29
+ lines.push('## OMD ENVIRONMENT STATE');
30
+ lines.push('');
31
+ lines.push(content.split('\n').slice(0, 60).join('\n')); // cap injection size
32
+ lines.push('');
33
+ }
34
+ } else if (fs.existsSync(preferencesMd)) {
35
+ // Best-effort fallback — count pending entries
36
+ const text = safeRead(preferencesMd) || '';
37
+ const pendingCount = (text.match(/^- status:\s*pending\b/gm) || []).length;
38
+ if (pendingCount > 0) {
39
+ lines.push('## OMD ENVIRONMENT STATE');
40
+ lines.push('');
41
+ lines.push(`Pending preferences: ${pendingCount}${pendingCount >= 7 ? ' — consider /omd-learn review' : ''}`);
42
+ lines.push('');
43
+ }
44
+ }
45
+
46
+ if (fs.existsSync(timelineMd)) {
47
+ const text = safeRead(timelineMd) || '';
48
+ const blocks = text.split(/^## /m).slice(1).slice(-3);
49
+ if (blocks.length > 0) {
50
+ lines.push('## RECENT TIMELINE (last 3)');
51
+ lines.push('');
52
+ for (const b of blocks) {
53
+ const firstLine = b.split('\n')[0];
54
+ const summary = (b.split('\n').slice(2).find((l) => l.trim()) || '').trim();
55
+ lines.push(`- ${firstLine.trim()} — ${summary}`);
56
+ }
57
+ lines.push('');
58
+ }
59
+ }
60
+
61
+ if (lines.length > 0) {
62
+ process.stdout.write(JSON.stringify({ additionalContext: lines.join('\n') }));
63
+ }
64
+
@@ -0,0 +1,75 @@
1
+ #!/usr/bin/env node
2
+ // UserPromptSubmit hook — DESIGN.md existence gate.
3
+ //
4
+ // Scope (2026-05-07, simplified from the prior keyword/regex forced-eval
5
+ // system): the hook now does the one thing description-based skill
6
+ // triggering cannot do — file-system state checks. If the project has no
7
+ // DESIGN.md and the user is asking for UI/design work, we surface a
8
+ // single warning recommending omd:init first. Everything else (which
9
+ // skill to invoke, when, in what language) is handled by Claude reading
10
+ // each SKILL.md description, the standard Anthropic mechanism.
11
+ //
12
+ // What was removed:
13
+ // - .claude/skills/skill-rules.json (per-skill keyword/regex pools)
14
+ // - the "OMD SKILL ACTIVATION CHECK" forced-injection block
15
+ // - per-skill required/suggested classification
16
+ // All those overlapped with SKILL.md descriptions and created a
17
+ // dual-source-of-truth maintenance burden.
18
+ //
19
+ // What remains:
20
+ // - DESIGN.md existence check
21
+ // - a small inline UI-cue keyword set (KO/EN/JA/ZH-TW) so we only fire
22
+ // the warning when the prompt is actually about UI — otherwise a
23
+ // casual "what's 2+2" wouldn't get spammed with init reminders
24
+ //
25
+ // Plain CommonJS so it works on any Node ≥18 without build deps.
26
+
27
+ 'use strict';
28
+
29
+ const fs = require('node:fs');
30
+ const path = require('node:path');
31
+
32
+ const projectDir = process.env.CLAUDE_PROJECT_DIR || process.cwd();
33
+
34
+ // Inline UI cue list (gate scope only). Tiny on purpose — this is a
35
+ // "is the user asking for UI work?" sniff test, not a full taxonomy.
36
+ // If you find yourself wanting to add 50 entries here, that's a sign
37
+ // the description on the relevant SKILL.md should grow instead.
38
+ const UI_CUES = [
39
+ // Korean
40
+ '디자인', '레이아웃', '화면', '컴포넌트', '버튼', '카드', '색', '색상',
41
+ '폰트', '스타일', '브랜드', '리팩토링', '랜딩', '페이지',
42
+ // English
43
+ 'design', 'layout', 'component', 'button', 'card', 'color', 'colour',
44
+ 'font', 'style', 'brand', 'refactor', 'landing', 'redesign', 'rework',
45
+ // Japanese
46
+ 'デザイン', 'レイアウト', 'コンポーネント', 'ボタン', 'スタイル',
47
+ 'カラー', 'フォント', 'ブランド', 'ランディング',
48
+ // Traditional Chinese
49
+ '設計', '佈局', '元件', '按鈕', '風格', '顏色', '字體', '品牌', '落地頁',
50
+ ];
51
+
52
+ let prompt = '';
53
+ process.stdin.setEncoding('utf8');
54
+ process.stdin.on('data', (chunk) => (prompt += chunk));
55
+ process.stdin.on('end', () => {
56
+ const designMdPath = path.join(projectDir, 'DESIGN.md');
57
+ if (fs.existsSync(designMdPath)) process.exit(0);
58
+
59
+ const lower = prompt.toLowerCase();
60
+ const looksLikeUiWork = UI_CUES.some(
61
+ (k) => lower.includes(k.toLowerCase()) || prompt.includes(k),
62
+ );
63
+ if (!looksLikeUiWork) process.exit(0);
64
+
65
+ const lines = [
66
+ '',
67
+ 'OMD GATE',
68
+ '⚠️ DESIGN.md not found at project root.',
69
+ ' This prompt looks like UI / design work. Run the omd:init skill first',
70
+ ' to bootstrap DESIGN.md, then re-issue the request so it can be applied',
71
+ ' with brand context.',
72
+ '',
73
+ ];
74
+ process.stdout.write(JSON.stringify({ additionalContext: lines.join('\n') }));
75
+ });
@@ -0,0 +1,55 @@
1
+ {
2
+ "$schema": "https://json.schemastore.org/claude-code-settings.json",
3
+ "_doc": "OmD project hooks — auto-installed by `omd install-skills`. Re-run with --force to refresh.",
4
+ "hooks": {
5
+ "UserPromptSubmit": [
6
+ {
7
+ "matcher": "",
8
+ "hooks": [
9
+ {
10
+ "type": "command",
11
+ "command": "node ${CLAUDE_PROJECT_DIR}/.claude/hooks/skill-activation.cjs",
12
+ "timeout": 3000
13
+ }
14
+ ]
15
+ }
16
+ ],
17
+ "SessionStart": [
18
+ {
19
+ "matcher": "",
20
+ "hooks": [
21
+ {
22
+ "type": "command",
23
+ "command": "node ${CLAUDE_PROJECT_DIR}/.claude/hooks/session-state-loader.cjs",
24
+ "timeout": 3000
25
+ }
26
+ ]
27
+ }
28
+ ],
29
+ "PostToolUse": [
30
+ {
31
+ "matcher": "Edit|Write|MultiEdit",
32
+ "hooks": [
33
+ {
34
+ "type": "command",
35
+ "command": "node ${CLAUDE_PROJECT_DIR}/.claude/hooks/post-edit-watch.cjs",
36
+ "timeout": 2000
37
+ }
38
+ ]
39
+ }
40
+ ],
41
+ "Stop": [
42
+ {
43
+ "matcher": "",
44
+ "hooks": [
45
+ {
46
+ "type": "command",
47
+ "command": "node ${CLAUDE_PROJECT_DIR}/.claude/hooks/session-end-foldin.cjs",
48
+ "timeout": 5000
49
+ }
50
+ ]
51
+ }
52
+ ]
53
+ }
54
+ }
55
+
package/AGENTS.md ADDED
@@ -0,0 +1,111 @@
1
+ # AGENTS.md — oh-my-design
2
+
3
+ This is the agent-instruction shim for OpenAI Codex / generic AGENTS.md-aware CLIs working inside this repository.
4
+
5
+ oh-my-design itself uses Claude Code skills + subagents for its design harness. This file is the parity layer for Codex users.
6
+
7
+ ## Repository quick map
8
+
9
+ - `src/` — TypeScript source for the `omd` CLI (`bin/oh-my-design.ts` is the entrypoint).
10
+ - `references/` — 67 real-company DESIGN.md files used as bundled references.
11
+ - `skills/omd-*` — Claude Code / Codex / OpenCode skill files (installed into target projects via `omd install-skills`).
12
+ - `.claude/agents/` — Subagent definitions for the design harness (Claude Code).
13
+ - `.codex/agents/` — Mirror TOML definitions for the design harness (Codex).
14
+ - `spec/omd-v0.1.md` — OmD spec (15-section DESIGN.md format).
15
+ - `research/harness-design/` — Design harness research + integration design.
16
+ - `skills/omd-lab-02-design-harness/` — Lab #02 versioned harness experiments.
17
+
18
+ ## Build / test / lint
19
+
20
+ - Build: `npm run build` (tsup → `dist/`)
21
+ - Type-check: `npm run lint` (`tsc --noEmit`)
22
+ - Unit tests: `npm test` (vitest)
23
+ - The CLI runs via `node dist/bin/oh-my-design.js …` after build.
24
+
25
+ ## Design harness mode
26
+
27
+ User-facing entry: **`/omd-harness <task>`** in Claude Code or Codex CLI.
28
+
29
+ The harness runs entirely inside the host CLI session — no external API keys, no separate process. The skill at `.codex/skills/omd-harness/` (or `.claude/skills/omd-harness/` for Claude Code) handles bootstrapping and orchestration handoff.
30
+
31
+ ### Entrypoint
32
+
33
+ ```
34
+ /omd-harness <도메인 + 톤/스타일 + 핵심 화면>
35
+ ```
36
+
37
+ Examples:
38
+ - `/omd-harness 토스 스타일로 가족용 식단 공유 앱 메인 화면`
39
+ - `/omd-harness Linear-clone B2B SaaS dashboard — 6 widgets, dark first`
40
+ - `/omd-harness 결제 완료 화면 — 성공/실패/부분성공 3 states`
41
+
42
+ For Lab #02 versioned runs, append `--lab v1` (or v2, v3 …) inside the slash command.
43
+
44
+ The skill internally bootstraps the run dir via a hidden `omd harness` helper (slug consistency, standardized subdirs, INDEX.md append). This helper is NOT a user surface — always use `/omd-harness`.
45
+
46
+ ### Codex-specific harness flow
47
+
48
+ When this AGENTS.md is loaded and a fresh `.omd/runs/run-<latest>/` exists:
49
+
50
+ 1. **Activate the orchestrator persona.** Read `.codex/agents/omd-master.toml` and adopt that role. The full behavioral spec lives at `.claude/agents/omd-master.md` — follow it verbatim regardless of channel.
51
+
52
+ 2. **Run the 10 phases in order** (see `.claude/agents/omd-master.md` for full details):
53
+ - Phase 1 — Discovery (5-8 questions, one batch)
54
+ - Phase 1.5 — Asset Brief (spawn omd-asset-curator)
55
+ - Phase 2 — UX Research (parallel × 2-3 omd-ux-researcher)
56
+ - Phase 3 — IA / Journey (master itself) → **user checkpoint #1**
57
+ - Phase 4 — Wireframe (spawn omd-ui-junior)
58
+ - Phase 5 — System / DESIGN.md.patch (master + omd init prepare) → **user checkpoint #2**
59
+ - Phase 6 — Components (spawn omd-ui-junior)
60
+ - Phase 6.5 — Asset Sourcing (spawn omd-asset-curator)
61
+ - Phase 7 — Microcopy (spawn omd-microcopy)
62
+ - Phase 8 — Validation (spawn omd-a11y-auditor → cross-family jury → spawn omd-persona-tester × 4) → **user checkpoint #3**
63
+ - Iteration loop (cap 3) — spawn omd-critic between iterations
64
+ - Phase 9 — Handoff (zip packaging for v0/Cursor/Subframe)
65
+
66
+ 3. **Spawn sub-agents** via Codex's spawn-agent mechanism with names matching `.codex/agents/<name>.toml`:
67
+ - `omd-ux-researcher`
68
+ - `omd-asset-curator`
69
+ - `omd-ui-junior`
70
+ - `omd-microcopy`
71
+ - `omd-a11y-auditor`
72
+ - `omd-persona-tester` (×4 in parallel for Phase 8)
73
+ - `omd-critic` (iteration > 1)
74
+
75
+ 4. **All artifacts go inside the run dir.** Never write outside it except for `DESIGN.md` (Phase 5, with user checkpoint approval) and `.omd/preferences.md` (via `omd remember`).
76
+
77
+ ### User checkpoints (mandatory, do not auto-skip)
78
+
79
+ - Checkpoint #1 (Phase 3 end) — show `journey.mmd`, halt for user reply.
80
+ - Checkpoint #2 (Phase 5 end) — show `DESIGN.md.patch`, halt.
81
+ - Checkpoint #3 (Phase 8 end) — show validation summary, halt.
82
+
83
+ A non-mandatory informational checkpoint #0 follows Phase 1.5 (asset self/fallback/skip choice). All four are gated; do not bypass.
84
+
85
+ ## OmD apply (UI work outside the harness)
86
+
87
+ For ad-hoc UI work (component changes, microcopy edits, color tweaks) not running through the full harness:
88
+
89
+ 1. Read project-root `DESIGN.md` in full at the start of the turn.
90
+ 2. Read `.omd/preferences.md` `pending` entries — these override DESIGN.md until folded in.
91
+ 3. Apply changes citing only DESIGN.md tokens (never invent).
92
+ 4. If the user corrects your design choice, run `omd remember "<one-sentence summary>" --context "<file>"` before ending the turn.
93
+
94
+ This mirrors the `omd:apply` Claude Code skill behavior.
95
+
96
+ ## Hard rules (apply across channels)
97
+
98
+ - Never fabricate DESIGN.md §11-13 (Brand Narrative / Principles / Personas) facts. Use `[FILL IN]` placeholders if user-provided facts are absent.
99
+ - Never introduce a token absent from DESIGN.md without going through Phase 5 (system extension with checkpoint #2 approval).
100
+ - Never download from Pinterest. Pinterest URLs are listed for the user to download manually.
101
+ - Never emit SUS / NPS / "satisfaction score" from synthetic personas. Use task_success / steps_vs_optimal / friction_count / heuristic_violations / abandonment instead.
102
+ - Never auto-skip user checkpoints.
103
+ - Never delete a run directory. They are permanent learning artifacts.
104
+
105
+ ## Pre-existing OmD shims (managed by `omd sync`)
106
+
107
+ Below this line, `omd sync` may add a managed block with shim content for Claude Code / Cursor compat. Do not edit between the markers.
108
+
109
+ <!-- omd:start version=1 -->
110
+ <!-- omd:end -->
111
+
package/README.ja.md CHANGED
@@ -1,5 +1,5 @@
1
1
  <p align="center">
2
- <img src="logo-bg.png" width="480" alt="oh-my-design" />
2
+ <img src=".github/assets/logo-bg.png" width="480" alt="oh-my-design" />
3
3
  </p>
4
4
 
5
5
  <h1 align="center">oh-my-design</h1>
package/README.ko.md CHANGED
@@ -1,5 +1,5 @@
1
1
  <p align="center">
2
- <img src="logo-bg.png" width="480" alt="oh-my-design" />
2
+ <img src=".github/assets/logo-bg.png" width="480" alt="oh-my-design" />
3
3
  </p>
4
4
 
5
5
  <h1 align="center">oh-my-design</h1>