odd-studio 2.4.1 → 2.6.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/package.json +1 -1
- package/scripts/excalidraw-skill/SKILL.md +208 -0
- package/scripts/install-excalidraw.js +29 -0
- package/scripts/postinstall.js +2 -1
- package/scripts/scaffold-project.js +12 -0
- package/skill/SKILL.md +9 -3
- package/skill/docs/build/build-protocol.md +176 -1
- package/skill/docs/planning/build-planner.md +258 -60
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 });
|
package/package.json
CHANGED
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: excalidraw
|
|
3
|
+
description: Wireframe and diagram generation for UI/design planning
|
|
4
|
+
version: 1.1.0
|
|
5
|
+
author: ODD Studio
|
|
6
|
+
source: https://github.com/excalidraw/excalidraw
|
|
7
|
+
tags:
|
|
8
|
+
- ui-design
|
|
9
|
+
- wireframing
|
|
10
|
+
- planning
|
|
11
|
+
- visualization
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
# Excalidraw Wireframe Generator
|
|
15
|
+
|
|
16
|
+
Generate `.excalidraw` wireframe files that can be opened in excalidraw.com or the VS Code Excalidraw extension.
|
|
17
|
+
|
|
18
|
+
## How This Skill Works
|
|
19
|
+
|
|
20
|
+
When invoked, you MUST generate a valid `.excalidraw` JSON file. This is not a documentation skill — it is a generation skill. You produce output.
|
|
21
|
+
|
|
22
|
+
## Output Format
|
|
23
|
+
|
|
24
|
+
Every invocation produces a `.excalidraw` file saved to `docs/wireframes/` in the project directory. The file is valid Excalidraw JSON that can be:
|
|
25
|
+
- Dragged into https://excalidraw.com for interactive editing
|
|
26
|
+
- Opened in VS Code with the Excalidraw extension
|
|
27
|
+
- Exported as PNG or SVG from either tool
|
|
28
|
+
|
|
29
|
+
## Excalidraw JSON Schema
|
|
30
|
+
|
|
31
|
+
An `.excalidraw` file is JSON with this structure:
|
|
32
|
+
|
|
33
|
+
```json
|
|
34
|
+
{
|
|
35
|
+
"type": "excalidraw",
|
|
36
|
+
"version": 2,
|
|
37
|
+
"source": "odd-studio",
|
|
38
|
+
"elements": [ ... ],
|
|
39
|
+
"appState": {
|
|
40
|
+
"gridSize": null,
|
|
41
|
+
"viewBackgroundColor": "#0a0a0f",
|
|
42
|
+
"theme": "dark"
|
|
43
|
+
},
|
|
44
|
+
"files": {}
|
|
45
|
+
}
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
### Element Types
|
|
49
|
+
|
|
50
|
+
Every element in the `elements` array has these common fields:
|
|
51
|
+
|
|
52
|
+
```json
|
|
53
|
+
{
|
|
54
|
+
"id": "unique-id",
|
|
55
|
+
"type": "rectangle|ellipse|diamond|text|line|arrow",
|
|
56
|
+
"x": 0,
|
|
57
|
+
"y": 0,
|
|
58
|
+
"width": 100,
|
|
59
|
+
"height": 50,
|
|
60
|
+
"angle": 0,
|
|
61
|
+
"strokeColor": "#495057",
|
|
62
|
+
"backgroundColor": "#1e1e2e",
|
|
63
|
+
"fillStyle": "solid",
|
|
64
|
+
"strokeWidth": 1,
|
|
65
|
+
"roughness": 0,
|
|
66
|
+
"opacity": 100,
|
|
67
|
+
"roundness": { "type": 3 },
|
|
68
|
+
"seed": 1001,
|
|
69
|
+
"version": 1,
|
|
70
|
+
"isDeleted": false,
|
|
71
|
+
"boundElements": null,
|
|
72
|
+
"link": null,
|
|
73
|
+
"locked": false
|
|
74
|
+
}
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
**Rectangle** — Use for containers, cards, buttons, inputs, navigation bars, progress bars:
|
|
78
|
+
- Set `roundness: { "type": 3 }` for rounded corners (cards, buttons)
|
|
79
|
+
- Set `roundness: null` for sharp corners (sidebars, headers)
|
|
80
|
+
- For buttons: small height (28-36), accent `backgroundColor`, `"transparent"` `strokeColor`
|
|
81
|
+
- For cards: `backgroundColor: "#313244"`, `strokeColor: "#495057"`
|
|
82
|
+
- For progress bars: two overlapping rectangles (background + fill)
|
|
83
|
+
|
|
84
|
+
**Text** — Use for labels, headings, body text:
|
|
85
|
+
```json
|
|
86
|
+
{
|
|
87
|
+
"type": "text",
|
|
88
|
+
"text": "Your label here",
|
|
89
|
+
"fontSize": 14,
|
|
90
|
+
"fontFamily": 1,
|
|
91
|
+
"textAlign": "left",
|
|
92
|
+
"verticalAlign": "top"
|
|
93
|
+
}
|
|
94
|
+
```
|
|
95
|
+
- Headings: `fontSize: 20-28`, `strokeColor: "#cdd6f4"`
|
|
96
|
+
- Body text: `fontSize: 13-14`, `strokeColor: "#cdd6f4"`
|
|
97
|
+
- Muted/secondary: `fontSize: 12-13`, `strokeColor: "#6c7086"`
|
|
98
|
+
- Accent text: `strokeColor: "#a78bfa"` (or project accent colour)
|
|
99
|
+
|
|
100
|
+
**Ellipse** — Use for avatars, status indicators:
|
|
101
|
+
- Equal width/height for circles
|
|
102
|
+
|
|
103
|
+
**Diamond** — Use for badges, decorative icons:
|
|
104
|
+
- Good for achievement/badge indicators
|
|
105
|
+
|
|
106
|
+
**Line** — Use for separators, connectors:
|
|
107
|
+
```json
|
|
108
|
+
{
|
|
109
|
+
"type": "line",
|
|
110
|
+
"points": [[0, 0], [200, 0]]
|
|
111
|
+
}
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
**Arrow** — Use for flow indicators, data flow diagrams:
|
|
115
|
+
```json
|
|
116
|
+
{
|
|
117
|
+
"type": "arrow",
|
|
118
|
+
"points": [[0, 0], [200, 0]],
|
|
119
|
+
"startArrowhead": null,
|
|
120
|
+
"endArrowhead": "arrow"
|
|
121
|
+
}
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
### Colour Palettes
|
|
125
|
+
|
|
126
|
+
**Dark mode (Catppuccin Mocha — default for ODD Studio):**
|
|
127
|
+
- Background: `#1e1e2e`
|
|
128
|
+
- Surface/cards: `#313244`
|
|
129
|
+
- Surface darker: `#181825`
|
|
130
|
+
- Border: `#495057`
|
|
131
|
+
- Muted surface: `#45475a`
|
|
132
|
+
- Text primary: `#cdd6f4`
|
|
133
|
+
- Text muted: `#6c7086`
|
|
134
|
+
- Accent purple: `#a78bfa`
|
|
135
|
+
- Success green: `#a6e3a1`
|
|
136
|
+
- Warning amber: `#fab387`
|
|
137
|
+
- Error red: `#f38ba8`
|
|
138
|
+
- Canvas background: `#0a0a0f`
|
|
139
|
+
|
|
140
|
+
**Light mode:**
|
|
141
|
+
- Background: `#ffffff`
|
|
142
|
+
- Surface/cards: `#f8f9fa`
|
|
143
|
+
- Border: `#dee2e6`
|
|
144
|
+
- Text primary: `#212529`
|
|
145
|
+
- Text muted: `#6c757d`
|
|
146
|
+
- Accent blue: `#3b82f6`
|
|
147
|
+
- Canvas background: `#f5f5f5`
|
|
148
|
+
|
|
149
|
+
### Layout Patterns
|
|
150
|
+
|
|
151
|
+
**Desktop (1280x800):**
|
|
152
|
+
- Sidebar: x=0, width=240, full height
|
|
153
|
+
- Main content: x=280 (240 sidebar + 40 padding)
|
|
154
|
+
- Content width: ~960px
|
|
155
|
+
- Card grid: 3 columns at 300px each with 30px gaps
|
|
156
|
+
|
|
157
|
+
**Mobile (375x812):**
|
|
158
|
+
- Full-width cards with 16px padding each side (x=16, width=343)
|
|
159
|
+
- Header bar: height=60, full width
|
|
160
|
+
- Bottom tab bar: y=752, height=60, full width
|
|
161
|
+
- Stack cards vertically with 16px gaps
|
|
162
|
+
|
|
163
|
+
**Tablet (768x1024):**
|
|
164
|
+
- 2-column card grid
|
|
165
|
+
- Collapsible sidebar or top navigation
|
|
166
|
+
|
|
167
|
+
### Wireframe Composition Rules
|
|
168
|
+
|
|
169
|
+
1. **Always include a label** above each wireframe frame identifying it (e.g., "DESKTOP — Student Dashboard (1280x800)")
|
|
170
|
+
2. **Use realistic content** — not "Lorem ipsum". Use domain-specific text from the specification.
|
|
171
|
+
3. **Show the key outcome flow** — the most important screen the persona interacts with.
|
|
172
|
+
4. **Include navigation** — sidebar on desktop, bottom tabs on mobile.
|
|
173
|
+
5. **Show data states** — progress bars should show realistic percentages, cards should have real titles.
|
|
174
|
+
6. **Use the project's accent colour** consistently for interactive elements (buttons, active tabs, links).
|
|
175
|
+
7. **Keep `roughness: 0`** for clean wireframes. Use `roughness: 1` only if a hand-drawn sketch style is requested.
|
|
176
|
+
|
|
177
|
+
### Generating Multiple Views
|
|
178
|
+
|
|
179
|
+
When generating wireframes for Step 9b (UI & Design Decision), create separate files for each design approach:
|
|
180
|
+
|
|
181
|
+
- `docs/wireframes/minimalist-dark.excalidraw` — dark mode, minimal, shadcn/ui
|
|
182
|
+
- `docs/wireframes/dense-dashboard-light.excalidraw` — light mode, data-dense, tables
|
|
183
|
+
- `docs/wireframes/minimal-accessible.excalidraw` — high contrast, large targets, WCAG AAA
|
|
184
|
+
- `docs/wireframes/brand-driven.excalidraw` — custom palette, domain-specific visual language
|
|
185
|
+
|
|
186
|
+
Each file should contain both desktop and mobile views side-by-side on the same canvas:
|
|
187
|
+
- Desktop frame at x=0
|
|
188
|
+
- Mobile frame at x=(desktop width + 120)
|
|
189
|
+
|
|
190
|
+
### Seed Values
|
|
191
|
+
|
|
192
|
+
Every element needs a unique `seed` value (integer). Use a simple incrementing counter:
|
|
193
|
+
- Desktop elements: 1001, 1002, 1003...
|
|
194
|
+
- Mobile elements: 2001, 2002, 2003...
|
|
195
|
+
- Additional views: 3001, 3002, 3003...
|
|
196
|
+
|
|
197
|
+
## Usage
|
|
198
|
+
|
|
199
|
+
When the `/excalidraw` command is invoked with arguments, parse the arguments to understand:
|
|
200
|
+
1. What to wireframe (which screen, which persona, which outcome)
|
|
201
|
+
2. Which design approach (dark/light, minimal/dense, accessible, brand-driven)
|
|
202
|
+
3. Which devices (desktop, mobile, tablet)
|
|
203
|
+
|
|
204
|
+
Then generate the `.excalidraw` JSON file using the schema above and save it to `docs/wireframes/[design-approach-name].excalidraw`.
|
|
205
|
+
|
|
206
|
+
After generating, tell the user:
|
|
207
|
+
- The file path
|
|
208
|
+
- How to open it: "Drag this file into excalidraw.com to view and edit interactively, or open it with the VS Code Excalidraw extension."
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
import fs from 'fs-extra';
|
|
3
|
+
import path from 'path';
|
|
4
|
+
import os from 'os';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Installs the excalidraw skill into Claude Code.
|
|
8
|
+
*
|
|
9
|
+
* Copies the SKILL.md (with full generation logic) from the bundled
|
|
10
|
+
* excalidraw-skill directory to ~/.claude/skills/excalidraw/
|
|
11
|
+
*/
|
|
12
|
+
export default async function installExcalidraw(packageRoot, options = {}) {
|
|
13
|
+
const source = path.join(packageRoot, 'scripts', 'excalidraw-skill');
|
|
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
|
+
// Copy the excalidraw skill directory (contains SKILL.md with generation logic)
|
|
26
|
+
await fs.copy(source, destination);
|
|
27
|
+
|
|
28
|
+
return { destination };
|
|
29
|
+
}
|
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
|
})
|
|
@@ -41,6 +41,18 @@ export default async function scaffoldProject(targetDir, projectName) {
|
|
|
41
41
|
await fs.writeJson(stateFile, state, { spaces: 2 });
|
|
42
42
|
}
|
|
43
43
|
|
|
44
|
+
// Create .vscode/extensions.json with recommended extensions
|
|
45
|
+
const vscodeDir = path.join(targetDir, '.vscode');
|
|
46
|
+
const extensionsFile = path.join(vscodeDir, 'extensions.json');
|
|
47
|
+
if (!fs.existsSync(extensionsFile)) {
|
|
48
|
+
await fs.ensureDir(vscodeDir);
|
|
49
|
+
await fs.writeJson(extensionsFile, {
|
|
50
|
+
recommendations: [
|
|
51
|
+
'pomdtr.excalidraw-editor'
|
|
52
|
+
]
|
|
53
|
+
}, { spaces: 2 });
|
|
54
|
+
}
|
|
55
|
+
|
|
44
56
|
// Initialise git if not already a repo
|
|
45
57
|
const gitDir = path.join(targetDir, '.git');
|
|
46
58
|
if (!fs.existsSync(gitDir)) {
|
package/skill/SKILL.md
CHANGED
|
@@ -250,17 +250,23 @@ Type `*build` to begin, or `*status` to see the full phase progress.
|
|
|
250
250
|
|
|
251
251
|
Generate the IDE Session Brief. This is a standalone document that a developer or AI coding agent can use to execute a build session without needing to ask planning questions.
|
|
252
252
|
|
|
253
|
-
Load `docs/plan.md` and all outcome files from `docs/outcomes/`. Generate `docs/session-brief.md`
|
|
253
|
+
Load `docs/plan.md` and all outcome files from `docs/outcomes/`. Check `.odd/state.json` for the current `sessionBriefCount` (default 0 if not set). Generate `docs/session-brief-[N].md` where N is the current count.
|
|
254
|
+
|
|
255
|
+
Include:
|
|
254
256
|
|
|
255
257
|
- Project overview (one paragraph)
|
|
256
258
|
- Active persona(s) for this session
|
|
257
259
|
- Outcomes in scope (with full 6-field specification)
|
|
258
260
|
- Contracts in play (what is produced, what is consumed)
|
|
261
|
+
- Available from previous phases (contracts already built)
|
|
259
262
|
- Verification steps for each outcome
|
|
260
263
|
- Build sequence (which outcome to start, which depends on which)
|
|
261
264
|
- Any known constraints or failure paths to handle
|
|
265
|
+
- Changes from original plan (if any reconciliation has occurred)
|
|
266
|
+
|
|
267
|
+
Increment `sessionBriefCount` in `.odd/state.json`.
|
|
262
268
|
|
|
263
|
-
After writing the file, display: "
|
|
269
|
+
After writing the file, display: "Session Brief [N] has been written to docs/session-brief-[N].md. Open it in your IDE or share it with your build AI to begin the session."
|
|
264
270
|
|
|
265
271
|
---
|
|
266
272
|
|
|
@@ -587,7 +593,7 @@ At key moments in the methodology, proactively explain why the current step matt
|
|
|
587
593
|
"Checkpoint runs automatically every time you confirm an outcome. It scans what was just built for security issues — exposed secrets, missing authentication checks, injection vulnerabilities — and briefs the build agent to fix anything it finds before you move on. You do not need to understand what it found or how it was fixed. Security is not a separate concern in ODD Studio. It is built into the rhythm of the build."
|
|
588
594
|
|
|
589
595
|
**Phase complete:**
|
|
590
|
-
"Phase complete. All outcomes in this phase have been verified and cleared by Checkpoint. The
|
|
596
|
+
"Phase complete. All outcomes in this phase have been verified and cleared by Checkpoint. The plan has been reconciled with changes from this phase, and Session Brief [N] has been generated for the next phase. Review it at `docs/session-brief-[N].md` or type `*build` to continue. All previous session briefs are retained. Well done — this is exactly how a well-planned build should progress."
|
|
591
597
|
|
|
592
598
|
---
|
|
593
599
|
|
|
@@ -83,7 +83,182 @@ Three checks run:
|
|
|
83
83
|
|
|
84
84
|
**Cross-persona check.** Confirm each persona sees what they should see and cannot access what they should not. Navigate as a customer to a page that should only be accessible to an organiser. Confirm it is blocked.
|
|
85
85
|
|
|
86
|
-
When all three checks pass, the phase is complete. ODD Studio
|
|
86
|
+
When all three checks pass, the phase is complete. ODD Studio runs the Phase Transition procedure.
|
|
87
|
+
|
|
88
|
+
---
|
|
89
|
+
|
|
90
|
+
## Phase Transition
|
|
91
|
+
|
|
92
|
+
When a phase is complete and all integration checks pass, ODD Studio advances to the next phase. This is a four-step process: mark complete, reconcile the plan, generate the next numbered brief, and confirm with the domain expert.
|
|
93
|
+
|
|
94
|
+
---
|
|
95
|
+
|
|
96
|
+
### Transition Step 1: Mark the current phase complete
|
|
97
|
+
|
|
98
|
+
Update `.odd/state.json`:
|
|
99
|
+
- Set the current phase status to `"complete"`
|
|
100
|
+
- Update `lastSessionDate`
|
|
101
|
+
|
|
102
|
+
Store completion in ruflo memory:
|
|
103
|
+
|
|
104
|
+
Call `mcp__ruflo__memory_store`:
|
|
105
|
+
- Key: `odd-phase-[phase-name]-complete`
|
|
106
|
+
- Namespace: `odd-project`
|
|
107
|
+
- Value: phase name, completion date, outcomes verified, integration checks passed
|
|
108
|
+
|
|
109
|
+
---
|
|
110
|
+
|
|
111
|
+
### Transition Step 2: Plan Reconciliation
|
|
112
|
+
|
|
113
|
+
During the build, things change. Specification gaps are discovered. The domain expert requests new features. A contract turns out to need a different shape. An outcome gets split into two. A service that was planned for a later phase gets pulled forward because the current phase needed it.
|
|
114
|
+
|
|
115
|
+
These changes happen *during* the build — they are recorded in ruflo memory as specification gaps, outcome updates, and contract changes. But `docs/plan.md` still reflects the original plan. If the next phase's brief is generated from a stale plan, it will conflict with reality.
|
|
116
|
+
|
|
117
|
+
**Before generating the next phase's brief, reconcile the plan.**
|
|
118
|
+
|
|
119
|
+
**2a. Gather all changes from the completed phase.**
|
|
120
|
+
|
|
121
|
+
Read from ruflo memory all changes recorded during the phase:
|
|
122
|
+
|
|
123
|
+
Call `mcp__ruflo__memory_search`:
|
|
124
|
+
- Query: `phase [completed-phase-name] changes`
|
|
125
|
+
- Namespace: `odd-project`
|
|
126
|
+
|
|
127
|
+
Also check:
|
|
128
|
+
- All outcome files in `docs/outcomes/` — compare current versions against the plan's original descriptions. Look for updated walkthroughs, new verification steps, changed contracts.
|
|
129
|
+
- The contract map in ruflo memory (`odd-contract-map`) — compare against `docs/contract-map.md`. Look for new contracts, changed data shapes, removed dependencies.
|
|
130
|
+
- Any `*outcome` edits made during the phase (specification gap fixes).
|
|
131
|
+
- Any new outcomes added during the build that were not in the original plan.
|
|
132
|
+
|
|
133
|
+
**2b. Classify each change.**
|
|
134
|
+
|
|
135
|
+
For each change found, classify it:
|
|
136
|
+
|
|
137
|
+
1. **Contained change** — affects only the completed phase. No impact on future phases. Example: a verification step was reworded, a UI layout was adjusted, an error message was improved.
|
|
138
|
+
|
|
139
|
+
2. **Contract change** — a contract's shape, name, or data flow was altered. This affects any future outcome that consumes this contract. Example: the mastery level contract now includes a `confidence_score` field that wasn't in the original plan.
|
|
140
|
+
|
|
141
|
+
3. **New outcome** — a new outcome was identified during the build that needs to be added to a future phase. Example: during Phase 1, the domain expert realised students need a "review mistakes" feature that wasn't originally planned.
|
|
142
|
+
|
|
143
|
+
4. **Moved outcome** — an outcome originally in a later phase was partially or fully built during this phase because it was needed earlier than planned. Example: basic parent notifications were built in Phase 1 because the teacher dashboard needed to reference them.
|
|
144
|
+
|
|
145
|
+
5. **Removed or deferred outcome** — an outcome was removed from scope or moved to a later phase. Example: the gamification system was deprioritised to focus on core learning.
|
|
146
|
+
|
|
147
|
+
6. **Dependency change** — a dependency between phases changed. Example: Phase 3 no longer depends on Phase 2's grouping feature because the parent dashboard was redesigned to use individual student data instead.
|
|
148
|
+
|
|
149
|
+
**2c. Update `docs/plan.md`.**
|
|
150
|
+
|
|
151
|
+
For each change that is NOT contained (types 2-6), update `docs/plan.md`:
|
|
152
|
+
|
|
153
|
+
- **Contract changes**: Update the contract descriptions in the plan. Note what changed and why.
|
|
154
|
+
- **New outcomes**: Add them to the appropriate phase. Re-run the dependency logic — does this new outcome depend on something that hasn't been built yet? If so, assign it to the correct phase.
|
|
155
|
+
- **Moved outcomes**: Update their phase assignment. Mark what was already built and what remains.
|
|
156
|
+
- **Removed/deferred outcomes**: Move them to a "Deferred" section at the bottom of the plan, with the reason.
|
|
157
|
+
- **Dependency changes**: Update the phase dependency descriptions.
|
|
158
|
+
|
|
159
|
+
Add a **Change Log** section at the bottom of `docs/plan.md`:
|
|
160
|
+
|
|
161
|
+
```markdown
|
|
162
|
+
## Change Log
|
|
163
|
+
|
|
164
|
+
### After Phase [completed phase name] — [date]
|
|
165
|
+
- [Change type]: [description of what changed and why]
|
|
166
|
+
- [Change type]: [description]
|
|
167
|
+
- [Change type]: [description]
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
**2d. Store the reconciled plan in ruflo memory.**
|
|
171
|
+
|
|
172
|
+
Call `mcp__ruflo__memory_store`:
|
|
173
|
+
- Key: `odd-plan`
|
|
174
|
+
- Namespace: `odd-project`
|
|
175
|
+
- Value: the full updated Master Implementation Plan
|
|
176
|
+
|
|
177
|
+
Call `mcp__ruflo__memory_store`:
|
|
178
|
+
- Key: `odd-plan-reconciliation-phase-[phase-name]`
|
|
179
|
+
- Namespace: `odd-project`
|
|
180
|
+
- Value: summary of all changes made during reconciliation, with classification and reasoning
|
|
181
|
+
|
|
182
|
+
**2e. Present the reconciliation to the domain expert.**
|
|
183
|
+
|
|
184
|
+
"Before I generate the next phase's brief, I need to account for what changed during the build. Here is what I found:
|
|
185
|
+
|
|
186
|
+
**Changes that affect future phases:**
|
|
187
|
+
- [list each non-contained change with its classification and impact]
|
|
188
|
+
|
|
189
|
+
**Changes contained to the completed phase (no impact on future phases):**
|
|
190
|
+
- [list contained changes — for information only]
|
|
191
|
+
|
|
192
|
+
**Updated plan:**
|
|
193
|
+
- [summary of how `docs/plan.md` was updated]
|
|
194
|
+
- [any outcomes added, moved, removed, or deferred]
|
|
195
|
+
- [any contract shapes that changed]
|
|
196
|
+
|
|
197
|
+
Does this reconciliation look correct? Are there any other changes from this phase that I missed?"
|
|
198
|
+
|
|
199
|
+
Wait for the domain expert to confirm before proceeding to Step 3.
|
|
200
|
+
|
|
201
|
+
---
|
|
202
|
+
|
|
203
|
+
### Transition Step 3: Generate the next numbered Session Brief
|
|
204
|
+
|
|
205
|
+
Session briefs are numbered sequentially. The first brief is `session-brief-0.md`. Each subsequent phase gets the next number.
|
|
206
|
+
|
|
207
|
+
Read `.odd/state.json` to get the current `sessionBriefCount`. The next brief is `docs/session-brief-[N].md` where N is the current count.
|
|
208
|
+
|
|
209
|
+
Generate the brief from the **reconciled** `docs/plan.md` (not the original plan). The brief must reflect any changes from Transition Step 2.
|
|
210
|
+
|
|
211
|
+
The brief follows the same structure as Step 10, with these additions:
|
|
212
|
+
|
|
213
|
+
- **"Available From Previous Phases"** section listing all contracts and infrastructure produced by completed phases
|
|
214
|
+
- **"Changes From Original Plan"** section listing any reconciliation changes that affect this phase — new outcomes added, contracts that changed shape, dependencies that shifted. If none: "No changes — this phase matches the original plan."
|
|
215
|
+
|
|
216
|
+
Save to `docs/session-brief-[N].md`.
|
|
217
|
+
|
|
218
|
+
Store in ruflo memory:
|
|
219
|
+
|
|
220
|
+
Call `mcp__ruflo__memory_store`:
|
|
221
|
+
- Key: `odd-session-brief-[N]`
|
|
222
|
+
- Namespace: `odd-project`
|
|
223
|
+
- Value: the contents of the new session brief
|
|
224
|
+
|
|
225
|
+
Update `.odd/state.json`:
|
|
226
|
+
- Set `currentBuildPhase` to the next phase
|
|
227
|
+
- Increment `sessionBriefCount`
|
|
228
|
+
|
|
229
|
+
---
|
|
230
|
+
|
|
231
|
+
### Transition Step 4: Confirm the transition
|
|
232
|
+
|
|
233
|
+
"Phase [completed phase name] is complete. All outcomes verified. All integration checks passed.
|
|
234
|
+
|
|
235
|
+
[If reconciliation found changes]: The plan has been updated to reflect [N] changes from this phase. Review the updated plan at `docs/plan.md`.
|
|
236
|
+
|
|
237
|
+
Session Brief [N] has been generated for Phase [next phase name]: [phase description]. This phase contains [n] outcomes: [list outcome names].
|
|
238
|
+
|
|
239
|
+
[If changes affect this phase]: Note: this phase has been updated since the original plan — [brief summary of what changed].
|
|
240
|
+
|
|
241
|
+
All previous session briefs are retained:
|
|
242
|
+
[list: session-brief-0.md through session-brief-[N-1].md]
|
|
243
|
+
|
|
244
|
+
Type `*build` to begin Phase [next phase name], or review the Session Brief at `docs/session-brief-[N].md` first."
|
|
245
|
+
|
|
246
|
+
---
|
|
247
|
+
|
|
248
|
+
### Transition Step 5: If this was the final phase
|
|
249
|
+
|
|
250
|
+
If no phases remain, the project build is complete. Update `.odd/state.json`:
|
|
251
|
+
- Set `currentPhase` to `"complete"`
|
|
252
|
+
- Set `buildComplete` to `true`
|
|
253
|
+
|
|
254
|
+
Confirm:
|
|
255
|
+
|
|
256
|
+
"All phases are complete. Every outcome has been verified and every integration check has passed. Your project is built.
|
|
257
|
+
|
|
258
|
+
Session briefs retained: [list all numbered briefs].
|
|
259
|
+
Plan reconciliation history: [list all reconciliation entries from the change log].
|
|
260
|
+
|
|
261
|
+
Review the full system end-to-end against your original personas. Does Alex experience what you documented? Does Sarah see what you specified? Does Jennifer receive what you described? If yes, your ODD project is done."
|
|
87
262
|
|
|
88
263
|
---
|
|
89
264
|
|
|
@@ -197,99 +197,142 @@ 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 — Component-by-Component 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 decisions in the project must happen — and you and the domain expert will make them together, one layer at a time.
|
|
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
|
+
**Do NOT present a matrix of pre-bundled stacks.** Technology choices are independent — the domain expert should be able to choose Next.js with Supabase and NextAuth, or SvelteKit with Neon and Clerk, or any other valid combination. Each layer is its own decision.
|
|
207
207
|
|
|
208
|
-
|
|
208
|
+
**Phase 1: Research and Prepare**
|
|
209
|
+
|
|
210
|
+
Read the full specification to understand the constraints:
|
|
209
211
|
- Every persona: their context, technical confidence, devices, volume
|
|
210
212
|
- Every walkthrough: load implications, real-time requirements, data complexity, integration needs
|
|
211
213
|
- Every contract: data relationships, how deeply interconnected the outcomes are
|
|
212
214
|
- The phase structure: scale and depth of what is being built
|
|
213
215
|
|
|
214
|
-
|
|
216
|
+
**Phase 2: Walk Through Each Decision — One at a Time**
|
|
215
217
|
|
|
216
|
-
|
|
218
|
+
Present each technology layer as its own decision. For each layer, present 3-4 credible options with trade-offs tied to THIS project's specification. Wait for the domain expert to choose before moving to the next layer.
|
|
217
219
|
|
|
218
|
-
|
|
220
|
+
**The sequence:**
|
|
219
221
|
|
|
220
|
-
|
|
222
|
+
1. Framework
|
|
223
|
+
2. Database
|
|
224
|
+
3. Authentication
|
|
225
|
+
4. Hosting & Deployment
|
|
226
|
+
5. Specialist Services (if needed — email, payments, real-time, etc.)
|
|
221
227
|
|
|
222
|
-
|
|
228
|
+
For each layer, follow this pattern:
|
|
223
229
|
|
|
224
|
-
|
|
230
|
+
---
|
|
225
231
|
|
|
226
|
-
[
|
|
232
|
+
**Decision [N]: [Layer Name]**
|
|
227
233
|
|
|
228
|
-
|
|
234
|
+
"Now we choose your [layer]. Based on your specification, here are the realistic options:"
|
|
229
235
|
|
|
230
|
-
|
|
236
|
+
**[Option A]**
|
|
237
|
+
- What it is: [one sentence]
|
|
238
|
+
- Why it fits your project: [specific evidence from the specification — reference a persona, outcome, or contract]
|
|
239
|
+
- Trade-off: [what you give up — cost, complexity, lock-in, learning curve]
|
|
231
240
|
|
|
232
|
-
|
|
233
|
-
-
|
|
234
|
-
-
|
|
241
|
+
**[Option B]**
|
|
242
|
+
- What it is: [one sentence]
|
|
243
|
+
- Why it fits your project: [specific evidence from the specification]
|
|
244
|
+
- Trade-off: [what you give up]
|
|
235
245
|
|
|
236
|
-
**
|
|
246
|
+
**[Option C]**
|
|
247
|
+
- What it is: [one sentence]
|
|
248
|
+
- Why it fits your project: [specific evidence from the specification]
|
|
249
|
+
- Trade-off: [what you give up]
|
|
237
250
|
|
|
238
|
-
|
|
251
|
+
"Which of these fits best for your project? Are there constraints I don't know about that rule any of these out?"
|
|
239
252
|
|
|
240
253
|
---
|
|
241
254
|
|
|
242
|
-
**
|
|
255
|
+
**Do not recommend. Offer. Let the domain expert choose.**
|
|
243
256
|
|
|
244
|
-
|
|
257
|
+
Wait for their answer. Record it. Move to the next layer.
|
|
245
258
|
|
|
246
|
-
|
|
259
|
+
If the domain expert raises a concern:
|
|
260
|
+
- If the concern reveals a constraint you missed: "You are right — I did not weight [constraint] heavily enough. Let me revise."
|
|
261
|
+
- If the concern is a misunderstanding: "I want to clarify — [option] actually handles [capability] this way."
|
|
262
|
+
- If the concern reveals a preference: "That preference carries a trade-off: [concrete consequence]. If you are comfortable with that, we proceed."
|
|
247
263
|
|
|
248
|
-
|
|
264
|
+
**Important rules for each decision:**
|
|
265
|
+
- Never bundle choices together. Framework is independent of database is independent of auth.
|
|
266
|
+
- Never exclude valid combinations. If someone wants Next.js + Supabase + NextAuth, that is a valid stack.
|
|
267
|
+
- Always tie reasoning to the specification. "This fits because Outcome 2.1 requires real-time updates for 90 students" — not "This is popular."
|
|
268
|
+
- If a previous choice constrains the next (e.g., choosing Supabase for database means Supabase Auth is available as an auth option), mention it as context but do not force it.
|
|
249
269
|
|
|
250
|
-
|
|
270
|
+
**Phase 3: Confirm the Fixed Layers**
|
|
251
271
|
|
|
252
|
-
|
|
272
|
+
After all choices are made, explain the two components that are included in every ODD Studio project regardless of choice:
|
|
253
273
|
|
|
254
|
-
|
|
274
|
+
**Drizzle ORM** — the database layer that keeps the AI honest.
|
|
255
275
|
|
|
256
|
-
|
|
276
|
+
"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."
|
|
257
277
|
|
|
258
|
-
**
|
|
278
|
+
**Vitest** — automated checks for invisible behaviours.
|
|
259
279
|
|
|
260
|
-
|
|
280
|
+
"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."
|
|
261
281
|
|
|
262
|
-
|
|
282
|
+
These are not negotiable. They exist because the build agents need them, not because of preference.
|
|
263
283
|
|
|
264
|
-
**
|
|
284
|
+
**Phase 4: Summarise and Confirm**
|
|
265
285
|
|
|
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."
|
|
286
|
+
After all decisions are made, present the complete stack as a summary:
|
|
269
287
|
|
|
270
|
-
|
|
288
|
+
"Here is the technical stack you have chosen, decision by decision:
|
|
271
289
|
|
|
272
|
-
**
|
|
290
|
+
- **Framework**: [chosen] — because [reason from their decision]
|
|
291
|
+
- **Database**: [chosen] — because [reason from their decision]
|
|
292
|
+
- **ORM**: Drizzle (fixed — build agent requirement)
|
|
293
|
+
- **Auth**: [chosen] — because [reason from their decision]
|
|
294
|
+
- **Hosting**: [chosen] — because [reason from their decision]
|
|
295
|
+
- **Testing**: Vitest (fixed — build agent requirement)
|
|
296
|
+
- [Any specialist services]: [chosen] — because [reason from their decision]
|
|
273
297
|
|
|
274
|
-
|
|
298
|
+
Does this look right? Any second thoughts before I record it?"
|
|
275
299
|
|
|
276
|
-
|
|
277
|
-
|
|
300
|
+
Wait for confirmation. If they want to change a layer, go back to that specific decision — do not re-run the entire sequence.
|
|
301
|
+
|
|
302
|
+
**Phase 5: Record the Decision**
|
|
278
303
|
|
|
279
|
-
|
|
280
|
-
ORM: Drizzle
|
|
281
|
-
Testing: Vitest
|
|
304
|
+
When the domain expert confirms, record the complete stack in CLAUDE.md and project memory.
|
|
282
305
|
|
|
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
|
|
306
|
+
Append a technical decisions section to `CLAUDE.md`:
|
|
288
307
|
|
|
289
|
-
|
|
290
|
-
|
|
308
|
+
```
|
|
309
|
+
## Technical Stack
|
|
291
310
|
|
|
292
|
-
|
|
311
|
+
**Chosen stack:**
|
|
312
|
+
- Framework: [chosen]
|
|
313
|
+
- Database: [chosen]
|
|
314
|
+
- ORM: Drizzle
|
|
315
|
+
- Auth: [chosen]
|
|
316
|
+
- Testing: Vitest
|
|
317
|
+
- Hosting: [chosen]
|
|
318
|
+
- [Other services]: [chosen]
|
|
319
|
+
|
|
320
|
+
**Decision reasoning (tied to specification):**
|
|
321
|
+
- Framework: [why, with reference to specific outcome or persona]
|
|
322
|
+
- Database: [why, with reference to specific outcome or persona]
|
|
323
|
+
- Auth: [why, with reference to specific outcome or persona]
|
|
324
|
+
- Hosting: [why, with reference to specific outcome or persona]
|
|
325
|
+
- 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
|
|
326
|
+
- Vitest: automated testing for invisible business rules — catches regressions before verification
|
|
327
|
+
|
|
328
|
+
**Alternatives considered (per layer):**
|
|
329
|
+
- Framework: [rejected options and why — specific constraint from the specification]
|
|
330
|
+
- Database: [rejected options and why]
|
|
331
|
+
- Auth: [rejected options and why]
|
|
332
|
+
- Hosting: [rejected options and why]
|
|
333
|
+
|
|
334
|
+
**Domain expert decision notes:**
|
|
335
|
+
[Any specific preferences, constraints, or reasoning the domain expert expressed across the decisions]
|
|
293
336
|
```
|
|
294
337
|
|
|
295
338
|
**Store the decision in ruflo memory.**
|
|
@@ -297,30 +340,177 @@ Domain expert constraints applied: [any preferences or constraints the domain ex
|
|
|
297
340
|
Call `mcp__ruflo__memory_store`:
|
|
298
341
|
- Key: `odd-tech-stack`
|
|
299
342
|
- Namespace: `odd-project`
|
|
300
|
-
- Value: the complete technical stack decision
|
|
343
|
+
- Value: the complete technical stack decision with per-layer reasoning tied to the specification
|
|
301
344
|
|
|
302
345
|
**Update `.odd/state.json`:**
|
|
303
346
|
- Set `techStackDecided: true`
|
|
304
|
-
- Set `techStack` to the chosen
|
|
347
|
+
- Set `techStack` to the chosen stack description (e.g., "Next.js 16 + Supabase + NextAuth + Vercel")
|
|
305
348
|
- Set `orm` to "Drizzle"
|
|
306
349
|
- Set `testingFramework` to "Vitest"
|
|
307
|
-
- Update `nextStep` to "
|
|
350
|
+
- Update `nextStep` to "Review UI and Design approach — type *build to continue"
|
|
308
351
|
|
|
309
|
-
Confirm to the user: "Technical stack
|
|
352
|
+
Confirm to the user: "Technical stack chosen and recorded. Every build agent will read this before writing a line of code."
|
|
353
|
+
|
|
354
|
+
---
|
|
355
|
+
|
|
356
|
+
## Step 9b: UI & Design Decision — Collaborative Visual Planning
|
|
357
|
+
|
|
358
|
+
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.
|
|
359
|
+
|
|
360
|
+
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.
|
|
361
|
+
|
|
362
|
+
**Phase 1: Understand Design Context**
|
|
363
|
+
|
|
364
|
+
Read the full specification to identify design constraints:
|
|
365
|
+
|
|
366
|
+
- **Personas**: Who is using this? What is their technical confidence? Do they need minimal, focused interfaces or rich, data-dense dashboards?
|
|
367
|
+
- **Outcomes**: Which outcomes have screens the persona interacts with? What information must be present, and what can be secondary?
|
|
368
|
+
- **Devices**: Desktop, mobile, tablet, kiosk? Are there accessibility or compliance requirements?
|
|
369
|
+
- **Volume**: High-frequency routine use or occasional intensive sessions? Does interface consistency matter more than density?
|
|
370
|
+
- **Domain language**: Is this a specialized domain with particular conventions (e.g., clinical, financial, legal)? The UI should speak that language.
|
|
371
|
+
|
|
372
|
+
**Phase 2: Identify Realistic Design Approaches**
|
|
373
|
+
|
|
374
|
+
Based on the specification, define 3-4 credible design strategies. Include:
|
|
375
|
+
|
|
376
|
+
1. **Minimalist + Dark (Recommended Default)**
|
|
377
|
+
- Dark background (slate/zinc), single accent colour, clear borders
|
|
378
|
+
- Single-column on mobile, grid on desktop
|
|
379
|
+
- Component library: shadcn/ui + Geist
|
|
380
|
+
- Philosophy: clarity through space and type
|
|
381
|
+
|
|
382
|
+
2. **Dense Dashboard + Light**
|
|
383
|
+
- Light background, information-rich tables and charts
|
|
384
|
+
- Multi-column layouts designed for desktop-first use
|
|
385
|
+
- Keyboard shortcuts, advanced filters, inline editing
|
|
386
|
+
- Philosophy: power users who live in the interface
|
|
387
|
+
|
|
388
|
+
3. **Minimal + Accessible**
|
|
389
|
+
- WCAG AAA compliance (not just AA)
|
|
390
|
+
- High contrast, large touch targets, full keyboard navigation
|
|
391
|
+
- Screen-reader optimized semantic HTML
|
|
392
|
+
- Philosophy: inclusive design that serves all personas equally
|
|
393
|
+
|
|
394
|
+
4. **Brand-Driven + Custom**
|
|
395
|
+
- Custom design system (if the domain demands visual distinction)
|
|
396
|
+
- Domain-specific visual language (e.g., clinical software → muted greens, financial → professional grays)
|
|
397
|
+
- Hand-crafted components specific to this domain
|
|
398
|
+
- Philosophy: interface as part of the brand experience
|
|
399
|
+
|
|
400
|
+
Do NOT include absurd alternatives. Every option must be defensible based on your specification.
|
|
401
|
+
|
|
402
|
+
**Phase 3: Generate Wireframes with Excalidraw**
|
|
403
|
+
|
|
404
|
+
For each design approach, use the excalidraw skill to generate wireframes showing:
|
|
405
|
+
|
|
406
|
+
- One key outcome flow (the most important persona interaction)
|
|
407
|
+
- Layout: how information is organized, where navigation lives, how forms and data are presented
|
|
408
|
+
- Component style: buttons, inputs, cards, modals — representative of the chosen approach
|
|
409
|
+
- Mobile variant (if relevant to specification)
|
|
410
|
+
|
|
411
|
+
Call the excalidraw skill (via `/excalidraw` command) with a prompt like:
|
|
412
|
+
|
|
413
|
+
```
|
|
414
|
+
Generate wireframes for [Design Approach Name] for our [project name] platform.
|
|
415
|
+
|
|
416
|
+
Context:
|
|
417
|
+
- Primary persona: [name], a [role]
|
|
418
|
+
- Key outcome: [outcome name] — [one-sentence description of what they do]
|
|
419
|
+
- Approach philosophy: [brief description of this design approach]
|
|
420
|
+
- Devices: [desktop/mobile/both]
|
|
421
|
+
- Visual style: [dark/light, minimalist/dense, etc.]
|
|
422
|
+
|
|
423
|
+
Show:
|
|
424
|
+
1. Desktop layout of the main interaction
|
|
425
|
+
2. Mobile layout (if applicable)
|
|
426
|
+
3. Key UI components (buttons, inputs, cards) in this style
|
|
427
|
+
4. Navigation pattern
|
|
428
|
+
|
|
429
|
+
Keep wireframes simple — focus on layout and information hierarchy, not pixel-perfect design.
|
|
430
|
+
```
|
|
431
|
+
|
|
432
|
+
The excalidraw skill will generate interactive wireframes you can review, iterate on, and export.
|
|
433
|
+
|
|
434
|
+
**Phase 4: The Domain Expert Reviews and Decides**
|
|
435
|
+
|
|
436
|
+
Present the wireframes side-by-side and ask:
|
|
437
|
+
|
|
438
|
+
"I have generated wireframes for four design approaches. Each matches a different priority from your specification:
|
|
439
|
+
|
|
440
|
+
- **Option A** prioritizes clarity and simplicity — perfect if your personas are occasional users or if the domain is already complex.
|
|
441
|
+
- **Option B** is information-dense — best if your personas spend hours in the system and need to see patterns and relationships at once.
|
|
442
|
+
- **Option C** emphasizes accessibility — ensures every persona, regardless of ability, can use the system equally.
|
|
443
|
+
- **Option D** is custom and domain-specific — creates a visual identity that positions your platform as specialized.
|
|
444
|
+
|
|
445
|
+
Review the wireframes. Tell me:
|
|
446
|
+
- Which design approach feels most natural for how [persona name] would work?
|
|
447
|
+
- Are there any constraints I missed — device types, accessibility requirements, team design preferences?
|
|
448
|
+
- If you could describe the 'feel' of the interface in three words, what would they be?"
|
|
449
|
+
|
|
450
|
+
**Do not push a recommendation. Let the domain expert choose based on the wireframes they see.**
|
|
451
|
+
|
|
452
|
+
**Phase 5: Record the Design Decision**
|
|
453
|
+
|
|
454
|
+
When the domain expert chooses, record the decision.
|
|
455
|
+
|
|
456
|
+
Append to `CLAUDE.md`:
|
|
457
|
+
|
|
458
|
+
```
|
|
459
|
+
## Design Approach
|
|
460
|
+
|
|
461
|
+
**Chosen design approach:**
|
|
462
|
+
[Design approach name]
|
|
463
|
+
|
|
464
|
+
**Reasoning (tied to specification):**
|
|
465
|
+
- [Persona]: [why this design serves them, with specific reference to an outcome]
|
|
466
|
+
- [Persona]: [why this design serves them]
|
|
467
|
+
- Information architecture: [how the chosen approach organizes information for this domain]
|
|
468
|
+
- Component library: [shadcn/ui + custom theming OR domain-specific components]
|
|
469
|
+
- Accessibility: [WCAG AA / AAA / custom standards]
|
|
470
|
+
|
|
471
|
+
**Alternatives considered:**
|
|
472
|
+
- [Option X]: [why it did not fit — specific constraint from the specification]
|
|
473
|
+
- [Option Y]: [why it did not fit — specific constraint from the specification]
|
|
474
|
+
|
|
475
|
+
**Domain expert decision notes:**
|
|
476
|
+
[Any specific preferences, constraints, or reasoning the domain expert expressed]
|
|
477
|
+
```
|
|
478
|
+
|
|
479
|
+
Store in ruflo memory:
|
|
480
|
+
|
|
481
|
+
Call `mcp__ruflo__memory_store`:
|
|
482
|
+
- Key: `odd-design-approach`
|
|
483
|
+
- Namespace: `odd-project`
|
|
484
|
+
- Value: the complete design decision with reasoning tied to the specification and wireframe references
|
|
485
|
+
|
|
486
|
+
Update `.odd/state.json`:
|
|
487
|
+
- Set `designApproachDecided: true`
|
|
488
|
+
- Set `designApproach` to the chosen approach name
|
|
489
|
+
- Update `nextStep` to "Type *export to generate the Session Brief, or *build to scaffold and start Phase A"
|
|
490
|
+
|
|
491
|
+
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
492
|
|
|
311
493
|
---
|
|
312
494
|
|
|
313
495
|
## Step 10: Session Brief Export
|
|
314
496
|
|
|
315
|
-
After the plan is approved, generate the Session Brief — the document a developer or build AI reads at the start of each build session.
|
|
497
|
+
After the plan is approved, generate the first Session Brief — the document a developer or build AI reads at the start of each build session.
|
|
498
|
+
|
|
499
|
+
**Session briefs are numbered.** Every phase gets its own brief, and all briefs are retained so the project has a complete history:
|
|
316
500
|
|
|
317
|
-
|
|
501
|
+
- `docs/session-brief-0.md` — Phase A (Foundation)
|
|
502
|
+
- `docs/session-brief-1.md` — Phase B (first outcomes)
|
|
503
|
+
- `docs/session-brief-2.md` — Phase C
|
|
504
|
+
- ...and so on.
|
|
505
|
+
|
|
506
|
+
The first brief generated here is always `docs/session-brief-0.md`.
|
|
318
507
|
|
|
319
508
|
Structure:
|
|
320
509
|
|
|
321
510
|
```markdown
|
|
322
|
-
# Session Brief — [Project Name] — Phase [X]: [Phase Name]
|
|
511
|
+
# Session Brief [N] — [Project Name] — Phase [X]: [Phase Name]
|
|
323
512
|
Generated: [date]
|
|
513
|
+
Phase: [N] of [total]
|
|
324
514
|
|
|
325
515
|
## Overview
|
|
326
516
|
[One paragraph describing the project, its domain, and its primary personas]
|
|
@@ -334,6 +524,9 @@ Generated: [date]
|
|
|
334
524
|
## Contracts In Play
|
|
335
525
|
[Shared contracts needed for this phase, contracts produced by this phase, contracts consumed from previous phases]
|
|
336
526
|
|
|
527
|
+
## Available From Previous Phases
|
|
528
|
+
[Contracts and infrastructure produced by completed phases — "None" for Phase A]
|
|
529
|
+
|
|
337
530
|
## Verification Steps
|
|
338
531
|
[For each outcome: the complete verification checklist from the outcome specification]
|
|
339
532
|
|
|
@@ -345,9 +538,13 @@ Generated: [date]
|
|
|
345
538
|
|
|
346
539
|
## Not In Scope
|
|
347
540
|
[Explicit list of things that are NOT to be built in this phase, to prevent scope creep]
|
|
541
|
+
|
|
542
|
+
## Changes From Original Plan
|
|
543
|
+
[If this brief was generated after a plan reconciliation: list what changed and why.
|
|
544
|
+
"None — this is the original plan" for the first brief.]
|
|
348
545
|
```
|
|
349
546
|
|
|
350
|
-
After writing the Session Brief, confirm: "Session Brief written to docs/session-brief.md. This is the primary input for your build agents.
|
|
547
|
+
After writing the Session Brief, confirm: "Session Brief 0 written to docs/session-brief-0.md. This is the primary input for your build agents."
|
|
351
548
|
|
|
352
549
|
---
|
|
353
550
|
|
|
@@ -365,14 +562,15 @@ Confirm to the user: "Master Implementation Plan saved to project memory. All bu
|
|
|
365
562
|
Also store the Session Brief:
|
|
366
563
|
|
|
367
564
|
Call `mcp__ruflo__memory_store`:
|
|
368
|
-
- Key: `odd-session-brief-
|
|
565
|
+
- Key: `odd-session-brief-0`
|
|
369
566
|
- Namespace: `odd-project`
|
|
370
|
-
- Value: the contents of `docs/session-brief.md`
|
|
567
|
+
- Value: the contents of `docs/session-brief-0.md`
|
|
371
568
|
|
|
372
569
|
Then update `.odd/state.json`:
|
|
373
570
|
- Set `planApproved: true`
|
|
374
571
|
- Populate `planPhases` with the array of phase names in build order
|
|
375
572
|
- Set `currentBuildPhase` to Phase A
|
|
573
|
+
- Set `sessionBriefCount` to 1
|
|
376
574
|
- Update `nextStep` to "Type *build — ODD Studio will scaffold the project, connect your services, and begin Phase A"
|
|
377
575
|
|
|
378
576
|
---
|