qualia-framework-v2 2.3.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/CLAUDE.md CHANGED
@@ -51,9 +51,10 @@ No accumulated garbage. No context rot.
51
51
  ## Quality Gates (always active)
52
52
  - **Frontend guard:** Read .planning/DESIGN.md before any frontend changes
53
53
  - **Deploy guard:** tsc + lint + build + tests must pass before deploy
54
- - **Branch guard:** Employees cannot push to main
55
- - **Env guard:** Never edit .env files
56
- - **Intent verification:** Confirm before modifying 3+ files
54
+ - **Branch guard:** Employees cannot push to main (OWNER can)
55
+ - **Env guard:** Employees cannot edit .env files (OWNER can — add keys, configure secrets directly)
56
+ - **Sudo guard:** Employees cannot run sudo (OWNER can)
57
+ - **Intent verification:** Confirm before modifying 3+ files (OWNER: just do it)
57
58
 
58
59
  ## Tracking
59
60
  `.planning/tracking.json` is updated on every push. The ERP reads it via git.
package/README.md CHANGED
@@ -12,6 +12,12 @@ npx qualia-framework-v2 install
12
12
 
13
13
  Enter your team code when prompted. Get your code from Fawzi.
14
14
 
15
+ **Other commands:**
16
+ ```bash
17
+ npx qualia-framework-v2 version # Check installed version + updates
18
+ npx qualia-framework-v2 update # Update to latest (remembers your code)
19
+ ```
20
+
15
21
  ## Usage
16
22
 
17
23
  Open Claude Code in any project directory:
@@ -33,6 +39,7 @@ Open Claude Code in any project directory:
33
39
  /qualia-handoff # Deliver to client
34
40
  /qualia-pause # Save session, continue later
35
41
  /qualia-resume # Pick up where you left off
42
+ /qualia-learn # Save a pattern, fix, or client pref
36
43
  /qualia-report # Log your work (mandatory)
37
44
  ```
38
45
 
@@ -40,7 +47,7 @@ See `guide.md` for the full developer guide.
40
47
 
41
48
  ## What's Inside
42
49
 
43
- - **17 skills** — slash commands from setup to handoff, plus debugging, design, review, and session management
50
+ - **18 skills** — slash commands from setup to handoff, plus debugging, design, review, knowledge, and session management
44
51
  - **3 agents** — planner, builder, verifier (each in fresh context)
45
52
  - **7 hooks** — branch guard, pre-push tracking sync, env protection, migration guard, deploy gate, pre-compact state save, session start
46
53
  - **3 rules** — security, frontend, deployment
@@ -85,10 +92,11 @@ npx qualia-framework-v2 install
85
92
  |
86
93
  v
87
94
  ~/.claude/
88
- ├── skills/ 17 slash commands
95
+ ├── skills/ 18 slash commands
89
96
  ├── agents/ planner.md, builder.md, verifier.md
90
97
  ├── hooks/ 7 shell scripts (branch, env, migration, deploy, push, compact, session)
91
98
  ├── bin/ state.js (state machine with precondition enforcement)
99
+ ├── knowledge/ learned-patterns.md, common-fixes.md, client-prefs.md
92
100
  ├── rules/ security.md, frontend.md, deployment.md
93
101
  ├── qualia-templates/ tracking.json, state.md, project.md, plan.md
94
102
  ├── CLAUDE.md global instructions (role-configured per team member)
package/agents/builder.md CHANGED
@@ -83,10 +83,28 @@ Rule of thumb: If you can explain the change in one sentence in a commit message
83
83
  - Always check auth server-side
84
84
  - Enable RLS on every table
85
85
  - Validate input with Zod at system boundaries
86
- 5. **Frontend standards:**
87
- - Distinctive fonts (not Inter/Arial)
88
- - Cohesive color palette with sharp accents
89
- - CSS transitions, subtle animations
90
- - Full-width layouts, no hardcoded max-width
86
+ 5. **Frontend standards (mandatory for any .tsx/.jsx/.css file):**
87
+ - Before writing any frontend code: read `.planning/DESIGN.md` if it exists — it's the design source of truth
88
+ - If no DESIGN.md, apply rules from `rules/frontend.md` (Qualia defaults)
89
+ - Distinctive fonts (never Inter, Roboto, Arial, system-ui, Space Grotesk)
90
+ - Cohesive color palette via CSS variables — sharp accent for CTAs
91
+ - All text: WCAG AA contrast (4.5:1 normal, 3:1 large text)
92
+ - Full-width fluid layouts — no hardcoded max-width caps
93
+ - Every interactive element needs ALL states: hover, focus (visible ring), active, disabled, loading, error, empty
94
+ - Semantic HTML (`nav`, `main`, `section`, `article`) — not div soup
95
+ - Keyboard accessible: Tab, Enter, Escape, Arrow keys work
96
+ - Touch targets: 44px minimum
97
+ - Form inputs: visible labels (not placeholder-only), error messages with `aria-describedby`
98
+ - Motion: 150–200ms hover, 250ms expand, stagger children on load, respect `prefers-reduced-motion`
99
+ - Mobile-first responsive: stack on mobile, expand on desktop, fluid typography
100
+ - Skip link on every page, heading hierarchy (one h1, sequential order)
101
+ - No emoji as icons — use SVGs
102
+ - `cursor: pointer` on all clickable elements
91
103
  6. **No empty catch blocks.** At minimum, log the error.
92
104
  7. **No dangerouslySetInnerHTML.** No eval().
105
+ 8. **React/Next.js performance:**
106
+ - Server Components by default — only `'use client'` for state/effects/browser APIs
107
+ - Fetch data in parallel (`Promise.all`), not sequential waterfalls
108
+ - Import specific functions, not entire libraries — avoid barrel file re-exports
109
+ - Use `next/image` with explicit width/height
110
+ - Use `next/dynamic` for heavy below-fold components
package/agents/planner.md CHANGED
@@ -85,6 +85,20 @@ If a task involves a library or API you're unsure about, use WebFetch to check t
85
85
 
86
86
  **Self-check:** Before returning the plan, verify every task has specific file paths, concrete actions, and testable done-when criteria. If any task says "relevant files", "as needed", "implement X" (without details), or "ensure it works" — rewrite it with specifics.
87
87
 
88
+ ## Design-Aware Planning
89
+
90
+ When a phase involves frontend work (pages, components, layouts, UI):
91
+
92
+ 1. **Check for `.planning/DESIGN.md`** — if it exists, reference it in task Context fields: `@.planning/DESIGN.md`
93
+ 2. **If no DESIGN.md and this is Phase 1** — add a Task 1 (Wave 1) to create it:
94
+ - Generate `.planning/DESIGN.md` from the design direction in PROJECT.md
95
+ - Use the template at `templates/DESIGN.md` — fill in: palette, typography (distinctive fonts), spacing, motion approach, component patterns
96
+ - Done when: DESIGN.md exists with concrete CSS variable values (not placeholders)
97
+ 3. **Include design criteria in "Done when"** for frontend tasks:
98
+ - Not just "page renders" but "page renders with design system typography, proper color palette, all interactive states (hover/focus/loading/error/empty), semantic HTML, keyboard accessible"
99
+ - Include responsive: "works on 375px mobile and 1440px desktop"
100
+ 4. **Reference `@.planning/DESIGN.md`** in the Context field of every frontend task so builders read it before coding
101
+
88
102
  ## Rules
89
103
 
90
104
  1. **Plans complete within ~50% context.** More plans with smaller scope = consistent quality. 2-3 tasks per plan is ideal.
@@ -148,6 +148,68 @@ Phase verdict:
148
148
 
149
149
  Never round up. A PARTIAL is not a PASS. The goal of verification is to catch the work that LOOKS done but ISN'T.
150
150
 
151
+ ## Design Verification (for phases with frontend work)
152
+
153
+ If the phase involved UI/frontend tasks, add a **Design Quality** section to the report:
154
+
155
+ ### Check 1: Design System Compliance
156
+ ```bash
157
+ # Generic fonts (should NOT appear)
158
+ grep -rn "font-family.*Inter\|font-family.*Roboto\|font-family.*Arial\|fontFamily.*Inter\|fontFamily.*Roboto" --include="*.tsx" --include="*.jsx" --include="*.css" app/ components/ src/ 2>/dev/null
159
+ grep -rn "font-sans\|font-inter" --include="*.tsx" --include="*.jsx" app/ components/ src/ 2>/dev/null
160
+
161
+ # Hardcoded max-width containers (should NOT appear)
162
+ grep -rn "max-w-\[1200\|max-w-\[1280\|max-width.*1200\|max-width.*1280\|max-w-7xl" --include="*.tsx" --include="*.jsx" --include="*.css" app/ components/ src/ 2>/dev/null
163
+
164
+ # Hardcoded colors instead of CSS variables (check density)
165
+ grep -rn "color:.*#\|background:.*#\|bg-\[#" --include="*.tsx" --include="*.jsx" app/ components/ src/ 2>/dev/null | wc -l
166
+ ```
167
+
168
+ ### Check 2: Accessibility Basics
169
+ ```bash
170
+ # Images without alt text
171
+ grep -rn "<img" --include="*.tsx" --include="*.jsx" app/ components/ src/ 2>/dev/null | grep -v "alt="
172
+
173
+ # Inputs without labels
174
+ grep -rn "<input\|<textarea\|<select" --include="*.tsx" --include="*.jsx" app/ components/ src/ 2>/dev/null | grep -v "aria-label\|aria-labelledby\|id=" | head -10
175
+
176
+ # outline:none without replacement focus style
177
+ grep -rn "outline.*none\|outline-none" --include="*.tsx" --include="*.jsx" --include="*.css" app/ components/ src/ 2>/dev/null | grep -v "focus-visible\|focus:\|focus-within"
178
+
179
+ # Missing lang attribute
180
+ grep -rn "<html" --include="*.tsx" --include="*.jsx" app/ 2>/dev/null | grep -v "lang="
181
+
182
+ # Heading hierarchy — check for h1 count
183
+ grep -rn "<h1\|<H1" --include="*.tsx" --include="*.jsx" app/ 2>/dev/null | wc -l
184
+ ```
185
+
186
+ ### Check 3: Interactive States
187
+ ```bash
188
+ # Buttons/links without hover/focus styles — spot check
189
+ grep -rn "<button\|<Button\|<a " --include="*.tsx" --include="*.jsx" app/ components/ src/ 2>/dev/null | head -5
190
+ # Verify these have hover/focus transitions in their styling
191
+
192
+ # Loading states — check for skeleton/spinner usage in pages with data fetching
193
+ grep -rn "fetch\|useQuery\|useSWR\|getServerSide\|async.*Component" --include="*.tsx" app/ 2>/dev/null | head -5
194
+ grep -rn "loading\|skeleton\|spinner\|Spinner\|Loading" --include="*.tsx" app/ components/ 2>/dev/null | wc -l
195
+
196
+ # Empty states — check lists/tables have empty handling
197
+ grep -rn "\.length.*===.*0\|\.length.*>.*0\|isEmpty\|no.*results\|no.*data" --include="*.tsx" app/ components/ 2>/dev/null | wc -l
198
+ ```
199
+
200
+ ### Check 4: Responsive
201
+ ```bash
202
+ # Check for responsive utilities or media queries
203
+ grep -rn "sm:\|md:\|lg:\|xl:\|@media" --include="*.tsx" --include="*.jsx" --include="*.css" app/ components/ src/ 2>/dev/null | wc -l
204
+ # If 0 responsive declarations across multiple components → FAIL
205
+ ```
206
+
207
+ ### Scoring Design
208
+ - 0 generic fonts + 0 hardcoded max-widths + colors via variables = **PASS**
209
+ - Accessibility basics all present = **PASS**
210
+ - States and responsive present = **PASS**
211
+ - Any category failing = add to **Gaps** list with specific file:line
212
+
151
213
  ## Rules
152
214
 
153
215
  1. **Never trust summaries.** Always grep the code yourself.
@@ -156,3 +218,4 @@ Never round up. A PARTIAL is not a PASS. The goal of verification is to catch th
156
218
  4. **Stubs are failures.** `// TODO: implement` means the task wasn't done.
