odd-studio 2.4.0 → 2.5.0

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.
package/bin/odd-studio.js CHANGED
@@ -41,8 +41,8 @@ program
41
41
  // ── init ──────────────────────────────────────────────────────────────────────
42
42
  program
43
43
  .command('init [project-name]')
44
- .description('Scaffold a new ODD project and install the /odd skill into Claude Code')
45
- .option('--skip-skill', 'Skip installing the /odd skill globally (advanced)')
44
+ .description('Scaffold a new ODD project and install /odd + excalidraw skills into Claude Code')
45
+ .option('--skip-skill', 'Skip installing the /odd and excalidraw skills globally (advanced)')
46
46
  .option('--skip-hooks', 'Skip installing safety hooks (not recommended)')
47
47
  .option('--yes', 'Accept all defaults without prompting')
48
48
  .action(async (projectName, options) => {
@@ -74,18 +74,24 @@ program
74
74
  process.exit(1);
75
75
  }
76
76
 
77
- // 2. Install /odd skill
77
+ // 2. Install /odd skill and excalidraw skill
78
78
  if (!options.skipSkill) {
79
- print.step(2, 5, 'Installing /odd skill into Claude Code...');
79
+ print.step(2, 5, 'Installing /odd skill and excalidraw skill into Claude Code...');
80
80
  const spinner2 = ora({ text: '', indent: 4 }).start();
81
81
  try {
82
- const result = await installSkill(PACKAGE_ROOT);
82
+ const { default: installExcalidraw } = await import('../scripts/install-excalidraw.js');
83
+ await Promise.all([
84
+ installSkill(PACKAGE_ROOT),
85
+ installExcalidraw(PACKAGE_ROOT)
86
+ ]);
83
87
  spinner2.stop();
84
- print.ok('Skill installed → ' + chalk.cyan(result.destination));
88
+ print.ok('/odd skill installed → ' + chalk.cyan('~/.claude/skills/odd/'));
89
+ print.ok('excalidraw skill installed → ' + chalk.cyan('~/.claude/skills/excalidraw/'));
85
90
  } catch (e) {
86
91
  spinner2.stop();
87
- print.warn('Could not install skill automatically: ' + e.message);
92
+ print.warn('Could not install skills automatically: ' + e.message);
88
93
  print.info('Manual install: copy ' + chalk.dim('skill/') + ' to ' + chalk.dim('~/.claude/skills/odd/'));
94
+ print.info('excalidraw skill: available via ' + chalk.dim('/excalidraw') + ' command in Claude Code');
89
95
  }
90
96
  } else {
91
97
  print.step(2, 5, 'Skipping skill install (--skip-skill)');
@@ -198,10 +204,11 @@ program
198
204
  // ── upgrade ───────────────────────────────────────────────────────────────────
199
205
  program
200
206
  .command('upgrade')
201
- .description('Upgrade the /odd skill and hooks to the latest version')
207
+ .description('Upgrade the /odd skill, excalidraw skill, and hooks to the latest version')
202
208
  .action(async () => {
203
209
  print.logo();
204
210
  const { default: installSkill } = await import('../scripts/install-skill.js');
211
+ const { default: installExcalidraw } = await import('../scripts/install-excalidraw.js');
205
212
  const { default: setupHooks } = await import('../scripts/setup-hooks.js');
206
213
 
207
214
  console.log(chalk.bold(' Upgrading ODD Studio...\n'));
@@ -214,6 +221,14 @@ program
214
221
  s1.fail('Skill update failed: ' + e.message);
215
222
  }
216
223
 
224
+ const s1b = ora({ text: 'Updating excalidraw skill...', indent: 4 }).start();
225
+ try {
226
+ await installExcalidraw(PACKAGE_ROOT, { force: true });
227
+ s1b.succeed('Excalidraw skill updated');
228
+ } catch (e) {
229
+ s1b.fail('Excalidraw skill update failed: ' + e.message);
230
+ }
231
+
217
232
  const s2 = ora({ text: 'Updating hooks...', indent: 4 }).start();
218
233
  try {
219
234
  await setupHooks(PACKAGE_ROOT, { force: true });
@@ -5,7 +5,10 @@
5
5
  # Blocks or warns on shell commands that could cause irreversible damage:
6
6
  # rm -rf, overwriting critical files, dropping databases, etc.
7
7
 
8
- COMMAND="${CLAUDE_TOOL_INPUT:-}"
8
+ INPUT=$(cat)
9
+ TOOL_NAME=$(echo "$INPUT" | jq -r '.tool_name // empty')
10
+ if [ "$TOOL_NAME" != "Bash" ]; then exit 0; fi
11
+ COMMAND=$(echo "$INPUT" | jq -r '.tool_input.command // empty')
9
12
 
10
13
  block() {
11
14
  echo "🛡️ ODD DESTRUCTIVE GUARD: $1" >&2
@@ -10,7 +10,10 @@
10
10
  # Exit 2 → block the command (Claude will not execute it)
11
11
  # Stderr → message shown to the user
12
12
 
13
- COMMAND="${CLAUDE_TOOL_INPUT:-}"
13
+ INPUT=$(cat)
14
+ TOOL_NAME=$(echo "$INPUT" | jq -r '.tool_name // empty')
15
+ if [ "$TOOL_NAME" != "Bash" ]; then exit 0; fi
16
+ COMMAND=$(echo "$INPUT" | jq -r '.tool_input.command // empty')
14
17
 
15
18
  # ── Helper ────────────────────────────────────────────────────────────────────
16
19
  block() {
@@ -5,7 +5,10 @@
5
5
  # Runs after a file is written. If the file is in docs/outcomes/ or docs/personas/,
6
6
  # checks for completeness. Provides coaching — does not block.
7
7
 
8
- FILE_PATH="${CLAUDE_TOOL_RESULT_FILE:-}"
8
+ INPUT=$(cat)
9
+ TOOL_NAME=$(echo "$INPUT" | jq -r '.tool_name // empty')
10
+ if [ "$TOOL_NAME" != "Write" ]; then exit 0; fi
11
+ FILE_PATH=$(echo "$INPUT" | jq -r '.tool_input.file_path // empty')
9
12
 
10
13
  # ── Only check ODD docs ───────────────────────────────────────────────────────
11
14
  if ! echo "$FILE_PATH" | grep -qE 'docs/(outcomes|personas)/'; then
@@ -5,7 +5,10 @@
5
5
  # Runs before npm run build, npm test, and deployment commands.
6
6
  # Checks that ODD project state is sane before the build proceeds.
7
7
 
8
- COMMAND="${CLAUDE_TOOL_INPUT:-}"
8
+ INPUT=$(cat)
9
+ TOOL_NAME=$(echo "$INPUT" | jq -r '.tool_name // empty')
10
+ if [ "$TOOL_NAME" != "Bash" ]; then exit 0; fi
11
+ COMMAND=$(echo "$INPUT" | jq -r '.tool_input.command // empty')
9
12
 
10
13
  # ── Only intercept build/deploy commands ─────────────────────────────────────
11
14
  if ! echo "$COMMAND" | grep -qE '(npm\s+run\s+(build|deploy|start:prod)|yarn\s+(build|deploy)|pnpm\s+(build|deploy))'; then
@@ -6,7 +6,10 @@
6
6
  # so that the next /odd session can resume from exactly this point.
7
7
  # Falls back to local .odd/state.json if ruflo is unavailable.
8
8
 
9
- COMMAND="${CLAUDE_TOOL_INPUT:-}"
9
+ INPUT=$(cat)
10
+ TOOL_NAME=$(echo "$INPUT" | jq -r '.tool_name // empty')
11
+ if [ "$TOOL_NAME" != "Bash" ]; then exit 0; fi
12
+ COMMAND=$(echo "$INPUT" | jq -r '.tool_input.command // empty')
10
13
 
11
14
  # ── Only trigger on git commit ────────────────────────────────────────────────
12
15
  if ! echo "$COMMAND" | grep -qE 'git\s+commit'; then
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "odd-studio",
3
- "version": "2.4.0",
3
+ "version": "2.5.0",
4
4
  "description": "Outcome-Driven Development for Claude Code — a planning and build harness for domain experts building serious software with AI.",
5
5
  "keywords": [
6
6
  "claude-code",
@@ -0,0 +1,180 @@
1
+ 'use strict';
2
+ import fs from 'fs-extra';
3
+ import path from 'path';
4
+ import os from 'os';
5
+ import { execSync } from 'child_process';
6
+
7
+ /**
8
+ * Installs the excalidraw skill into Claude Code.
9
+ *
10
+ * This creates a wrapper skill that calls the excalidraw system to generate wireframes.
11
+ * The skill is installed to ~/.claude/skills/excalidraw/
12
+ */
13
+ export default async function installExcalidraw(packageRoot, options = {}) {
14
+ const destination = path.join(os.homedir(), '.claude', 'skills', 'excalidraw');
15
+
16
+ // Ensure ~/.claude/skills/ exists
17
+ await fs.ensureDir(path.join(os.homedir(), '.claude', 'skills'));
18
+
19
+ // If destination exists and not forcing, back it up
20
+ if (fs.existsSync(destination) && !options.force) {
21
+ const backup = destination + '.backup-' + Date.now();
22
+ await fs.move(destination, backup);
23
+ }
24
+
25
+ // Create the excalidraw skill wrapper directory
26
+ await fs.ensureDir(destination);
27
+
28
+ // Create the SKILL.md manifest
29
+ const skillManifest = `---
30
+ name: excalidraw
31
+ description: Wireframe and diagram generation for UI/design planning
32
+ version: 1.0.0
33
+ author: ODD Studio
34
+ source: https://github.com/excalidraw/excalidraw
35
+ tags:
36
+ - ui-design
37
+ - wireframing
38
+ - planning
39
+ - visualization
40
+ ---
41
+
42
+ # Excalidraw Wireframe Generator
43
+
44
+ Generate interactive wireframes and diagrams for design planning, prototyping, and visual communication.
45
+
46
+ ## Installation
47
+
48
+ This skill is automatically installed by ODD Studio during project initialization.
49
+
50
+ ## Usage
51
+
52
+ Use the excalidraw skill to generate wireframes for design review:
53
+
54
+ \`\`\`
55
+ /excalidraw
56
+
57
+ Generate wireframes for [Design Approach Name] for our [project name] platform.
58
+
59
+ Context:
60
+ - Primary persona: [name], a [role]
61
+ - Key outcome: [outcome name] — [description]
62
+ - Approach philosophy: [design approach philosophy]
63
+ - Devices: [device types]
64
+ - Visual style: [style description]
65
+
66
+ Show:
67
+ 1. Desktop layout
68
+ 2. Mobile layout (if applicable)
69
+ 3. Key UI components
70
+ 4. Navigation pattern
71
+ \`\`\`
72
+
73
+ ## When to Use
74
+
75
+ - **Step 9b of Build Planning**: Generate wireframes for different design approach options
76
+ - **UI Design Review**: Create visual mockups for domain expert feedback
77
+ - **System Architecture Documentation**: Diagram system flows and component relationships
78
+ - **Accessibility Planning**: Sketch layouts with accessibility requirements in mind
79
+
80
+ ## Features
81
+
82
+ - Interactive canvas — edit and iterate on wireframes in real-time
83
+ - Infinite canvas — zoom and pan without limits
84
+ - Collaboration-ready — export diagrams for sharing with team members
85
+ - Library support — use common UI patterns and components
86
+ - Multiple export formats — PNG, SVG, JSON for further editing
87
+
88
+ ## Integration with ODD Studio
89
+
90
+ Excalidraw is deeply integrated into the ODD planning workflow:
91
+
92
+ 1. **Step 9 (Technical Architecture)**: Plan database and framework choices
93
+ 2. **Step 9b (UI & Design Decision)**: Generate 3-4 design approach wireframes using excalidraw
94
+ 3. **Step 10 (Session Brief)**: Include wireframe references in the build specification
95
+ 4. **Build Phase**: Build agents reference wireframes when implementing UI
96
+
97
+ ## Notes
98
+
99
+ - Wireframes generated in Step 9b are stored as \`.excalidraw\` files in \`docs/wireframes/\`
100
+ - Each design approach option gets its own wireframe file
101
+ - Domain expert selects preferred design from the wireframes
102
+ - Selected design is recorded in \`CLAUDE.md\` under \`Design Approach\`
103
+ `;
104
+
105
+ await fs.writeFile(path.join(destination, 'SKILL.md'), skillManifest);
106
+
107
+ // Create a README for setup instructions
108
+ const readmeContent = `# Excalidraw Skill for ODD Studio
109
+
110
+ This skill enables interactive wireframe and diagram generation within the ODD planning workflow.
111
+
112
+ ## What Is Excalidraw?
113
+
114
+ Excalidraw is a virtual whiteboard application for creating hand-drawn style diagrams, wireframes, and architectural sketches. It's simple, intuitive, and designed for collaborative design planning.
115
+
116
+ ## Auto-Installed Components
117
+
118
+ When you run \`npx odd-studio init\`, this skill is automatically installed with:
119
+
120
+ - Claude Code integration configuration
121
+ - ODD Studio-specific prompts and templates
122
+ - Wireframing guidelines for design approach decisions
123
+ - Export templates for Session Brief integration
124
+
125
+ ## Using Excalidraw in ODD Studio
126
+
127
+ ### Step 9b: Design Planning
128
+
129
+ When Rachel (the Build Planner) reaches Step 9b (UI & Design Decision), you'll generate wireframes for each design approach option:
130
+
131
+ \`\`\`
132
+ /excalidraw
133
+
134
+ Generate wireframes for [Design Approach] for [project name].
135
+
136
+ Context:
137
+ - Primary persona: [name]
138
+ - Key outcome: [outcome]
139
+ - Approach: [philosophy]
140
+ - Devices: [device types]
141
+
142
+ Show: Desktop layout, mobile (if applicable), key components, navigation
143
+ \`\`\`
144
+
145
+ ### Exporting Wireframes
146
+
147
+ Export each set of wireframes as:
148
+ - **Interactive .excalidraw file** — for iterating and refining
149
+ - **PNG image** — for sharing with domain expert
150
+ - **SVG vector** — for including in documentation
151
+
152
+ Save wireframes to \`docs/wireframes/[design-approach-name]/\`
153
+
154
+ ### In the Session Brief
155
+
156
+ Reference wireframes in the Session Brief under the UI section:
157
+
158
+ \`\`\`markdown
159
+ ## Design Approach
160
+
161
+ [Design approach name]
162
+
163
+ See wireframes at: docs/wireframes/[design-approach-name]/
164
+ \`\`\`
165
+
166
+ ## Browser-Based
167
+
168
+ Excalidraw works in any modern browser. If you have a local Excalidraw instance running, Claude Code will use it. Otherwise, the skill links to the official web version.
169
+
170
+ ## Documentation
171
+
172
+ - Official Excalidraw docs: https://excalidraw.com/
173
+ - Excalidraw GitHub: https://github.com/excalidraw/excalidraw
174
+ - ODD Studio integration guide: See \`SKILL.md\`
175
+ `;
176
+
177
+ await fs.writeFile(path.join(destination, 'README.md'), readmeContent);
178
+
179
+ return { destination };
180
+ }
@@ -17,11 +17,12 @@ const pkg = new URL('..', import.meta.url).pathname.replace(/\/$/, '');
17
17
 
18
18
  Promise.all([
19
19
  import('./install-skill.js').then(({ default: installSkill }) => installSkill(pkg)),
20
+ import('./install-excalidraw.js').then(({ default: installExcalidraw }) => installExcalidraw(pkg)),
20
21
  import('./setup-hooks.js').then(({ default: setupHooks }) => setupHooks(pkg)),
21
22
  import('./setup-mcp.js').then(({ default: setupMcp }) => setupMcp()),
22
23
  ])
23
24
  .then(() => {
24
- console.log('✓ ODD Studio: /odd skill, safety hooks, and ruflo memory installed into Claude Code');
25
+ console.log('✓ ODD Studio: /odd skill, excalidraw skill, safety hooks, and ruflo memory installed into Claude Code');
25
26
  console.log(' → Restart Claude Code now to activate ruflo memory and hooks.');
26
27
  console.log(' Run: npx odd-studio init [project-name] to scaffold your first project.');
27
28
  })
@@ -197,116 +197,288 @@ This is not a test. It is a check that the plan makes intuitive sense to the dom
197
197
 
198
198
  ---
199
199
 
200
- ## Step 9: Technical Architecture
200
+ ## Step 9: Technical Architecture — Collaborative Decision-Making
201
201
 
202
- The plan is structurally complete. Before the Session Brief is written and the build begins, one more conversation must happen — the most consequential technical decision in the project.
202
+ The plan is structurally complete. Before the Session Brief is written and the build begins, the most consequential technical decision in the project must happen — and you and the domain expert will make it together.
203
203
 
204
- Until now, every question you asked was a domain question. You were drawing out knowledge the domain expert already held. This step is different. You Rachel are now the expert. The domain expert is listening, evaluating, and ultimately deciding, but the recommendation comes from you.
204
+ This step is fundamentally different from the previous eight. Until now, you drew out knowledge the domain expert already held. Now you bring technical expertise to the table. But expertise does not mean autonomous decision-making. It means presenting options with clear trade-offs, then stepping back while the domain expert chooses.
205
205
 
206
- **Read the full specification before making any recommendation.**
206
+ **Phase 1: Research and Prepare**
207
207
 
208
- You already have the contract map. Now read everything else:
208
+ Read the full specification to understand the constraints:
209
209
  - Every persona: their context, technical confidence, devices, volume
210
210
  - Every walkthrough: load implications, real-time requirements, data complexity, integration needs
211
211
  - Every contract: data relationships, how deeply interconnected the outcomes are
212
212
  - The phase structure: scale and depth of what is being built
213
213
 
214
- Do not generate a generic recommendation. Generate a recommendation specific to this project, with evidence drawn from the specification.
214
+ **Phase 2: Identify Realistic Options**
215
215
 
216
- **Make a concrete recommendation not a list of options.**
216
+ Based on this project's specification, identify 3-4 realistic technology stacks. Do NOT include absurd alternatives that no reasonable person would suggest. Include only credible options that would work for this kind of project.
217
217
 
218
- Do not say "here are some technologies you might consider." Say "this is what I recommend, and here is why." Name specific tools. Justify each one using what the specification reveals.
218
+ For each option, identify:
219
+ - Core framework (Next.js, SvelteKit, Remix, Astro, etc.)
220
+ - Database (PostgreSQL + Drizzle, MongoDB, Supabase, etc.)
221
+ - Hosting (Vercel, AWS, self-hosted, etc.)
222
+ - Authentication method (Clerk, Auth0, NextAuth, etc.)
223
+ - Any specialized services (Stripe for payments, Resend for email, etc.)
219
224
 
220
- Structure the recommendation as follows:
225
+ **Phase 3: Create a Comparison Matrix**
226
+
227
+ Present the options side-by-side, with specific reasoning tied to THIS project:
228
+
229
+ ---
230
+
231
+ **Technical Stack Options for [project name]:**
232
+
233
+ | Component | Option A | Option B | Option C |
234
+ |-----------|----------|----------|----------|
235
+ | **Framework** | Next.js (App Router) | SvelteKit | Remix |
236
+ | **Database + ORM** | PostgreSQL + Drizzle | MongoDB | Supabase (PostgreSQL) |
237
+ | **Hosting** | Vercel | AWS Lambda | Self-hosted |
238
+ | **Testing** | Vitest | Jest | Vitest |
239
+ | **Best for** | [reason specific to spec] | [reason specific to spec] | [reason specific to spec] |
240
+ | **Trade-off** | [specific cost] | [specific cost] | [specific cost] |
241
+
242
+ **Detailed reasoning for each option:**
243
+
244
+ **Option A — [name]**
245
+ - Why it fits: [specific evidence from your specification: personas, walkthroughs, contracts]
246
+ - What it handles well: [capabilities aligned to your outcomes]
247
+ - Trade-off: [what you give up — complexity, cost, learning curve, etc.]
248
+ - Example from your spec: [concrete reference to a outcome or persona that this solves for]
249
+
250
+ **Option B — [name]**
251
+ - Why it fits: [specific evidence from your specification]
252
+ - What it handles well: [capabilities]
253
+ - Trade-off: [what you give up]
254
+ - Example from your spec: [concrete reference]
255
+
256
+ **Option C — [name]**
257
+ - Why it fits: [specific evidence from your specification]
258
+ - What it handles well: [capabilities]
259
+ - Trade-off: [what you give up]
260
+ - Example from your spec: [concrete reference]
221
261
 
222
262
  ---
223
263
 
224
- **My recommendation for [project name]:**
264
+ **Always include Drizzle and Vitest in every option.**
265
+
266
+ Regardless of the framework, database, or hosting choices, every stack includes:
267
+
268
+ **Drizzle ORM** — the database layer that keeps the AI honest.
269
+
270
+ "Drizzle is the tool that ensures the build agents always know the exact shape of your data. Every field, every type, every relationship lives in your codebase as versioned migrations. When something goes wrong, we can reverse the last change precisely — the same way git lets us reverse code changes. Without Drizzle, agents are guessing about your database. With it, they know."
271
+
272
+ **Vitest** — automated checks for invisible behaviours.
273
+
274
+ "Vitest runs the business rules and calculations you cannot verify by clicking — access control logic, pricing calculations, workflow state transitions. Every outcome built triggers Vitest automatically. If a rule breaks because of a change somewhere else, Vitest catches it before you reach the verification step."
275
+
276
+ **Phase 4: The Domain Expert Decides**
277
+
278
+ Present the matrix and ask directly:
279
+
280
+ "I have identified three realistic technical stacks for your project. Each solves different constraints from your specification. Review them: the trade-offs are real, not cosmetic. Which approach best matches your priorities?
281
+
282
+ Tell me:
283
+ - Which option resonates with you, and why?
284
+ - Are there constraints I do not know about — a team preference, a budget limit, a compliance requirement — that rules out any option?
285
+ - Do you have experience with any of these that would make you more confident with one option?"
225
286
 
226
- [Name the complete stack framework, database, hosting, any key third-party services such as payments, email, authentication]
287
+ **Do not recommend. Offer. Let the domain expert choose.**
227
288
 
228
- **Why this stack:**
289
+ Listen to their choice. If they choose one of the options as presented, move to Phase 5. If they raise a concern about an option, address it:
229
290
 
230
- For each component, give a specific reason tied to the specification. Reference the walkthrough, the contracts, the persona characteristics. For example:
291
+ - If the concern reveals a constraint you missed: "You are right I did not weight [constraint] heavily enough. Let me revise the options."
292
+ - If the concern is a misunderstanding: "I want to clarify — [component] in [Option X] actually handles [capability] this way, because of [specific feature]."
293
+ - If the concern reveals a preference: "I understand the preference for [alternative]. This choice carries a trade-off: [concrete consequence]. If you are comfortable with that, we proceed. If not, [other option] avoids it."
231
294
 
232
- - "Your data is deeply relational [Outcome A] produces a record that [Outcome B], [Outcome C], and [Outcome D] all consume, with different fields from each. A relational database handles this natively."
233
- - "Your [persona]'s walkthrough requires real-time availability counts — the number must update immediately when another user acts. This requires [specific approach]."
234
- - "You have [n] outcomes with payment flows. [Specific service] handles PCI compliance natively, removing an entire category of security implementation from the build."
295
+ The domain expert has the final say. They should make that decision with full information, not because they feel pressured.
296
+
297
+ **Phase 5: Record the Decision**
298
+
299
+ When the domain expert has chosen, record their decision in CLAUDE.md and project memory.
300
+
301
+ Append a technical decisions section to `CLAUDE.md`:
302
+
303
+ ```
304
+ ## Technical Stack
305
+
306
+ **Chosen stack:**
307
+ - Framework: [chosen]
308
+ - Database: [chosen]
309
+ - ORM: Drizzle
310
+ - Testing: Vitest
311
+ - Hosting: [chosen]
312
+ - [Other services]: [chosen]
313
+
314
+ **Reasoning (tied to specification):**
315
+ - [Component]: [why, with reference to specific outcome or persona]
316
+ - [Component]: [why, with reference to specific outcome or persona]
317
+ - Drizzle: type-safe database layer with versioned migrations — build agents always know the exact shape of the data and every change is tracked alongside code changes
318
+ - Vitest: automated testing for invisible business rules — catches regressions before verification
319
+
320
+ **Alternatives considered:**
321
+ - [Option X]: [why it did not fit — specific constraint from the specification]
322
+ - [Option Y]: [why it did not fit — specific constraint from the specification]
323
+
324
+ **Domain expert decision notes:**
325
+ [Any specific preferences, constraints, or reasoning the domain expert expressed]
326
+ ```
327
+
328
+ **Store the decision in ruflo memory.**
329
+
330
+ Call `mcp__ruflo__memory_store`:
331
+ - Key: `odd-tech-stack`
332
+ - Namespace: `odd-project`
333
+ - Value: the complete technical stack decision with reasoning tied to the specification
235
334
 
236
- **What I considered and rejected:**
335
+ **Update `.odd/state.json`:**
336
+ - Set `techStackDecided: true`
337
+ - Set `techStack` to the chosen stack description (e.g., "Next.js 16 + Neon PostgreSQL + Vercel + Clerk")
338
+ - Set `orm` to "Drizzle"
339
+ - Set `testingFramework` to "Vitest"
340
+ - Update `nextStep` to "Review UI and Design approach — type *build to continue"
237
341
 
238
- Name the alternatives that a reasonable person might suggest for this kind of project, and explain specifically why they do not fit this specification.
342
+ Confirm to the user: "Technical stack chosen and recorded. [Stack name] will be used for this project. Every build agent will read this before writing a line of code."
239
343
 
240
344
  ---
241
345
 
242
- **Always include in the recommendation: Drizzle and Vitest.**
346
+ ## Step 9b: UI & Design Decision — Collaborative Visual Planning
347
+
348
+ With the technical stack decided, the next decision shapes how your personas experience the system: the design approach, layout strategy, visual language, and component philosophy.
243
349
 
244
- Regardless of the other stack choices, these two tools are always part of every recommendation. Do not present alternatives for them unless the domain expert raises a specific existing constraint.
350
+ This step mirrors Step 9's collaborative structure you will identify design options, generate wireframes for visual review, and choose the approach that best serves your personas and your domain.
245
351
 
246
- **Drizzle ORM** always recommended as the database layer.
352
+ **Phase 1: Understand Design Context**
247
353
 
248
- Drizzle defines the database structure in the same language as the rest of the project. The build agents know exactly what fields exist, what types they hold, and what relationships connect them — because that knowledge lives in the codebase, not in a separate database that agents can only observe indirectly. Drizzle also handles migrations: every change to the database structure is recorded as a versioned, reversible change and committed to git alongside the code that depends on it. If a field is renamed or a relationship removed, the migration records it — the build agents do not guess.
354
+ Read the full specification to identify design constraints:
249
355
 
250
- Explain to the domain expert: "Drizzle is the tool that keeps the AI honest about your data. Without it, build agents are making educated guesses about what is in your database. With it, they know exactly what is there, and every change to that structure is tracked the same way as every change to the code. Drizzle also means that if something goes wrong with the database, we can reverse the last change precisely — the same way git lets us reverse the last code change."
356
+ - **Personas**: Who is using this? What is their technical confidence? Do they need minimal, focused interfaces or rich, data-dense dashboards?
357
+ - **Outcomes**: Which outcomes have screens the persona interacts with? What information must be present, and what can be secondary?
358
+ - **Devices**: Desktop, mobile, tablet, kiosk? Are there accessibility or compliance requirements?
359
+ - **Volume**: High-frequency routine use or occasional intensive sessions? Does interface consistency matter more than density?
360
+ - **Domain language**: Is this a specialized domain with particular conventions (e.g., clinical, financial, legal)? The UI should speak that language.
251
361
 
252
- **Vitest** always recommended as the testing framework.
362
+ **Phase 2: Identify Realistic Design Approaches**
253
363
 
254
- Every outcome has a verification checklist — steps the domain expert follows in the browser to confirm the outcome works. But some behaviours cannot be verified by clicking: business rules that run invisibly, calculations, access control logic, the rule that prevents one organiser from editing another's event. Vitest runs automated checks for these. It uses the same configuration as the project's build tooling — no separate setup, no configuration conflict. It runs tests in parallel and completes in seconds. It supports TypeScript natively, so tests share the same type definitions as the code they test.
364
+ Based on the specification, define 3-4 credible design strategies. Include:
255
365
 
256
- Explain to the domain expert: "Vitest runs the checks that you cannot run by clicking through the browser — the business rules and calculations that happen invisibly inside the system. Every time an outcome is built, Vitest runs these checks automatically. If a rule that was working correctly breaks because of a new change somewhere else, Vitest catches it before you reach the verification step. Think of it as a safety net underneath the verification you do yourself."
366
+ 1. **Minimalist + Dark (Recommended Default)**
367
+ - Dark background (slate/zinc), single accent colour, clear borders
368
+ - Single-column on mobile, grid on desktop
369
+ - Component library: shadcn/ui + Geist
370
+ - Philosophy: clarity through space and type
257
371
 
258
- **Invite genuine pushback.**
372
+ 2. **Dense Dashboard + Light**
373
+ - Light background, information-rich tables and charts
374
+ - Multi-column layouts designed for desktop-first use
375
+ - Keyboard shortcuts, advanced filters, inline editing
376
+ - Philosophy: power users who live in the interface
259
377
 
260
- After presenting the recommendation, explicitly invite the domain expert to challenge it:
378
+ 3. **Minimal + Accessible**
379
+ - WCAG AAA compliance (not just AA)
380
+ - High contrast, large touch targets, full keyboard navigation
381
+ - Screen-reader optimized semantic HTML
382
+ - Philosophy: inclusive design that serves all personas equally
261
383
 
262
- "That is my recommendation based on everything in your specification. I want you to push back if anything does not fit. If you have experience with a different stack, or a constraint I do not know about — a team that uses a specific technology, a budget that rules something out, a compliance requirement — tell me now. This decision is harder to change after the build starts than before."
384
+ 4. **Brand-Driven + Custom**
385
+ - Custom design system (if the domain demands visual distinction)
386
+ - Domain-specific visual language (e.g., clinical software → muted greens, financial → professional grays)
387
+ - Hand-crafted components specific to this domain
388
+ - Philosophy: interface as part of the brand experience
263
389
 
264
- **Respond to challenges with reasoning, not capitulation.**
390
+ Do NOT include absurd alternatives. Every option must be defensible based on your specification.
265
391
 
266
- If the domain expert suggests an alternative, engage with it seriously:
267
- - If the alternative is genuinely suitable: "You are right — [reason]. I had not weighted [factor] heavily enough. Let me revise the recommendation."
268
- - If the alternative creates a risk: "I understand the preference for [alternative]. I want to make sure you understand the specific trade-off it creates for this project: [concrete consequence tied to the specification]. If you are comfortable with that trade-off, we proceed with [alternative]. If not, [original recommendation] avoids it."
392
+ **Phase 3: Generate Wireframes with Excalidraw**
269
393
 
270
- Do not abandon a recommendation simply because the domain expert expresses a preference. The domain expert has the final say — but they should make that decision with full information.
394
+ For each design approach, use the excalidraw skill to generate wireframes showing:
271
395
 
272
- **Record the decision in CLAUDE.md.**
396
+ - One key outcome flow (the most important persona interaction)
397
+ - Layout: how information is organized, where navigation lives, how forms and data are presented
398
+ - Component style: buttons, inputs, cards, modals — representative of the chosen approach
399
+ - Mobile variant (if relevant to specification)
273
400
 
274
- When consensus is reached, append a technical decisions section to `CLAUDE.md`:
401
+ Call the excalidraw skill (via `/excalidraw` command) with a prompt like:
275
402
 
276
403
  ```
277
- ## Technical Stack
404
+ Generate wireframes for [Design Approach Name] for our [project name] platform.
405
+
406
+ Context:
407
+ - Primary persona: [name], a [role]
408
+ - Key outcome: [outcome name] — [one-sentence description of what they do]
409
+ - Approach philosophy: [brief description of this design approach]
410
+ - Devices: [desktop/mobile/both]
411
+ - Visual style: [dark/light, minimalist/dense, etc.]
412
+
413
+ Show:
414
+ 1. Desktop layout of the main interaction
415
+ 2. Mobile layout (if applicable)
416
+ 3. Key UI components (buttons, inputs, cards) in this style
417
+ 4. Navigation pattern
418
+
419
+ Keep wireframes simple — focus on layout and information hierarchy, not pixel-perfect design.
420
+ ```
421
+
422
+ The excalidraw skill will generate interactive wireframes you can review, iterate on, and export.
423
+
424
+ **Phase 4: The Domain Expert Reviews and Decides**
425
+
426
+ Present the wireframes side-by-side and ask:
427
+
428
+ "I have generated wireframes for four design approaches. Each matches a different priority from your specification:
429
+
430
+ - **Option A** prioritizes clarity and simplicity — perfect if your personas are occasional users or if the domain is already complex.
431
+ - **Option B** is information-dense — best if your personas spend hours in the system and need to see patterns and relationships at once.
432
+ - **Option C** emphasizes accessibility — ensures every persona, regardless of ability, can use the system equally.
433
+ - **Option D** is custom and domain-specific — creates a visual identity that positions your platform as specialized.
278
434
 
279
- Chosen stack: [list each component]
280
- ORM: Drizzle
281
- Testing: Vitest
435
+ Review the wireframes. Tell me:
436
+ - Which design approach feels most natural for how [persona name] would work?
437
+ - Are there any constraints I missed — device types, accessibility requirements, team design preferences?
438
+ - If you could describe the 'feel' of the interface in three words, what would they be?"
282
439
 
283
- Reasoning:
284
- - [Component]: [why, tied to the specification]
285
- - [Component]: [why, tied to the specification]
286
- - Drizzle: type-safe database layer with versioned migrations — build agents always know the exact shape of the data and every change is tracked
287
- - Vitest: fast, co-located testing with native TypeScript support — catches business rule regressions automatically before verification
440
+ **Do not push a recommendation. Let the domain expert choose based on the wireframes they see.**
288
441
 
289
- Considered and rejected:
290
- - [Alternative]: [why it does not fit this project]
442
+ **Phase 5: Record the Design Decision**
443
+
444
+ When the domain expert chooses, record the decision.
445
+
446
+ Append to `CLAUDE.md`:
291
447
 
292
- Domain expert constraints applied: [any preferences or constraints the domain expert specified, or "none"]
293
448
  ```
449
+ ## Design Approach
294
450
 
295
- **Store the decision in ruflo memory.**
451
+ **Chosen design approach:**
452
+ [Design approach name]
453
+
454
+ **Reasoning (tied to specification):**
455
+ - [Persona]: [why this design serves them, with specific reference to an outcome]
456
+ - [Persona]: [why this design serves them]
457
+ - Information architecture: [how the chosen approach organizes information for this domain]
458
+ - Component library: [shadcn/ui + custom theming OR domain-specific components]
459
+ - Accessibility: [WCAG AA / AAA / custom standards]
460
+
461
+ **Alternatives considered:**
462
+ - [Option X]: [why it did not fit — specific constraint from the specification]
463
+ - [Option Y]: [why it did not fit — specific constraint from the specification]
464
+
465
+ **Domain expert decision notes:**
466
+ [Any specific preferences, constraints, or reasoning the domain expert expressed]
467
+ ```
468
+
469
+ Store in ruflo memory:
296
470
 
297
471
  Call `mcp__ruflo__memory_store`:
298
- - Key: `odd-tech-stack`
472
+ - Key: `odd-design-approach`
299
473
  - Namespace: `odd-project`
300
- - Value: the complete technical stack decision including chosen tools, ORM, testing framework, reasoning, and rejected alternatives
474
+ - Value: the complete design decision with reasoning tied to the specification and wireframe references
301
475
 
302
- **Update `.odd/state.json`:**
303
- - Set `techStackDecided: true`
304
- - Set `techStack` to the chosen framework
305
- - Set `orm` to "Drizzle"
306
- - Set `testingFramework` to "Vitest"
307
- - Update `nextStep` to "Set up the project — type *build to scaffold the project and configure your services"
476
+ Update `.odd/state.json`:
477
+ - Set `designApproachDecided: true`
478
+ - Set `designApproach` to the chosen approach name
479
+ - Update `nextStep` to "Type *export to generate the Session Brief, or *build to scaffold and start Phase A"
308
480
 
309
- Confirm to the user: "Technical stack recorded in CLAUDE.md and project memory. Every build agent will read this before writing a line of code. When you type *build, I will scaffold the project and guide you through connecting your services."
481
+ Confirm to the user: "Design approach chosen and recorded. [Design approach name] will guide all screens in this project. Every build agent will reference these wireframes when implementing the UI."
310
482
 
311
483
  ---
312
484