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 +23 -8
- package/hooks/odd-destructive-guard.sh +4 -1
- package/hooks/odd-git-safety.sh +4 -1
- package/hooks/odd-outcome-quality.sh +4 -1
- package/hooks/odd-pre-build.sh +4 -1
- package/hooks/odd-session-save.sh +4 -1
- package/package.json +1 -1
- package/scripts/install-excalidraw.js +180 -0
- package/scripts/postinstall.js +2 -1
- package/skill/docs/planning/build-planner.md +230 -58
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
|
|
45
|
-
.option('--skip-skill', 'Skip installing the /odd
|
|
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
|
|
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('
|
|
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
|
|
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
|
-
|
|
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
|
package/hooks/odd-git-safety.sh
CHANGED
|
@@ -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
|
-
|
|
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
|
-
|
|
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
|
package/hooks/odd-pre-build.sh
CHANGED
|
@@ -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
|
-
|
|
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
|
-
|
|
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
|
@@ -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
|
+
}
|
package/scripts/postinstall.js
CHANGED
|
@@ -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,
|
|
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
|
-
|
|
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
|
-
**
|
|
206
|
+
**Phase 1: Research and Prepare**
|
|
207
207
|
|
|
208
|
-
|
|
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
|
-
|
|
214
|
+
**Phase 2: Identify Realistic Options**
|
|
215
215
|
|
|
216
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
**
|
|
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
|
-
|
|
287
|
+
**Do not recommend. Offer. Let the domain expert choose.**
|
|
227
288
|
|
|
228
|
-
|
|
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
|
-
|
|
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
|
-
|
|
233
|
-
|
|
234
|
-
|
|
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
|
-
**
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
**
|
|
352
|
+
**Phase 1: Understand Design Context**
|
|
247
353
|
|
|
248
|
-
|
|
354
|
+
Read the full specification to identify design constraints:
|
|
249
355
|
|
|
250
|
-
|
|
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
|
-
**
|
|
362
|
+
**Phase 2: Identify Realistic Design Approaches**
|
|
253
363
|
|
|
254
|
-
|
|
364
|
+
Based on the specification, define 3-4 credible design strategies. Include:
|
|
255
365
|
|
|
256
|
-
|
|
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
|
-
**
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
390
|
+
Do NOT include absurd alternatives. Every option must be defensible based on your specification.
|
|
265
391
|
|
|
266
|
-
|
|
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
|
-
|
|
394
|
+
For each design approach, use the excalidraw skill to generate wireframes showing:
|
|
271
395
|
|
|
272
|
-
|
|
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
|
-
|
|
401
|
+
Call the excalidraw skill (via `/excalidraw` command) with a prompt like:
|
|
275
402
|
|
|
276
403
|
```
|
|
277
|
-
|
|
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
|
-
|
|
280
|
-
|
|
281
|
-
|
|
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
|
-
|
|
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
|
-
|
|
290
|
-
|
|
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
|
-
**
|
|
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-
|
|
472
|
+
- Key: `odd-design-approach`
|
|
299
473
|
- Namespace: `odd-project`
|
|
300
|
-
- Value: the complete
|
|
474
|
+
- Value: the complete design decision with reasoning tied to the specification and wireframe references
|
|
301
475
|
|
|
302
|
-
|
|
303
|
-
- Set `
|
|
304
|
-
- Set `
|
|
305
|
-
-
|
|
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: "
|
|
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
|
|