157
219
  5. **Empty catch blocks are failures.** They hide real errors.
158
220
  6. **Run tsc.** If TypeScript doesn't compile, nothing works.
221
+ 7. **Design debt is a gap.** Generic fonts, missing states, inaccessible components, and hardcoded layouts are failures — not "nice to haves."
package/bin/cli.js CHANGED
@@ -1,20 +1,148 @@
1
1
  #!/usr/bin/env node
2
2
 
3
+ const { execSync } = require("child_process");
4
+ const path = require("path");
5
+ const fs = require("fs");
6
+
3
7
  const TEAL = "\x1b[38;2;0;206;209m";
8
+ const TG = "\x1b[38;2;0;170;175m";
4
9
  const DIM = "\x1b[38;2;80;90;100m";
10
+ const GREEN = "\x1b[38;2;52;211;153m";
5
11
  const WHITE = "\x1b[38;2;220;225;230m";
12
+ const YELLOW = "\x1b[38;2;234;179;8m";
13
+ const RED = "\x1b[38;2;239;68;68m";
6
14
  const RESET = "\x1b[0m";
15
+ const BOLD = "\x1b[1m";
7
16
 
8
- const cmd = process.argv[2];
17
+ const CLAUDE_DIR = path.join(require("os").homedir(), ".claude");
18
+ const PKG = require("../package.json");
19
+ const CONFIG_FILE = path.join(CLAUDE_DIR, ".qualia-config.json");
20
+
21
+ function readConfig() {
22
+ try {
23
+ return JSON.parse(fs.readFileSync(CONFIG_FILE, "utf8"));
24
+ } catch {
25
+ return {};
26
+ }
27
+ }
28
+
29
+ function writeConfig(cfg) {
30
+ if (!fs.existsSync(CLAUDE_DIR)) fs.mkdirSync(CLAUDE_DIR, { recursive: true });
31
+ fs.writeFileSync(CONFIG_FILE, JSON.stringify(cfg, null, 2) + "\n");
32
+ }
33
+
34
+ function banner() {
35
+ console.log("");
36
+ console.log(` ${TEAL}${BOLD}◆${RESET} ${WHITE}${BOLD}Qualia Framework${RESET} ${DIM}v${PKG.version}${RESET}`);
37
+ console.log(` ${DIM}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${RESET}`);
38
+ }
9
39
 
10
- if (cmd === "install") {
40
+ // ─── Commands ────────────────────────────────────────────
41
+
42
+ function cmdInstall() {
11
43
  require("./install.js");
12
- } else {
44
+ }
45
+
46
+ function cmdVersion() {
47
+ banner();
48
+ const cfg = readConfig();
49
+
50
+ console.log(` ${DIM}Installed:${RESET} ${WHITE}${PKG.version}${RESET}`);
51
+ if (cfg.installed_by) {
52
+ console.log(` ${DIM}User:${RESET} ${WHITE}${cfg.installed_by}${RESET} ${DIM}(${cfg.role})${RESET}`);
53
+ }
54
+ if (cfg.installed_at) {
55
+ console.log(` ${DIM}Date:${RESET} ${WHITE}${cfg.installed_at}${RESET}`);
56
+ }
57
+
58
+ // Check for updates
59
+ try {
60
+ const latest = execSync("npm view qualia-framework-v2 version 2>/dev/null", {
61
+ encoding: "utf8",
62
+ timeout: 5000,
63
+ }).trim();
64
+ const semverGt = (a, b) => {
65
+ const pa = a.split(".").map(Number), pb = b.split(".").map(Number);
66
+ for (let i = 0; i < 3; i++) { if (pa[i] > pb[i]) return true; if (pa[i] < pb[i]) return false; }
67
+ return false;
68
+ };
69
+ if (latest && semverGt(latest, PKG.version)) {
70
+ console.log("");
71
+ console.log(` ${YELLOW}Update available:${RESET} ${WHITE}${latest}${RESET}`);
72
+ console.log(` ${DIM}Run:${RESET} npx qualia-framework-v2 update`);
73
+ } else if (latest) {
74
+ console.log(` ${DIM}Latest:${RESET} ${GREEN}${latest} ✓${RESET} ${DIM}(up to date)${RESET}`);
75
+ }
76
+ } catch {
77
+ console.log(` ${DIM}Latest:${RESET} ${DIM}(offline — couldn't check)${RESET}`);
78
+ }
13
79
  console.log("");
14
- console.log(`${TEAL} ◆ Qualia Framework v2${RESET}`);
15
- console.log(`${DIM} ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${RESET}`);
80
+ }
81
+
82
+ function cmdUpdate() {
83
+ banner();
84
+ const cfg = readConfig();
85
+
86
+ if (!cfg.code) {
87
+ console.log(` ${RED}✗${RESET} No install code saved. Run ${TEAL}install${RESET} first.`);
88
+ console.log("");
89
+ process.exit(1);
90
+ }
91
+
92
+ console.log(` ${DIM}Current:${RESET} ${WHITE}${PKG.version}${RESET}`);
93
+ console.log(` ${DIM}Updating...${RESET}`);
16
94
  console.log("");
17
- console.log(` ${WHITE}Usage:${RESET}`);
18
- console.log(` npx qualia-framework-v2 ${TEAL}install${RESET} Install the framework`);
95
+
96
+ try {
97
+ // Pull latest and reinstall with saved code
98
+ execSync(
99
+ `npx qualia-framework-v2@latest install <<< "${cfg.code}"`,
100
+ { stdio: "inherit", shell: true, timeout: 60000 }
101
+ );
102
+ } catch (e) {
103
+ console.log(` ${RED}✗${RESET} Update failed. Run manually: npx qualia-framework-v2@latest install`);
104
+ process.exit(1);
105
+ }
106
+ }
107
+
108
+ function cmdHelp() {
109
+ banner();
19
110
  console.log("");
111
+ console.log(` ${WHITE}Commands:${RESET}`);
112
+ console.log(` npx qualia-framework-v2 ${TEAL}install${RESET} Install or reinstall the framework`);
113
+ console.log(` npx qualia-framework-v2 ${TEAL}update${RESET} Update to the latest version`);
114
+ console.log(` npx qualia-framework-v2 ${TEAL}version${RESET} Show installed version + check for updates`);
115
+ console.log("");
116
+ console.log(` ${WHITE}After install:${RESET}`);
117
+ console.log(` ${TG}/qualia${RESET} What should I do next?`);
118
+ console.log(` ${TG}/qualia-new${RESET} Set up a new project`);
119
+ console.log(` ${TG}/qualia-plan${RESET} Plan a phase`);
120
+ console.log(` ${TG}/qualia-build${RESET} Build it (parallel tasks)`);
121
+ console.log(` ${TG}/qualia-verify${RESET} Verify it works`);
122
+ console.log(` ${TG}/qualia-design${RESET} One-shot design fix`);
123
+ console.log(` ${TG}/qualia-debug${RESET} Structured debugging`);
124
+ console.log(` ${TG}/qualia-review${RESET} Production audit`);
125
+ console.log(` ${TG}/qualia-ship${RESET} Deploy to production`);
126
+ console.log(` ${TG}/qualia-report${RESET} Log your work`);
127
+ console.log("");
128
+ }
129
+
130
+ // ─── Main ────────────────────────────────────────────────
131
+ const cmd = process.argv[2];
132
+
133
+ switch (cmd) {
134
+ case "install":
135
+ cmdInstall();
136
+ break;
137
+ case "version":
138
+ case "-v":
139
+ case "--version":
140
+ cmdVersion();
141
+ break;
142
+ case "update":
143
+ case "upgrade":
144
+ cmdUpdate();
145
+ break;
146
+ default:
147
+ cmdHelp();
20
148
  }
package/bin/install.js CHANGED
@@ -223,6 +223,46 @@ async function main() {
223
223
  warn(`guide.md — ${e.message}`);
224
224
  }
225
225
 
226
+ // ─── Knowledge directory ─────────────────────────────────
227
+ log(`${WHITE}Knowledge${RESET}`);
228
+ const knowledgeDir = path.join(CLAUDE_DIR, "knowledge");
229
+ if (!fs.existsSync(knowledgeDir)) fs.mkdirSync(knowledgeDir, { recursive: true });
230
+ const knowledgeFiles = {
231
+ "learned-patterns.md": "# Learned Patterns\n\nPatterns discovered across projects. Updated by `/qualia-evolve` and manual notes.\n",
232
+ "common-fixes.md": "# Common Fixes\n\nRecurring issues and their solutions.\n",
233
+ "client-prefs.md": "# Client Preferences\n\nClient-specific preferences, design choices, and requirements.\n",
234
+ };
235
+ for (const [name, defaultContent] of Object.entries(knowledgeFiles)) {
236
+ const dest = path.join(knowledgeDir, name);
237
+ if (!fs.existsSync(dest)) {
238
+ fs.writeFileSync(dest, defaultContent);
239
+ ok(`${name} (created)`);
240
+ } else {
241
+ ok(`${name} (exists)`);
242
+ }
243
+ }
244
+
245
+ // ─── Save config (for update command) ──────────────────
246
+ const configFile = path.join(CLAUDE_DIR, ".qualia-config.json");
247
+ const config = {
248
+ code,
249
+ installed_by: member.name,
250
+ role: member.role,
251
+ version: require("../package.json").version,
252
+ installed_at: new Date().toISOString().split("T")[0],
253
+ };
254
+ fs.writeFileSync(configFile, JSON.stringify(config, null, 2) + "\n");
255
+
256
+ // ─── ERP API key (for report uploads) ──────────────────
257
+ log(`${WHITE}ERP integration${RESET}`);
258
+ const erpKeyFile = path.join(CLAUDE_DIR, ".erp-api-key");
259
+ if (!fs.existsSync(erpKeyFile)) {
260
+ fs.writeFileSync(erpKeyFile, "qualia-claude-2026", { mode: 0o600 });
261
+ ok(".erp-api-key (created)");
262
+ } else {
263
+ ok(".erp-api-key (exists)");
264
+ }
265
+
226
266
  // ─── Configure settings.json ───────────────────────────
227
267
  console.log("");
228
268
  log(`${WHITE}Configuring settings.json...${RESET}`);
@@ -292,6 +332,11 @@ async function main() {
292
332
  {
293
333
  matcher: "Bash",
294
334
  hooks: [
335
+ {
336
+ type: "command",
337
+ command: `${hd}/auto-update.sh`,
338
+ timeout: 5,
339
+ },
295
340
  {
296
341
  type: "command",
297
342
  if: "Bash(git push*)",
@@ -384,7 +429,7 @@ async function main() {
384
429
 
385
430
  fs.writeFileSync(settingsPath, JSON.stringify(settings, null, 2));
386
431
 
387
- ok("Hooks: branch-guard, pre-push, env-block, migration-guard, deploy-gate, pre-compact");
432
+ ok("Hooks: auto-update, branch-guard, pre-push, env-block, migration-guard, deploy-gate, pre-compact");
388
433
  ok("Status line + spinner configured");
389
434
  ok("Environment variables + permissions");
390
435
 
@@ -395,10 +440,11 @@ async function main() {
395
440
  console.log(` ${WHITE}${member.name}${RESET} ${DIM}(${member.role})${RESET}`);
396
441
  console.log(` Skills: ${WHITE}${skills.length}${RESET}`);
397
442
  console.log(` Agents: ${WHITE}3${RESET} ${DIM}(planner, builder, verifier)${RESET}`);
398
- console.log(` Hooks: ${WHITE}6${RESET} ${DIM}(branch-guard, pre-push, env-block, migration-guard, deploy-gate, pre-compact)${RESET}`);
399
- console.log(` Rules: ${WHITE}3${RESET} ${DIM}(security, frontend, deployment)${RESET}`);
400
- console.log(` Scripts: ${WHITE}1${RESET} ${DIM}(state.js)${RESET}`);
401
- console.log(` Templates: ${WHITE}4${RESET}`);
443
+ console.log(` Hooks: ${WHITE}7${RESET} ${DIM}(auto-update, branch-guard, pre-push, env-block, migration-guard, deploy-gate, pre-compact)${RESET}`);
444
+ console.log(` Rules: ${WHITE}${fs.readdirSync(rulesDir).length}${RESET} ${DIM}(security, frontend, design-reference, deployment)${RESET}`);
445
+ console.log(` Scripts: ${WHITE}1${RESET} ${DIM}(state.js — state machine)${RESET}`);
446
+ console.log(` Knowledge: ${WHITE}3${RESET} ${DIM}(patterns, fixes, client prefs)${RESET}`);
447
+ console.log(` Templates: ${WHITE}${fs.readdirSync(tmplDir).length}${RESET}`);
402
448
  console.log(` Status line: ${GREEN}✓${RESET}`);
403
449
  console.log(` CLAUDE.md: ${GREEN}✓${RESET} ${DIM}(${member.role})${RESET}`);
404
450
 
@@ -0,0 +1,56 @@
1
+ #!/bin/bash
2
+ # Qualia auto-update — checks once per day, updates silently in background
3
+ # Runs as PreToolUse hook. Cached so it's a no-op most of the time.
4
+
5
+ CLAUDE_DIR="$HOME/.claude"
6
+ CACHE_FILE="$CLAUDE_DIR/.qualia-last-update-check"
7
+ CONFIG_FILE="$CLAUDE_DIR/.qualia-config.json"
8
+ LOCK_FILE="$CLAUDE_DIR/.qualia-updating"
9
+ MAX_AGE=86400 # 24 hours in seconds
10
+
11
+ # Exit fast if recently checked (most common path — single stat call)
12
+ if [ -f "$CACHE_FILE" ]; then
13
+ LAST_CHECK=$(cat "$CACHE_FILE" 2>/dev/null || echo 0)
14
+ NOW=$(date +%s)
15
+ AGE=$((NOW - LAST_CHECK))
16
+ if [ "$AGE" -lt "$MAX_AGE" ]; then
17
+ exit 0
18
+ fi
19
+ fi
20
+
21
+ # Exit if already updating
22
+ [ -f "$LOCK_FILE" ] && exit 0
23
+
24
+ # Update cache timestamp immediately (prevents concurrent checks)
25
+ date +%s > "$CACHE_FILE"
26
+
27
+ # Run the actual check + update in background so we don't block the user
28
+ (
29
+ trap 'rm -f "$LOCK_FILE"' EXIT
30
+ touch "$LOCK_FILE"
31
+
32
+ # Get installed version
33
+ INSTALLED=$(node -e "try{console.log(JSON.parse(require('fs').readFileSync('$CONFIG_FILE','utf8')).version)}catch{console.log('0.0.0')}" 2>/dev/null)
34
+ [ -z "$INSTALLED" ] && INSTALLED="0.0.0"
35
+
36
+ # Get latest from npm (5s timeout)
37
+ LATEST=$(npm view qualia-framework-v2 version 2>/dev/null)
38
+ [ -z "$LATEST" ] && exit 0
39
+
40
+ # Compare versions
41
+ NEEDS_UPDATE=$(node -e "
42
+ const a='$LATEST'.split('.').map(Number), b='$INSTALLED'.split('.').map(Number);
43
+ for(let i=0;i<3;i++){if(a[i]>b[i]){console.log('yes');process.exit()}if(a[i]<b[i]){process.exit()}}
44
+ " 2>/dev/null)
45
+
46
+ if [ "$NEEDS_UPDATE" = "yes" ]; then
47
+ # Get saved install code
48
+ CODE=$(node -e "try{console.log(JSON.parse(require('fs').readFileSync('$CONFIG_FILE','utf8')).code)}catch{}" 2>/dev/null)
49
+ [ -z "$CODE" ] && exit 0
50
+
51
+ # Run silent update
52
+ npx qualia-framework-v2@latest install <<< "$CODE" > /dev/null 2>&1
53
+ fi
54
+ ) &
55
+
56
+ exit 0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "qualia-framework-v2",
3
- "version": "2.3.0",
3
+ "version": "2.5.0",
4
4
  "description": "Claude Code workflow framework by Qualia Solutions. Plan, build, verify, ship.",
5
5
  "bin": {
6
6
  "qualia-framework-v2": "./bin/cli.js"
@@ -0,0 +1,179 @@
1
+ ---
2
+ globs: ["*.tsx", "*.jsx", "*.css", "*.scss"]
3
+ ---
4
+
5
+ # Design Reference — Deep Specs
6
+
7
+ Detailed values for motion, accessibility, and responsive design. Loaded alongside `frontend.md` for frontend work.
8
+
9
+ ## Motion Specification
10
+
11
+ ### Duration Table
12
+
13
+ | Action | Duration | Easing | Example |
14
+ |--------|----------|--------|---------|
15
+ | Micro-feedback | 100ms | ease-out | Button press, checkbox toggle |
16
+ | Hover/focus | 150ms | ease-out | Color change, underline appear |
17
+ | Small reveal | 200ms | ease-out | Tooltip show, dropdown open |
18
+ | Expand/collapse | 250ms | ease-in-out | Accordion, panel slide |
19
+ | Page element enter | 300ms | cubic-bezier(0, 0, 0.2, 1) | Card fade-in, section reveal |
20
+ | Page transition | 400ms | cubic-bezier(0.4, 0, 0.2, 1) | Route change, modal open |
21
+ | Complex orchestration | 500–800ms | staggered | Page load sequence |
22
+
23
+ ### Easing Curves (CSS)
24
+
25
+ ```css
26
+ --ease-standard: cubic-bezier(0.4, 0, 0.2, 1); /* General movement */
27
+ --ease-decelerate: cubic-bezier(0, 0, 0.2, 1); /* Enter screen */
28
+ --ease-accelerate: cubic-bezier(0.4, 0, 1, 1); /* Exit screen */
29
+ --ease-spring: cubic-bezier(0.34, 1.56, 0.64, 1); /* Playful bounce */
30
+ --ease-smooth: cubic-bezier(0.25, 0.1, 0.25, 1); /* Subtle shift */
31
+ ```
32
+
33
+ ### Stagger Pattern
34
+
35
+ ```css
36
+ /* Stagger children on page load */
37
+ @keyframes fadeUp {
38
+ from { opacity: 0; transform: translateY(12px); }
39
+ to { opacity: 1; transform: translateY(0); }
40
+ }
41
+
42
+ .stagger > * {
43
+ animation: fadeUp 300ms var(--ease-decelerate) both;
44
+ }
45
+ .stagger > *:nth-child(1) { animation-delay: 0ms; }
46
+ .stagger > *:nth-child(2) { animation-delay: 60ms; }
47
+ .stagger > *:nth-child(3) { animation-delay: 120ms; }
48
+ .stagger > *:nth-child(4) { animation-delay: 180ms; }
49
+ .stagger > *:nth-child(5) { animation-delay: 240ms; }
50
+ ```
51
+
52
+ ### Reduced Motion
53
+
54
+ ```css
55
+ @media (prefers-reduced-motion: reduce) {
56
+ *, *::before, *::after {
57
+ animation-duration: 0.01ms !important;
58
+ animation-iteration-count: 1 !important;
59
+ transition-duration: 0.01ms !important;
60
+ scroll-behavior: auto !important;
61
+ }
62
+ }
63
+ ```
64
+
65
+ ## WCAG AA Checklist
66
+
67
+ ### Perceivable
68
+ - [ ] All images have descriptive alt text (decorative: `alt=""` + `aria-hidden="true"`)
69
+ - [ ] Color contrast: 4.5:1 normal text, 3:1 large text (18px+ bold / 24px+)
70
+ - [ ] Color contrast: 3:1 for UI components and graphical objects
71
+ - [ ] Information not conveyed by color alone — icons, text, patterns as supplements
72
+ - [ ] Video/audio: captions or transcripts where applicable
73
+ - [ ] Text resizable to 200% without loss of content
74
+ - [ ] Content reflows at 320px viewport width (no horizontal scroll)
75
+
76
+ ### Operable
77
+ - [ ] All functionality available via keyboard (Tab, Enter, Space, Escape, Arrows)
78
+ - [ ] No keyboard traps (except intentional focus traps in modals)
79
+ - [ ] Visible focus indicator: 2px+ ring, contrasting color, no `outline: none` without replacement
80
+ - [ ] Skip navigation link as first focusable element
81
+ - [ ] Touch targets: 44x44px minimum (48x48px recommended)
82
+ - [ ] No content that flashes more than 3 times per second
83
+ - [ ] Page titles are descriptive and unique
84
+
85
+ ### Understandable
86
+ - [ ] Form inputs have visible labels (not placeholder-only)
87
+ - [ ] Error messages identify the field and describe the error
88
+ - [ ] Error suggestions explain how to fix the problem
89
+ - [ ] Required fields marked with `aria-required="true"` and visual indicator
90
+ - [ ] Language set: `<html lang="en">`
91
+ - [ ] Consistent navigation across pages
92
+ - [ ] No unexpected context changes on input
93
+
94
+ ### Robust
95
+ - [ ] Valid HTML (no duplicate IDs, proper nesting)
96
+ - [ ] ARIA used correctly: `role`, `aria-label`, `aria-describedby`, `aria-expanded`, `aria-hidden`
97
+ - [ ] Dynamic content: `aria-live="polite"` for updates, `aria-live="assertive"` for errors
98
+ - [ ] Custom components have proper roles and keyboard interaction patterns
99
+
100
+ ## Responsive Breakpoints
101
+
102
+ ### Strategy: Mobile-First with Fluid Scaling
103
+
104
+ ```css
105
+ /* Base: mobile (320px–639px) */
106
+ /* sm: 640px+ — large phone / small tablet */
107
+ /* md: 768px+ — tablet */
108
+ /* lg: 1024px+ — laptop */
109
+ /* xl: 1280px+ — desktop */
110
+ /* 2xl: 1536px+ — large desktop */
111
+ ```
112
+
113
+ ### Common Patterns
114
+
115
+ | Pattern | Mobile | Tablet | Desktop |
116
+ |---------|--------|--------|---------|
117
+ | Navigation | Hamburger + drawer | Hamburger or condensed | Full horizontal |
118
+ | Grid | 1 column | 2 columns | 3–4 columns |
119
+ | Sidebar | Hidden, overlay | Collapsible | Always visible |
120
+ | Hero | Stacked, full-width | Stacked, padded | Side-by-side |
121
+ | Table | Card view or scroll | Scroll with sticky col | Full table |
122
+ | Modal | Full screen | Centered, 80% width | Centered, max-width |
123
+ | Form | Single column | Single column | Two column for long forms |
124
+
125
+ ### Fluid Typography
126
+
127
+ ```css
128
+ /* Body */
129
+ font-size: clamp(1rem, 0.5rem + 1.5vw, 1.125rem);
130
+
131
+ /* H1 */
132
+ font-size: clamp(2rem, 1rem + 3vw, 3.75rem);
133
+
134
+ /* H2 */
135
+ font-size: clamp(1.5rem, 0.75rem + 2.25vw, 2.5rem);
136
+
137
+ /* H3 */
138
+ font-size: clamp(1.25rem, 0.75rem + 1.5vw, 1.875rem);
139
+ ```
140
+
141
+ ### Fluid Spacing
142
+
143
+ ```css
144
+ /* Section padding */
145
+ padding-inline: clamp(1rem, 5vw, 4rem);
146
+ padding-block: clamp(2rem, 8vw, 6rem);
147
+
148
+ /* Component gap */
149
+ gap: clamp(1rem, 3vw, 2rem);
150
+ ```
151
+
152
+ ## React/Next.js Performance (Critical)
153
+
154
+ ### Priority 1: Eliminate Waterfalls
155
+ - Fetch data in parallel (`Promise.all`), not sequentially
156
+ - Use Suspense boundaries to stream content progressively
157
+ - Prefetch data on hover/focus for anticipated navigation
158
+ - Colocate data fetching with the component that needs it
159
+
160
+ ### Priority 2: Bundle Size
161
+ - Import specific functions, not entire libraries (`import { format } from 'date-fns'`)
162
+ - Avoid barrel files (index.ts re-exports) — import directly from source
163
+ - Use `next/dynamic` for heavy components not needed on initial load
164
+ - Lazy-load below-fold content and non-critical features
165
+
166
+ ### Priority 3: Rendering
167
+ - Server Components by default — only add `'use client'` when needed (state, effects, browser APIs)
168
+ - Avoid unnecessary `useEffect` — derive values during render when possible
169
+ - Use CSS `content-visibility: auto` for long scrollable lists
170
+ - Images: `next/image` with proper `width`/`height` to prevent layout shift
171
+
172
+ ## Compound Component Patterns
173
+
174
+ When building reusable components:
175
+ - **No boolean prop proliferation** (`isCompact`, `showHeader`, `isRounded`) — use composition instead
176
+ - Compound components: `<Select>`, `<Select.Trigger>`, `<Select.Content>` with shared context
177
+ - Explicit variants: `<Alert.Destructive>` instead of `<Alert isDestructive>`
178
+ - Children over render props: `children` for composition, not `renderHeader`/`renderFooter`
179
+ - React 19: use `use()` instead of `useContext()`, skip `forwardRef` (ref is a regular prop)
package/rules/frontend.md CHANGED
@@ -2,31 +2,124 @@
2
2
  globs: ["*.tsx", "*.jsx", "*.css", "*.scss", "tailwind.config.*"]
3
3
  ---
4
4
 
5
- # Frontend Aesthetics
5
+ # Frontend Design Standards
6
6
 
7
- - Distinctive fonts (not Inter/Arial)
8
- - Cohesive color palette with sharp accents
9
- - CSS transitions, staggered animations
10
- - Layered backgrounds, subtle gradients
11
- - Avoid: card grids, generic heroes, blue-purple gradients
12
- - Full-width layouts — no hardcoded 1200px/1280px caps. Use fluid widths that fill the viewport with sensible padding.
7
+ These are Qualia brand standards — mandatory for every frontend component. Not suggestions.
13
8
 
14
- Note: Qualia agents MUST follow these rules when building any frontend component. These are Fawzi's brand standards, not suggestions.
9
+ ## Typography
10
+
11
+ **Never use:** Inter, Roboto, Arial, Helvetica, system-ui, Space Grotesk (overused by AI).
12
+
13
+ - Pair a distinctive display font with a refined body font
14
+ - Type scale: 12 / 14 / 16 / 18 / 20 / 24 / 30 / 36 / 48 / 60 / 72
15
+ - Body: 16px min, line-height 1.5–1.7
16
+ - Headings: line-height 1.1–1.3, letter-spacing -0.02em for large sizes
17
+ - Weight hierarchy: Regular (400) body, Medium (500) labels, Semibold (600) headings, Bold (700) display
18
+ - Prose max-width: 65ch. Everything else: fluid full-width
19
+
20
+ ## Color
21
+
22
+ - Commit to a cohesive palette — define in CSS variables
23
+ - One dominant brand color with sharp accent for CTAs
24
+ - Never: blue-purple gradients, rainbow palettes, gray-on-gray
25
+ - Dark mode: not just inverted — rethink surfaces, reduce contrast slightly
26
+ - Semantic colors: success (green), warning (amber), error (red), info (blue) — always with non-color indicator too
27
+ - All text must meet **WCAG AA** contrast: 4.5:1 normal text, 3:1 large text (18px+ bold or 24px+)
28
+
29
+ ## Layout
30
+
31
+ - Full-width layouts — no hardcoded `max-width: 1200px` or `1280px` caps
32
+ - Fluid padding: `clamp(1rem, 5vw, 4rem)` for horizontal, generous vertical
33
+ - 8px spacing grid: 4 / 8 / 12 / 16 / 24 / 32 / 48 / 64 / 96
34
+ - Tight spacing within groups, generous between sections
35
+ - Asymmetry > symmetry. Overlap, diagonal flow, grid-breaking elements when appropriate
36
+ - No card grids — use varied layouts with visual hierarchy
37
+ - No generic hero sections — make them distinctive and purposeful
38
+
39
+ ## Motion & Animation
40
+
41
+ - Hover/focus transitions: 150–200ms ease-out
42
+ - Expand/collapse: 200–300ms ease-in-out
43
+ - Page transitions: 300–500ms ease-out
44
+ - Staggered entrance animations: 50–80ms delay between items
45
+ - **Always** respect `prefers-reduced-motion: reduce` — disable non-essential animation
46
+ - Easing: `cubic-bezier(0.4, 0, 0.2, 1)` (standard), `cubic-bezier(0, 0, 0.2, 1)` (decelerate), `cubic-bezier(0.4, 0, 1, 1)` (accelerate)
47
+ - One well-orchestrated page load > scattered micro-interactions
48
+ - CSS-only for HTML projects, Motion library (`motion/react`) for React
49
+
50
+ ## States (Every Interactive Element)
51
+
52
+ - **Loading:** Skeleton or spinner on async operations — never a blank void
53
+ - **Empty:** Helpful message + action when lists/data are empty — never "No results"
54
+ - **Error:** User-friendly message + recovery action — never raw error text
55
+ - **Hover:** Visual feedback within 100ms
56
+ - **Focus:** Visible focus ring (2px+ offset, high contrast) — never `outline: none` without replacement
57
+ - **Active/Pressed:** Scale down slightly or color shift
58
+ - **Disabled:** Reduced opacity (0.5) + `cursor: not-allowed` + `aria-disabled`
59
+
60
+ ## Accessibility (WCAG AA Minimum)
61
+
62
+ - Semantic HTML: `<nav>`, `<main>`, `<article>`, `<section>`, `<aside>`, `<header>`, `<footer>` — not divs for everything
63
+ - Heading hierarchy: One `<h1>` per page, sequential order (no skipping h2→h4)
64
+ - All images: descriptive `alt` text (or `alt=""` + `aria-hidden` if decorative)
65
+ - All form inputs: visible `<label>` linked via `htmlFor` — not placeholder-only
66
+ - All interactive elements: keyboard accessible (Tab, Enter, Escape, Arrow keys)
67
+ - Touch targets: 44x44px minimum
68
+ - ARIA: use native HTML elements first. Only add ARIA when HTML semantics aren't enough
69
+ - Never rely solely on color to convey information — add icons, text, or patterns
70
+ - Skip link: `<a href="#main" class="sr-only focus:not-sr-only">` on every page
71
+ - Live regions: `aria-live="polite"` for dynamic content updates (toasts, form validation)
72
+
73
+ ## Responsive Design
74
+
75
+ - Mobile-first: base styles for mobile, `@media (min-width)` for larger screens
76
+ - Breakpoints: `sm: 640px`, `md: 768px`, `lg: 1024px`, `xl: 1280px`, `2xl: 1536px`
77
+ - Fluid typography: `clamp(1rem, 0.5rem + 1.5vw, 1.25rem)` for body, scale up for headings
78
+ - Stack on mobile, expand on desktop — never force horizontal scroll
79
+ - Test: 320px (small phone), 375px (iPhone), 768px (tablet), 1024px (laptop), 1440px (desktop)
80
+ - Images: `max-width: 100%`, `height: auto`, use `srcset` for responsive images
81
+ - Navigation: hamburger menu on mobile, expanded on desktop
82
+
83
+ ## Component Quality
84
+
85
+ - `cursor: pointer` on ALL clickable elements
86
+ - Smooth transitions (150–300ms) on all state changes
87
+ - No emoji as icons — use SVGs or icon libraries
88
+ - Buttons: clear visual hierarchy (primary, secondary, ghost, destructive)
89
+ - Inputs: visible borders, focus rings, error states with `aria-describedby`
90
+ - Links: distinguishable from text (underline or color + another indicator)
91
+ - Modals: trap focus, close on Escape, `aria-modal="true"`, restore focus on close
92
+ - Toast/notifications: `aria-live`, auto-dismiss with adequate time (5s+), dismissible
93
+
94
+ ## Anti-Patterns (Kill on Sight)
95
+
96
+ - Card grids where every card looks identical → varied layouts
97
+ - Generic hero with stock photo → distinctive, purposeful hero
98
+ - Blue-purple gradients → brand colors
99
+ - Static pages with no motion → purposeful animation
100
+ - Fixed widths → fluid responsive
101
+ - Gray text on white (#999 on #fff fails WCAG) → proper contrast
102
+ - Placeholder text shipped to production → real content or proper empty states
103
+ - `outline: none` without focus replacement → visible focus indicators
104
+ - `div` soup → semantic HTML
105
+ - Hardcoded colors scattered in JSX → CSS variables or Tailwind config
106
+
107
+ ## Design System Integration
108
+
109
+ If `.planning/DESIGN.md` exists in the project, it takes precedence over these defaults.
110
+ Read it before any frontend work. It contains project-specific: palette, typography, spacing, component patterns.
15
111
 
16
112
  ## Impeccable Design Skills (global)
17
- Use these `/commands` for design refinement on any frontend work:
18
- - `/polish` — Final detail pass before shipping (spacing, alignment, consistency)
19
- - `/bolder` — Amplify safe/boring designs to be more striking
113
+ - `/polish` Final detail pass before shipping
114
+ - `/bolder` — Amplify safe/boring designs
20
115
  - `/design-quieter` — Tone down overly aggressive designs
21
- - `/animate` — Add purposeful micro-interactions and motion
116
+ - `/animate` — Add purposeful micro-interactions
22
117
  - `/colorize` — Inject strategic color into monochrome UIs
23
118
  - `/clarify` — Fix unclear UX copy, labels, error messages
24
- - `/critique` — Design director-level review (run before shipping)
119
+ - `/critique` — Design director-level review
25
120
  - `/distill` — Strip unnecessary complexity
26
121
  - `/delight` — Add memorable touches and personality
27
122
  - `/harden` — Edge cases, overflow, i18n robustness
28
- - `/onboard` — First-time user experience flows
29
- - `/normalize` — Align with project design system
30
123
  - `/responsive` — Cross-device responsive adaptation
31
124
 
32
125
  ### Recommended workflow
@@ -0,0 +1,84 @@
1
+ ---
2
+ name: qualia-learn
3
+ description: "Save a learning, pattern, fix, or client preference to the knowledge base. Persists across projects and sessions. Trigger on 'remember this', 'save this pattern', 'learned something', 'note for future', 'client prefers', 'qualia-learn'."
4
+ ---
5
+
6
+ # /qualia-learn — Save Knowledge
7
+
8
+ Persist learnings across projects and sessions. Saved to `~/.claude/knowledge/`.
9
+
10
+ ## Usage
11
+
12
+ - `/qualia-learn` — Interactively save a learning
13
+ - `/qualia-learn {description}` — Save directly
14
+
15
+ ## Knowledge Types
16
+
17
+ ### Patterns (`learned-patterns.md`)
18
+ Recurring approaches that work (or don't). Architecture decisions, library choices, prompt patterns.
19
+
20
+ **Example:** "Supabase RLS policies need to be added in the same migration as the table — adding them later causes a window where data is unprotected."
21
+
22
+ ### Fixes (`common-fixes.md`)
23
+ Problems you've solved before. Error messages and their solutions.
24
+
25
+ **Example:** "`next/font` crash on Vercel: caused by importing font in a client component that's also used server-side. Fix: move font import to layout.tsx."
26
+
27
+ ### Client Prefs (`client-prefs.md`)
28
+ Client-specific preferences, design choices, requirements.
29
+
30
+ **Example:** "Acme Corp: prefers dark mode, hates rounded corners, logo must be SVG not PNG, primary color #FF6B00."
31
+
32
+ ## Process
33
+
34
+ ### 1. Classify
35
+
36
+ If description given, classify automatically. Otherwise ask:
37
+
38
+ ```
39
+ What did you learn?
40
+ 1. Pattern — approach that works (or doesn't)
41
+ 2. Fix — problem and its solution
42
+ 3. Client preference — client-specific requirement
43
+ ```
44
+
45
+ ### 2. Format Entry
46
+
47
+ ```markdown
48
+ ### {Title} ({date})
49
+ **Project:** {current project name or "general"}
50
+ **Context:** {brief context — what you were building when you learned this}
51
+
52
+ {The learning — be specific enough that future-you understands without context}
53
+ ```
54
+
55
+ ### 3. Append to Knowledge File
56
+
57
+ ```bash
58
+ # Append to the right file
59
+ echo "{formatted entry}" >> ~/.claude/knowledge/{type}.md
60
+ ```
61
+
62
+ - Pattern → `~/.claude/knowledge/learned-patterns.md`
63
+ - Fix → `~/.claude/knowledge/common-fixes.md`
64
+ - Client pref → `~/.claude/knowledge/client-prefs.md`
65
+
66
+ ### 4. Confirm
67
+
68
+ ```
69
+ ◆ Saved to {file}
70
+ "{title}"
71
+ ```
72
+
73
+ ## Reading Knowledge
74
+
75
+ Skills can read knowledge files for context:
76
+ ```bash
77
+ cat ~/.claude/knowledge/learned-patterns.md 2>/dev/null
78
+ cat ~/.claude/knowledge/common-fixes.md 2>/dev/null
79
+ cat ~/.claude/knowledge/client-prefs.md 2>/dev/null
80
+ ```
81
+
82
+ The `/qualia-debug` skill should check `common-fixes.md` before investigating.
83
+ The `/qualia-new` skill should check `client-prefs.md` when setting up client projects.
84
+ The `/qualia-plan` skill should check `learned-patterns.md` when planning phases.
@@ -223,6 +223,44 @@ Create Supabase project (via MCP or manual).
223
223
  **`.planning/PROJECT.md`** — use template, fill from answers:
224
224
  - Client, description, requirements (from features), out of scope, stack, design direction, decisions
225
225
 
226
+ ### Step 8a. Create Design System
227
+
228
+ Generate **`.planning/DESIGN.md`** using `templates/DESIGN.md` as the template.
229
+
230
+ Fill in based on the design direction chosen in Step 3:
231
+
232
+ **Dark & Bold:**
233
+ - Palette: dark backgrounds (#0a0a0a, #141414), vibrant accent (teal #00d4aa, amber #f59e0b, etc.)
234
+ - Typography: bold display font + clean body font (e.g., "Plus Jakarta Sans" + "DM Sans")
235
+ - Effects: glass morphism, noise textures, glow effects
236
+ - Motion: expressive — staggered fades, parallax hints
237
+
238
+ **Clean & Minimal:**
239
+ - Palette: light backgrounds (#fafafa, #ffffff), single muted accent
240
+ - Typography: refined serif or geometric sans (e.g., "Outfit" + "Source Serif 4")
241
+ - Effects: subtle shadows, thin borders
242
+ - Motion: minimal — fades only, no stagger
243
+
244
+ **Colorful & Playful:**
245
+ - Palette: vibrant multi-color, warm backgrounds
246
+ - Typography: rounded friendly fonts (e.g., "Nunito" + "Quicksand")
247
+ - Effects: gradients, rounded shapes, illustrations
248
+ - Motion: expressive — bouncy spring easing, scale on hover
249
+
250
+ **Corporate / Professional:**
251
+ - Palette: navy/charcoal base, conservative accent (blue, green)
252
+ - Typography: trustworthy geometric (e.g., "Manrope" + "IBM Plex Sans")
253
+ - Effects: clean borders, subtle shadows, structured grids
254
+ - Motion: subtle — smooth fades, no bounce
255
+
256
+ **Always include in DESIGN.md:**
257
+ - Concrete CSS variable values (not placeholders)
258
+ - Google Fonts import URL
259
+ - Spacing scale (8px grid)
260
+ - Component patterns (buttons, inputs, cards)
261
+ - Responsive approach
262
+ - Anti-patterns to avoid
263
+
226
264
  ### Step 8b. Initialize State
227
265
 
228
266
  ```bash
@@ -14,39 +14,125 @@ Run after all feature phases are verified. Makes it look production-ready.
14
14
  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
15
15
  ```
16
16
 
17
- ### 1. Critique
18
- Review the entire UI. Check:
19
- - Visual hierarchy and information architecture
20
- - Color consistency, contrast, readability
21
- - Spacing and alignment
22
- - Component consistency across pages
23
-
24
- ### 2. Polish
25
- Fix what critique found:
26
- - Alignment and spacing issues
27
- - Font consistency
28
- - Color palette adherence (Qualia teal brand)
29
- - Transition and hover state consistency
17
+ ### 0. Load Design Context
18
+
19
+ ```bash
20
+ cat .planning/DESIGN.md 2>/dev/null || echo "NO_DESIGN"
21
+ ```
22
+
23
+ If DESIGN.md exists → use it as the standard. If not → use Qualia defaults from `rules/frontend.md`.
24
+
25
+ Read EVERY frontend file before modifying. No blind edits.
26
+
27
+ ### 1. Critique (Structured Audit)
28
+
29
+ Review the entire UI against this checklist. Check each item, note violations with file:line.
30
+
31
+ **Typography:**
32
+ - [ ] No generic fonts (Inter, Roboto, Arial, system-ui, Space Grotesk)
33
+ - [ ] Proper type scale with clear hierarchy (display → heading → body → caption)
34
+ - [ ] Body text: 16px+, line-height 1.5–1.7
35
+ - [ ] Headings: tighter line-height (1.1–1.3), negative letter-spacing for large sizes
36
+ - [ ] Prose max-width: 65ch
37
+ - [ ] Font weights used for hierarchy (Regular, Medium, Semibold, Bold)
38
+
39
+ **Color & Contrast:**
40
+ - [ ] Cohesive palette via CSS variables (not scattered hex values)
41
+ - [ ] All text passes WCAG AA contrast (4.5:1 normal, 3:1 large)
42
+ - [ ] CTA buttons use accent color — stand out from the page
43
+ - [ ] No blue-purple gradients, no rainbow palettes
44
+ - [ ] Dark mode: rethought surfaces (not just inverted)
45
+ - [ ] Semantic colors used consistently (success=green, error=red, warning=amber)
46
+
47
+ **Layout & Spacing:**
48
+ - [ ] Full-width fluid layouts — no hardcoded max-width caps
49
+ - [ ] 8px spacing grid followed consistently
50
+ - [ ] Tight spacing within groups, generous between sections
51
+ - [ ] Fluid padding: `clamp(1rem, 5vw, 4rem)` horizontal
52
+ - [ ] No identical card grids — varied visual hierarchy
53
+ - [ ] No generic heroes — purposeful, distinctive
54
+
55
+ **Interactive States:**
56
+ - [ ] Every button/link: hover (color shift, 150ms), focus (visible ring), active (press feedback), disabled
57
+ - [ ] Loading: skeleton or spinner on all async operations
58
+ - [ ] Empty: helpful message + action on empty lists/data
59
+ - [ ] Error: user-friendly message + recovery action on failed fetches
60
+ - [ ] Form validation: inline errors with `aria-describedby`
61
+
62
+ **Motion:**
63
+ - [ ] Hover/focus: 150–200ms transitions
64
+ - [ ] Page load: staggered entrance animations (50–80ms delay)
65
+ - [ ] Expand/collapse: 250ms ease-in-out
66
+ - [ ] `prefers-reduced-motion` respected (no animation for users who opt out)
67
+ - [ ] No jank: transforms and opacity only for animated properties
68
+
69
+ **Accessibility:**
70
+ - [ ] Semantic HTML: `nav`, `main`, `section`, `article`, `header`, `footer`
71
+ - [ ] One `h1` per page, sequential heading hierarchy
72
+ - [ ] All images: descriptive `alt` (or `alt=""` + `aria-hidden` if decorative)
73
+ - [ ] All form inputs: visible `<label>` with `htmlFor` — not placeholder-only
74
+ - [ ] All interactive elements: keyboard accessible (Tab/Enter/Escape)
75
+ - [ ] Touch targets: 44px minimum
76
+ - [ ] Skip link: `<a href="#main">` as first focusable element
77
+ - [ ] No `outline: none` without focus replacement
78
+ - [ ] `<html lang="en">` set
79
+ - [ ] Color not sole information carrier — icons/text as supplements
80
+
81
+ **Responsive:**
82
+ - [ ] Mobile-first approach (base styles for mobile, min-width breakpoints for larger)
83
+ - [ ] No horizontal scroll at 320px
84
+ - [ ] Navigation: hamburger on mobile, expanded on desktop
85
+ - [ ] Touch targets adequate on mobile (44px min)
86
+ - [ ] Fluid typography with `clamp()`
87
+ - [ ] Images: `max-width: 100%`, responsive srcset where needed
88
+ - [ ] Tables: card view or horizontal scroll on mobile
89
+
90
+ **Performance:**
91
+ - [ ] Server Components by default — `'use client'` only when needed
92
+ - [ ] Images via `next/image` with width/height
93
+ - [ ] No barrel file imports — direct imports from source
94
+ - [ ] Heavy components lazy-loaded with `next/dynamic`
95
+ - [ ] Data fetched in parallel, not sequentially
96
+
97
+ ### 2. Fix Everything
98
+
99
+ Work through violations from the critique. Fix each category:
100
+
101
+ 1. Typography first (sets the visual foundation)
102
+ 2. Color & contrast (palette coherence)
103
+ 3. Layout & spacing (structural fixes)
104
+ 4. Interactive states (loading, empty, error, hover, focus)
105
+ 5. Motion (transitions, entrance animations, reduced-motion)
106
+ 6. Accessibility (semantic HTML, ARIA, keyboard, labels)
107
+ 7. Responsive (mobile breakpoints, fluid sizing)
108
+ 8. Performance (quick wins — image optimization, dynamic imports)
30
109
 
31
110
  ### 3. Harden
32
- Edge cases and robustness:
33
- - Empty states (no data, loading, error)
34
- - Text overflow, long content
35
- - Mobile responsive (check all breakpoints)
36
- - Error messages (user-friendly, not technical)
37
111
 
38
- ### 4. Qualia Frontend Rules
39
- - Distinctive fonts (not Inter/Arial)
40
- - Cohesive color palette with sharp accents
41
- - CSS transitions, staggered animations
42
- - Full-width layouts, no hardcoded max-width caps
43
- - No card grids, no generic heroes, no blue-purple gradients
112
+ After polish, stress-test edge cases:
113
+ - Long text content (overflow, truncation, word-break)
114
+ - Extremely long usernames or email addresses
115
+ - Empty data everywhere simultaneously
116
+ - Error state on every fetch simultaneously
117
+ - 320px viewport width
118
+ - Keyboard-only navigation through entire flow
119
+ - Screen reader landmarks check (semantic HTML)
120
+ - Right-to-left text (if i18n is planned)
121
+ - Slow network (loading states visible, no flash of empty content)
44
122
 
45
- ### 5. Commit & Update
123
+ ### 4. Verify
124
+
125
+ ```bash
126
+ npx tsc --noEmit 2>&1 | head -20
127
+ ```
128
+
129
+ Fix any TypeScript errors before committing.
130
+
131
+ ### 5. Commit & Transition
46
132
 
47
133
  ```bash
48
134
  git add {changed files}
49
- git commit -m "polish: design and UX pass"
135
+ git commit -m "polish: design and UX pass — typography, accessibility, responsive, states"
50
136
  ```
51
137
 
52
138
  ```bash
@@ -54,6 +140,22 @@ node ~/.claude/bin/state.js transition --to polished
54
140
  ```
55
141
  Do NOT manually edit STATE.md or tracking.json — state.js handles both.
56
142
 
143
+ ### 6. Report
144
+
57
145
  ```
146
+ ◆ QUALIA ► POLISHED
147
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
148
+ Files modified: {N}
149
+
150
+ Typography ✓ {brief}
151
+ Color ✓ {brief}
152
+ Layout ✓ {brief}
153
+ States ✓ {brief}
154
+ Motion ✓ {brief}
155
+ Accessibility ✓ {brief}
156
+ Responsive ✓ {brief}
157
+ Performance ✓ {brief}
158
+ Hardening ✓ {brief}
159
+
58
160
  → Run: /qualia-ship
59
161
  ```
@@ -5,7 +5,7 @@ description: "Generate session report and commit to repo. Mandatory before clock
5
5
 
6
6
  # /qualia-report — Session Report
7
7
 
8
- Generate a concise report of what was done. Committed to git for the ERP to read.
8
+ Generate a concise report of what was done. Committed to git and uploaded to the ERP for clock-out.
9
9
 
10
10
  ## Process
11
11
 
@@ -69,7 +69,28 @@ git commit -m "report: session {YYYY-MM-DD}"
69
69
  git push
70
70
  ```
71
71
 
72
- ### 5. Update State
72
+ ### 5. Upload to ERP
73
+
74
+ **This step is MANDATORY** — the clock-out modal requires the report to be uploaded.
75
+
76
+ ```bash
77
+ ERP_URL="https://portal.qualiasolutions.net"
78
+ API_KEY=$(cat ~/.claude/.erp-api-key 2>/dev/null)
79
+ REPORT_FILE=".planning/reports/report-{date}.md"
80
+ EMAIL=$(git config user.email)
81
+ PROJECT=$(basename $(pwd))
82
+
83
+ curl -s -X POST "$ERP_URL/api/claude/report-upload" \
84
+ -H "X-API-Key: $API_KEY" \
85
+ -F "file=@$REPORT_FILE" \
86
+ -F "employee_email=$EMAIL" \
87
+ -F "project_name=$PROJECT"
88
+ ```
89
+
90
+ If the upload succeeds, print: "Report uploaded to ERP. You can now clock out."
91
+ If it fails (no API key, network error), print the error and tell the employee to ask Fawzi.
92
+
93
+ ### 6. Update State
73
94
 
74
95
  ```bash
75
96
  node ~/.claude/bin/state.js transition --to activity --notes "Session report generated"
@@ -0,0 +1,137 @@
1
+ # Design System — {Project Name}
2
+
3
+ > Generated during project setup. This is the source of truth for all frontend work.
4
+ > Builder agents read this before writing any component. Update it as design evolves.
5
+
6
+ ## Brand
7
+
8
+ - **Tone:** {dark-bold | clean-minimal | colorful-playful | corporate-professional}
9
+ - **Personality:** {1-2 sentences describing the feel — e.g., "Confident and technical, like a Bloomberg terminal meets a luxury brand"}
10
+ - **Industry:** {e.g., fintech, healthcare, SaaS, e-commerce}
11
+
12
+ ## Color System
13
+
14
+ ```css
15
+ :root {
16
+ /* Primary — brand identity */
17
+ --color-primary: {value};
18
+ --color-primary-hover: {value};
19
+ --color-primary-subtle: {value}; /* backgrounds, badges */
20
+
21
+ /* Accent — CTAs, highlights */
22
+ --color-accent: {value};
23
+ --color-accent-hover: {value};
24
+
25
+ /* Neutral — text, borders, backgrounds */
26
+ --color-bg: {value};
27
+ --color-bg-subtle: {value}; /* cards, raised surfaces */
28
+ --color-bg-muted: {value}; /* disabled, secondary surfaces */
29
+ --color-text: {value};
30
+ --color-text-muted: {value}; /* secondary text */
31
+ --color-text-subtle: {value}; /* placeholders, hints */
32
+ --color-border: {value};
33
+ --color-border-subtle: {value};
34
+
35
+ /* Semantic */
36
+ --color-success: {value};
37
+ --color-warning: {value};
38
+ --color-error: {value};
39
+ --color-info: {value};
40
+ }
41
+
42
+ /* Dark mode overrides */
43
+ [data-theme="dark"] {
44
+ --color-bg: {value};
45
+ --color-bg-subtle: {value};
46
+ --color-text: {value};
47
+ /* ... override all tokens ... */
48
+ }
49
+ ```
50
+
51
+ ## Typography
52
+
53
+ ```css
54
+ :root {
55
+ /* Font families */
56
+ --font-display: '{Display Font}', {fallback}; /* Hero text, page titles */
57
+ --font-heading: '{Heading Font}', {fallback}; /* Section headings */
58
+ --font-body: '{Body Font}', {fallback}; /* Paragraphs, UI text */
59
+ --font-mono: '{Mono Font}', monospace; /* Code, data */
60
+
61
+ /* Scale */
62
+ --text-xs: clamp(0.75rem, 0.7rem + 0.25vw, 0.8rem);
63
+ --text-sm: clamp(0.875rem, 0.8rem + 0.4vw, 0.9rem);
64
+ --text-base: clamp(1rem, 0.5rem + 1.5vw, 1.125rem);
65
+ --text-lg: clamp(1.125rem, 0.75rem + 1.2vw, 1.25rem);
66
+ --text-xl: clamp(1.25rem, 0.75rem + 1.5vw, 1.5rem);
67
+ --text-2xl: clamp(1.5rem, 0.75rem + 2.25vw, 2rem);
68
+ --text-3xl: clamp(1.875rem, 1rem + 2.5vw, 2.5rem);
69
+ --text-4xl: clamp(2.25rem, 1rem + 3vw, 3rem);
70
+ --text-5xl: clamp(3rem, 1rem + 4vw, 4rem);
71
+ }
72
+ ```
73
+
74
+ **Google Fonts import:** `{URL}`
75
+
76
+ ## Spacing Scale
77
+
78
+ Based on 8px grid: `4 / 8 / 12 / 16 / 24 / 32 / 48 / 64 / 96 / 128`
79
+
80
+ - **Within components:** 8–16px
81
+ - **Between related elements:** 16–24px
82
+ - **Between sections:** 48–96px
83
+ - **Page padding:** `clamp(1rem, 5vw, 4rem)` horizontal
84
+
85
+ ## Motion
86
+
87
+ - **Approach:** {minimal | subtle | expressive}
88
+ - **Page load:** staggered fade-up, 60ms delay between elements
89
+ - **Hover/focus:** 150ms ease-out
90
+ - **Expand/collapse:** 250ms ease-in-out
91
+ - **Page transitions:** 400ms ease-out
92
+ - **Reduced motion:** all non-essential animations disabled
93
+
94
+ ## Component Patterns
95
+
96
+ ### Buttons
97
+ - **Primary:** solid {accent} background, white text, rounded-{radius}
98
+ - **Secondary:** bordered, transparent background
99
+ - **Ghost:** text-only, hover background
100
+ - **Destructive:** red variant for dangerous actions
101
+ - **Sizes:** sm (32px), md (40px), lg (48px)
102
+
103
+ ### Inputs
104
+ - Border: 1px solid var(--color-border)
105
+ - Focus: 2px ring var(--color-primary)
106
+ - Error: red border + error text below with `aria-describedby`
107
+ - Height: 40px (md), 48px (lg)
108
+
109
+ ### Cards/Surfaces
110
+ - Background: var(--color-bg-subtle)
111
+ - Border: 1px solid var(--color-border-subtle) or shadow
112
+ - Border-radius: {value}
113
+ - No identical card grids — vary layout and emphasis
114
+
115
+ ## Responsive Approach
116
+
117
+ - **Strategy:** mobile-first
118
+ - **Primary breakpoints:** 768px (tablet), 1024px (desktop)
119
+ - **Navigation:** hamburger on mobile, expanded on desktop
120
+ - **Layout:** single column mobile → multi-column desktop
121
+ - **Touch targets:** 44px minimum on mobile
122
+
123
+ ## Visual Effects
124
+
125
+ - {e.g., "Noise texture overlay at 3% opacity on hero sections"}
126
+ - {e.g., "Glass-morphism on floating elements: backdrop-blur-xl bg-white/80"}
127
+ - {e.g., "Gradient mesh on hero: radial-gradient from primary to transparent"}
128
+ - {e.g., "Decorative geometric shapes as background accents"}
129
+
130
+ ## Anti-Patterns (Don't Do This)
131
+
132
+ - No Inter, Roboto, Arial, system-ui fonts
133
+ - No blue-purple gradients
134
+ - No identical card grids
135
+ - No generic stock-photo heroes
136
+ - No hardcoded max-width containers (use fluid layouts)
137
+ - No gray-on-gray low-contrast text