qualia-framework 3.2.0 → 3.3.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 +3 -4
- package/README.md +59 -23
- package/agents/plan-checker.md +158 -0
- package/agents/planner.md +52 -0
- package/agents/research-synthesizer.md +86 -0
- package/agents/researcher.md +119 -0
- package/agents/roadmapper.md +157 -0
- package/agents/verifier.md +180 -32
- package/bin/cli.js +403 -9
- package/bin/install.js +219 -70
- package/bin/qualia-ui.js +11 -11
- package/bin/state.js +200 -6
- package/bin/statusline.js +4 -4
- package/docs/erp-contract.md +161 -0
- package/hooks/branch-guard.js +23 -2
- package/hooks/migration-guard.js +23 -0
- package/hooks/pre-compact.js +20 -0
- package/hooks/pre-deploy-gate.js +39 -0
- package/hooks/pre-push.js +20 -0
- package/hooks/session-start.js +16 -43
- package/package.json +6 -4
- package/references/questioning.md +123 -0
- package/rules/infrastructure.md +87 -0
- package/skills/qualia/SKILL.md +1 -0
- package/skills/qualia-build/SKILL.md +18 -0
- package/skills/qualia-design/SKILL.md +14 -8
- package/skills/qualia-discuss/SKILL.md +115 -0
- package/skills/qualia-help/SKILL.md +60 -0
- package/skills/qualia-learn/SKILL.md +27 -4
- package/skills/qualia-map/SKILL.md +145 -0
- package/skills/qualia-milestone/SKILL.md +148 -0
- package/skills/qualia-new/SKILL.md +374 -229
- package/skills/qualia-plan/SKILL.md +135 -30
- package/skills/qualia-polish/SKILL.md +167 -117
- package/skills/qualia-report/SKILL.md +17 -8
- package/skills/qualia-research/SKILL.md +124 -0
- package/skills/qualia-review/SKILL.md +126 -41
- package/skills/qualia-test/SKILL.md +134 -0
- package/skills/qualia-verify/SKILL.md +1 -1
- package/templates/DESIGN.md +440 -102
- package/templates/help.html +476 -0
- package/templates/phase-context.md +48 -0
- package/templates/plan.md +14 -0
- package/templates/projects/ai-agent.md +55 -0
- package/templates/projects/mobile-app.md +56 -0
- package/templates/projects/voice-agent.md +55 -0
- package/templates/projects/website.md +58 -0
- package/templates/requirements.md +69 -0
- package/templates/research-project/ARCHITECTURE.md +70 -0
- package/templates/research-project/FEATURES.md +60 -0
- package/templates/research-project/PITFALLS.md +73 -0
- package/templates/research-project/STACK.md +51 -0
- package/templates/research-project/SUMMARY.md +86 -0
- package/templates/roadmap.md +71 -0
- package/tests/bin.test.sh +20 -6
- package/tests/hooks.test.sh +76 -7
- package/tests/runner.js +1915 -0
- package/tests/state.test.sh +189 -11
|
@@ -1,101 +1,206 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: qualia-plan
|
|
3
|
-
description: "Plan the current phase — spawns planner
|
|
3
|
+
description: "Plan the current phase — spawns planner, validates with plan-checker in a revision loop (max 3), optionally runs discuss/research first. Use when ready to plan a phase."
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# /qualia-plan — Plan a Phase
|
|
7
7
|
|
|
8
|
-
Spawn a planner agent to break the current phase into executable tasks.
|
|
8
|
+
Spawn a planner agent to break the current phase into executable tasks, then validate the plan with a checker (up to 3 revision cycles) before routing to build.
|
|
9
9
|
|
|
10
10
|
## Usage
|
|
11
|
+
|
|
11
12
|
`/qualia-plan` — plan the next unplanned phase
|
|
12
|
-
`/qualia-plan {N}` — plan specific phase
|
|
13
|
+
`/qualia-plan {N}` — plan specific phase N
|
|
13
14
|
`/qualia-plan {N} --gaps` — plan fixes for verification failures
|
|
15
|
+
`/qualia-plan {N} --skip-check` — skip the plan-checker validation loop (not recommended)
|
|
14
16
|
|
|
15
17
|
## Process
|
|
16
18
|
|
|
17
|
-
### 1. Determine Phase & Load
|
|
19
|
+
### 1. Determine Phase & Load Context
|
|
18
20
|
|
|
19
21
|
```bash
|
|
20
22
|
cat .planning/STATE.md 2>/dev/null
|
|
23
|
+
cat .planning/ROADMAP.md 2>/dev/null
|
|
24
|
+
cat .planning/PROJECT.md 2>/dev/null
|
|
21
25
|
cat ~/.claude/knowledge/learned-patterns.md 2>/dev/null
|
|
22
26
|
cat ~/.claude/knowledge/client-prefs.md 2>/dev/null
|
|
23
27
|
```
|
|
24
28
|
|
|
25
29
|
If no phase number given, use the current phase from STATE.md.
|
|
26
|
-
If any learned patterns apply to this phase's work, pass them to the planner in the spawn prompt under a `## Relevant Learnings` section.
|
|
27
|
-
If this is a client project and `client-prefs.md` has an entry for the client, include those preferences in the planner context.
|
|
28
30
|
|
|
29
|
-
|
|
31
|
+
**Read phase-specific context if it exists:**
|
|
32
|
+
```bash
|
|
33
|
+
cat .planning/phase-{N}-context.md 2>/dev/null # from /qualia-discuss
|
|
34
|
+
cat .planning/phase-{N}-research.md 2>/dev/null # from /qualia-research
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
### 2. Optional: Suggest Deeper Prep
|
|
38
|
+
|
|
39
|
+
**If ROADMAP.md marked this phase as a "research flag" AND no phase-{N}-research.md exists:**
|
|
40
|
+
|
|
41
|
+
- header: "Research first?"
|
|
42
|
+
- question: "This phase was flagged for deeper research. Run /qualia-research {N} first?"
|
|
43
|
+
- options:
|
|
44
|
+
- "Yes, research first" — Run /qualia-research {N} inline, then continue
|
|
45
|
+
- "Skip, plan directly" — I know enough
|
|
46
|
+
|
|
47
|
+
**If phase involves compliance/regulatory/architectural stakes AND no phase-{N}-context.md exists:**
|
|
48
|
+
|
|
49
|
+
Briefly suggest: *"Want to run /qualia-discuss {N} first to lock decisions? Optional."*
|
|
50
|
+
|
|
51
|
+
Don't force it. Some phases don't need it.
|
|
52
|
+
|
|
53
|
+
### 3. Spawn Planner (Fresh Context)
|
|
30
54
|
|
|
31
55
|
```bash
|
|
32
|
-
node ~/.claude/bin/qualia-ui.js banner plan {N} "{phase name from
|
|
56
|
+
node ~/.claude/bin/qualia-ui.js banner plan {N} "{phase name from ROADMAP.md}"
|
|
33
57
|
node ~/.claude/bin/qualia-ui.js spawn planner "Breaking phase into tasks..."
|
|
34
58
|
```
|
|
35
59
|
|
|
36
|
-
Spawn
|
|
60
|
+
Spawn the planner:
|
|
37
61
|
|
|
38
62
|
```
|
|
39
63
|
Agent(prompt="
|
|
40
|
-
Read your role:
|
|
64
|
+
Read your role: @~/.claude/agents/qualia-planner.md
|
|
41
65
|
|
|
42
|
-
|
|
66
|
+
<project_context>
|
|
43
67
|
@.planning/PROJECT.md
|
|
68
|
+
</project_context>
|
|
44
69
|
|
|
45
|
-
|
|
70
|
+
<current_state>
|
|
46
71
|
@.planning/STATE.md
|
|
72
|
+
</current_state>
|
|
73
|
+
|
|
74
|
+
<phase_details>
|
|
75
|
+
Phase {N} from ROADMAP.md:
|
|
76
|
+
@.planning/ROADMAP.md
|
|
47
77
|
|
|
48
|
-
|
|
49
|
-
|
|
78
|
+
Goal: {goal from ROADMAP.md}
|
|
79
|
+
Requirements: {REQ-IDs from ROADMAP.md}
|
|
80
|
+
Success criteria: {success criteria from ROADMAP.md}
|
|
81
|
+
</phase_details>
|
|
50
82
|
|
|
51
|
-
|
|
83
|
+
<locked_decisions>
|
|
84
|
+
{if phase-{N}-context.md exists, inline its Locked Decisions section; else 'none'}
|
|
85
|
+
</locked_decisions>
|
|
52
86
|
|
|
53
|
-
|
|
87
|
+
<research_findings>
|
|
88
|
+
{if phase-{N}-research.md exists, inline its recommendation; else 'none'}
|
|
89
|
+
</research_findings>
|
|
90
|
+
|
|
91
|
+
{If --gaps: Also read @.planning/phase-{N}-verification.md for failures to fix. Create gap-closure plan.}
|
|
92
|
+
|
|
93
|
+
<relevant_learnings>
|
|
94
|
+
{inline any applicable patterns from knowledge/learned-patterns.md}
|
|
95
|
+
</relevant_learnings>
|
|
96
|
+
|
|
97
|
+
Create the plan at .planning/phase-{N}-plan.md (or .planning/phase-{N}-gaps-plan.md for --gaps).
|
|
54
98
|
", subagent_type="qualia-planner", description="Plan phase {N}")
|
|
55
99
|
```
|
|
56
100
|
|
|
57
|
-
###
|
|
101
|
+
### 4. Validate the Plan (unless --skip-check)
|
|
102
|
+
|
|
103
|
+
Read the generated plan. Spawn the plan-checker:
|
|
104
|
+
|
|
105
|
+
```
|
|
106
|
+
Agent(prompt="
|
|
107
|
+
Read your role: @~/.claude/agents/qualia-plan-checker.md
|
|
108
|
+
|
|
109
|
+
<plan_path>.planning/phase-{N}-plan.md</plan_path>
|
|
110
|
+
<phase_goal>{goal from ROADMAP.md}</phase_goal>
|
|
111
|
+
<success_criteria>{criteria from ROADMAP.md}</success_criteria>
|
|
112
|
+
<project_context>@.planning/PROJECT.md</project_context>
|
|
113
|
+
|
|
114
|
+
Validate against the 7 rules. Return PASS or REVISE with structured issues.
|
|
115
|
+
", subagent_type="qualia-plan-checker", description="Check plan phase {N}")
|
|
116
|
+
```
|
|
58
117
|
|
|
59
|
-
|
|
118
|
+
**Revision loop (max 3 iterations):**
|
|
119
|
+
|
|
120
|
+
- Iteration 1: Check → if REVISE, re-spawn planner with checker issues
|
|
121
|
+
- Iteration 2: Re-check → if REVISE, re-spawn planner with new issues
|
|
122
|
+
- Iteration 3: Final check → if REVISE or BLOCKED, escalate to user
|
|
123
|
+
|
|
124
|
+
For each revision:
|
|
125
|
+
|
|
126
|
+
```
|
|
127
|
+
Agent(prompt="
|
|
128
|
+
Read your role: @~/.claude/agents/qualia-planner.md
|
|
129
|
+
|
|
130
|
+
<revision_mode>true</revision_mode>
|
|
131
|
+
<current_plan>@.planning/phase-{N}-plan.md</current_plan>
|
|
132
|
+
<checker_feedback>
|
|
133
|
+
{inline REVISE output from plan-checker}
|
|
134
|
+
</checker_feedback>
|
|
135
|
+
|
|
136
|
+
Revise the plan in place. Address every issue. Do NOT add new tasks or change scope
|
|
137
|
+
— only fix what the checker flagged.
|
|
138
|
+
", subagent_type="qualia-planner", description="Revise plan phase {N}")
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
After revision, spawn the checker again. Max 3 total revision cycles.
|
|
142
|
+
|
|
143
|
+
**If checker returns BLOCKED after 3 cycles:**
|
|
144
|
+
|
|
145
|
+
```bash
|
|
146
|
+
node ~/.claude/bin/qualia-ui.js fail "Plan failed validation after 3 revisions"
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
Show the remaining issues. Ask:
|
|
150
|
+
- "Skip validation and proceed anyway" (use `--skip-check`)
|
|
151
|
+
- "Adjust the roadmap" (phase scope may be wrong)
|
|
152
|
+
- "Adjust the phase goal" (success criteria may be under-specified)
|
|
153
|
+
|
|
154
|
+
### 5. Present Final Plan
|
|
60
155
|
|
|
61
156
|
```bash
|
|
62
157
|
node ~/.claude/bin/qualia-ui.js divider
|
|
63
158
|
node ~/.claude/bin/qualia-ui.js ok "Plan ready: {count} tasks across {count} waves"
|
|
64
159
|
```
|
|
65
160
|
|
|
66
|
-
|
|
67
|
-
|
|
161
|
+
For each wave:
|
|
68
162
|
```bash
|
|
69
|
-
node ~/.claude/bin/qualia-ui.js wave {wave_num} {wave_total} {
|
|
163
|
+
node ~/.claude/bin/qualia-ui.js wave {wave_num} {wave_total} {task_count}
|
|
70
164
|
node ~/.claude/bin/qualia-ui.js task 1 "{task title}"
|
|
71
165
|
node ~/.claude/bin/qualia-ui.js task 2 "{task title}"
|
|
72
166
|
```
|
|
73
167
|
|
|
74
|
-
End with
|
|
168
|
+
End with plain text: *"Approve? (yes / adjust)"*
|
|
75
169
|
|
|
76
|
-
If "adjust" — get feedback, re-spawn planner with revision context.
|
|
170
|
+
If "adjust" — get feedback, re-spawn planner with revision context, re-validate.
|
|
77
171
|
|
|
78
|
-
###
|
|
172
|
+
### 6. Update State
|
|
79
173
|
|
|
80
174
|
```bash
|
|
81
175
|
node ~/.claude/bin/state.js transition --to planned --phase {N}
|
|
82
176
|
```
|
|
83
|
-
|
|
84
|
-
Do NOT manually edit STATE.md or tracking.json
|
|
177
|
+
|
|
178
|
+
If state.js returns an error, show it and stop. Do NOT manually edit STATE.md or tracking.json.
|
|
179
|
+
|
|
180
|
+
### 7. Route
|
|
85
181
|
|
|
86
182
|
```bash
|
|
87
183
|
node ~/.claude/bin/qualia-ui.js end "PHASE {N} PLANNED" "/qualia-build {N}"
|
|
88
184
|
```
|
|
89
185
|
|
|
90
|
-
|
|
186
|
+
## Gap Closure Mode (`--gaps`)
|
|
91
187
|
|
|
92
188
|
When invoked as `/qualia-plan {N} --gaps`, the planner is in gap-closure mode:
|
|
93
189
|
|
|
94
190
|
1. Read `.planning/phase-{N}-verification.md` — extract ONLY the FAIL items
|
|
95
191
|
2. For each FAIL item, create a targeted fix task:
|
|
96
|
-
- **Files:**
|
|
97
|
-
- **Action:**
|
|
98
|
-
- **Done when:**
|
|
192
|
+
- **Files:** specific files that failed verification
|
|
193
|
+
- **Action:** specific fix (not "fix auth" — "add session persistence check in src/lib/auth.ts signIn function")
|
|
194
|
+
- **Done when:** the exact verification criterion that previously failed, restated
|
|
99
195
|
3. Do NOT re-plan passing items. Do NOT add new features. Gap plans are surgical.
|
|
100
196
|
4. Write to `.planning/phase-{N}-gaps-plan.md` (separate from original plan)
|
|
101
197
|
5. All gap tasks are Wave 1 (parallel) unless they share files
|
|
198
|
+
6. Plan-checker still validates the gap plan — same 7 rules apply
|
|
199
|
+
|
|
200
|
+
## Rules
|
|
201
|
+
|
|
202
|
+
1. **Plan-checker is mandatory by default.** Only skip with `--skip-check`, and only if you know what you're doing.
|
|
203
|
+
2. **Max 3 revision cycles.** After 3 failed checks, escalate — the phase scope is probably wrong.
|
|
204
|
+
3. **Honor locked decisions.** If phase-{N}-context.md exists, its locked decisions are non-negotiable.
|
|
205
|
+
4. **One plan file per phase.** Don't create phase-1-plan.md AND phase-1-plan-v2.md. Edit in place.
|
|
206
|
+
5. **Revision is surgical.** When revising, only fix what the checker flagged — no scope creep.
|
|
@@ -1,11 +1,24 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: qualia-polish
|
|
3
|
-
description: "Design and UX pass —
|
|
3
|
+
description: "Design and UX pass — anti-AI-slop, genuine craft, responsive, accessible. Run after all phases are verified."
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# /qualia-polish — Design Pass
|
|
7
7
|
|
|
8
|
-
Run after all feature phases are verified.
|
|
8
|
+
Makes it look like a human designer built it. Kills AI slop. Run after all feature phases are verified.
|
|
9
|
+
|
|
10
|
+
## The Standard
|
|
11
|
+
|
|
12
|
+
Every site Qualia ships must feel **designed, not generated.** AI-generated sites have tells:
|
|
13
|
+
- Identical card grids with rounded corners and soft shadows
|
|
14
|
+
- Blue-purple gradients on everything
|
|
15
|
+
- Inter/system-ui font with no hierarchy
|
|
16
|
+
- Generic hero with centered text and a stock gradient background
|
|
17
|
+
- Fixed-width containers leaving dead space on wide screens
|
|
18
|
+
- No motion, no personality, no opinion
|
|
19
|
+
- Perfect symmetry everywhere (real design has tension)
|
|
20
|
+
|
|
21
|
+
**Kill all of these.** A Qualia site should make someone ask "who designed this?" — not "which template is this?"
|
|
9
22
|
|
|
10
23
|
## Process
|
|
11
24
|
|
|
@@ -19,139 +32,176 @@ node ~/.claude/bin/qualia-ui.js banner polish
|
|
|
19
32
|
cat .planning/DESIGN.md 2>/dev/null || echo "NO_DESIGN"
|
|
20
33
|
```
|
|
21
34
|
|
|
22
|
-
If DESIGN.md exists →
|
|
35
|
+
If DESIGN.md exists → it's the standard. Read ALL 12 sections. Key sections for polish:
|
|
36
|
+
- §1 Visual Theme — the feel and signature details
|
|
37
|
+
- §2 Color Palette — exact hex values, CSS variables, contrast ratios
|
|
38
|
+
- §3 Typography — hierarchy table with exact sizes/weights/spacing
|
|
39
|
+
- §4 Components — exact button/card/input/badge specs
|
|
40
|
+
- §5 Layout — spacing scale, grid strategy
|
|
41
|
+
- §6 Depth & Elevation — shadow levels with exact rgba values
|
|
42
|
+
- §7 Do's/Don'ts — brand-specific guardrails
|
|
43
|
+
- §9 Agent Prompt Guide — quick reference for common patterns
|
|
44
|
+
- §10 Accessibility — WCAG checklist
|
|
45
|
+
- §11 Hardening — stress-test criteria
|
|
46
|
+
- §12 Anti-Slop Detection — grep patterns for automated checks
|
|
47
|
+
|
|
48
|
+
If no DESIGN.md → use `rules/frontend.md` defaults.
|
|
23
49
|
|
|
24
50
|
Read EVERY frontend file before modifying. No blind edits.
|
|
25
51
|
|
|
26
|
-
### 1.
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
**Typography:**
|
|
31
|
-
- [ ] No generic fonts (Inter, Roboto, Arial, system-ui, Space Grotesk)
|
|
32
|
-
- [ ] Proper type scale with clear hierarchy (display → heading → body → caption)
|
|
33
|
-
- [ ] Body text: 16px+, line-height 1.5–1.7
|
|
34
|
-
- [ ] Headings: tighter line-height (1.1–1.3), negative letter-spacing for large sizes
|
|
35
|
-
- [ ] Prose max-width: 65ch
|
|
36
|
-
- [ ] Font weights used for hierarchy (Regular, Medium, Semibold, Bold)
|
|
37
|
-
|
|
38
|
-
**Color & Contrast:**
|
|
39
|
-
- [ ] Cohesive palette via CSS variables (not scattered hex values)
|
|
40
|
-
- [ ] All text passes WCAG AA contrast (4.5:1 normal, 3:1 large)
|
|
41
|
-
- [ ] CTA buttons use accent color — stand out from the page
|
|
42
|
-
- [ ] No blue-purple gradients, no rainbow palettes
|
|
43
|
-
- [ ] Dark mode: rethought surfaces (not just inverted)
|
|
44
|
-
- [ ] Semantic colors used consistently (success=green, error=red, warning=amber)
|
|
45
|
-
|
|
46
|
-
**Layout & Spacing:**
|
|
47
|
-
- [ ] Full-width fluid layouts — no hardcoded max-width caps
|
|
48
|
-
- [ ] 8px spacing grid followed consistently
|
|
49
|
-
- [ ] Tight spacing within groups, generous between sections
|
|
50
|
-
- [ ] Fluid padding: `clamp(1rem, 5vw, 4rem)` horizontal
|
|
51
|
-
- [ ] No identical card grids — varied visual hierarchy
|
|
52
|
-
- [ ] No generic heroes — purposeful, distinctive
|
|
53
|
-
|
|
54
|
-
**Interactive States:**
|
|
55
|
-
- [ ] Every button/link: hover (color shift, 150ms), focus (visible ring), active (press feedback), disabled
|
|
56
|
-
- [ ] Loading: skeleton or spinner on all async operations
|
|
57
|
-
- [ ] Empty: helpful message + action on empty lists/data
|
|
58
|
-
- [ ] Error: user-friendly message + recovery action on failed fetches
|
|
59
|
-
- [ ] Form validation: inline errors with `aria-describedby`
|
|
60
|
-
|
|
61
|
-
**Motion:**
|
|
62
|
-
- [ ] Hover/focus: 150–200ms transitions
|
|
63
|
-
- [ ] Page load: staggered entrance animations (50–80ms delay)
|
|
64
|
-
- [ ] Expand/collapse: 250ms ease-in-out
|
|
65
|
-
- [ ] `prefers-reduced-motion` respected (no animation for users who opt out)
|
|
66
|
-
- [ ] No jank: transforms and opacity only for animated properties
|
|
67
|
-
|
|
68
|
-
**Accessibility:**
|
|
69
|
-
- [ ] Semantic HTML: `nav`, `main`, `section`, `article`, `header`, `footer`
|
|
70
|
-
- [ ] One `h1` per page, sequential heading hierarchy
|
|
71
|
-
- [ ] All images: descriptive `alt` (or `alt=""` + `aria-hidden` if decorative)
|
|
72
|
-
- [ ] All form inputs: visible `<label>` with `htmlFor` — not placeholder-only
|
|
73
|
-
- [ ] All interactive elements: keyboard accessible (Tab/Enter/Escape)
|
|
74
|
-
- [ ] Touch targets: 44px minimum
|
|
75
|
-
- [ ] Skip link: `<a href="#main">` as first focusable element
|
|
76
|
-
- [ ] No `outline: none` without focus replacement
|
|
77
|
-
- [ ] `<html lang="en">` set
|
|
78
|
-
- [ ] Color not sole information carrier — icons/text as supplements
|
|
79
|
-
|
|
80
|
-
**Responsive:**
|
|
81
|
-
- [ ] Mobile-first approach (base styles for mobile, min-width breakpoints for larger)
|
|
82
|
-
- [ ] No horizontal scroll at 320px
|
|
83
|
-
- [ ] Navigation: hamburger on mobile, expanded on desktop
|
|
84
|
-
- [ ] Touch targets adequate on mobile (44px min)
|
|
85
|
-
- [ ] Fluid typography with `clamp()`
|
|
86
|
-
- [ ] Images: `max-width: 100%`, responsive srcset where needed
|
|
87
|
-
- [ ] Tables: card view or horizontal scroll on mobile
|
|
88
|
-
|
|
89
|
-
**Performance:**
|
|
90
|
-
- [ ] Server Components by default — `'use client'` only when needed
|
|
91
|
-
- [ ] Images via `next/image` with width/height
|
|
92
|
-
- [ ] No barrel file imports — direct imports from source
|
|
93
|
-
- [ ] Heavy components lazy-loaded with `next/dynamic`
|
|
94
|
-
- [ ] Data fetched in parallel, not sequentially
|
|
95
|
-
|
|
96
|
-
### 2. Fix Everything
|
|
97
|
-
|
|
98
|
-
Work through violations from the critique. Fix each category:
|
|
99
|
-
|
|
100
|
-
1. Typography first (sets the visual foundation)
|
|
101
|
-
2. Color & contrast (palette coherence)
|
|
102
|
-
3. Layout & spacing (structural fixes)
|
|
103
|
-
4. Interactive states (loading, empty, error, hover, focus)
|
|
104
|
-
5. Motion (transitions, entrance animations, reduced-motion)
|
|
105
|
-
6. Accessibility (semantic HTML, ARIA, keyboard, labels)
|
|
106
|
-
7. Responsive (mobile breakpoints, fluid sizing)
|
|
107
|
-
8. Performance (quick wins — image optimization, dynamic imports)
|
|
108
|
-
|
|
109
|
-
### 3. Harden
|
|
110
|
-
|
|
111
|
-
After polish, stress-test edge cases:
|
|
112
|
-
- Long text content (overflow, truncation, word-break)
|
|
113
|
-
- Extremely long usernames or email addresses
|
|
114
|
-
- Empty data everywhere simultaneously
|
|
115
|
-
- Error state on every fetch simultaneously
|
|
116
|
-
- 320px viewport width
|
|
117
|
-
- Keyboard-only navigation through entire flow
|
|
118
|
-
- Screen reader landmarks check (semantic HTML)
|
|
119
|
-
- Right-to-left text (if i18n is planned)
|
|
120
|
-
- Slow network (loading states visible, no flash of empty content)
|
|
121
|
-
|
|
122
|
-
### 4. Verify
|
|
52
|
+
### 1. AI Slop Detector
|
|
53
|
+
|
|
54
|
+
Run these checks first. Any hits = mandatory fixes.
|
|
123
55
|
|
|
124
56
|
```bash
|
|
125
|
-
|
|
57
|
+
# Generic fonts (the #1 AI tell)
|
|
58
|
+
grep -rn "Inter\|Roboto\|Arial\|Helvetica\|system-ui\|Space.Grotesk" --include="*.tsx" --include="*.css" --include="*.scss" --include="tailwind*" app/ components/ src/ 2>/dev/null | grep -v node_modules
|
|
59
|
+
|
|
60
|
+
# Hardcoded max-width containers (screams template)
|
|
61
|
+
grep -rn "max-w-7xl\|max-w-\[1200\|max-w-\[1280\|max-width.*1200\|max-width.*1280" --include="*.tsx" --include="*.css" app/ components/ src/ 2>/dev/null
|
|
62
|
+
|
|
63
|
+
# Blue-purple gradients
|
|
64
|
+
grep -rn "from-blue.*to-purple\|from-purple.*to-blue\|linear-gradient.*blue.*purple\|linear-gradient.*purple.*blue\|from-indigo.*to-violet" --include="*.tsx" --include="*.css" app/ components/ src/ 2>/dev/null
|
|
65
|
+
|
|
66
|
+
# Card grid monotony (same card component repeated in a grid)
|
|
67
|
+
grep -rn "grid-cols-3\|grid-cols-4" --include="*.tsx" app/ components/ src/ 2>/dev/null | head -5
|
|
68
|
+
|
|
69
|
+
# Generic hero patterns
|
|
70
|
+
grep -rn "text-center.*mx-auto\|Hero\|hero" --include="*.tsx" app/ components/ src/ 2>/dev/null | head -5
|
|
71
|
+
|
|
72
|
+
# Scattered hardcoded colors (no design system)
|
|
73
|
+
grep -rn "text-\[#\|bg-\[#\|border-\[#\|color:.*#\|background:.*#" --include="*.tsx" app/ components/ src/ 2>/dev/null | wc -l
|
|
126
74
|
```
|
|
127
75
|
|
|
128
|
-
|
|
76
|
+
**Every hit gets fixed.** Not flagged — fixed.
|
|
77
|
+
|
|
78
|
+
### 2. Typography Pass
|
|
79
|
+
|
|
80
|
+
**Goal:** A reader should feel the type was chosen, not defaulted.
|
|
81
|
+
|
|
82
|
+
- Pick a distinctive display font. Not Inter, not Roboto, not system. Something with character: Clash Display, Cabinet Grotesk, General Sans, Satoshi, Plus Jakarta Sans, Outfit, Sora, Manrope. Pair with a clean body font.
|
|
83
|
+
- Establish clear hierarchy: display (hero text) → h1 → h2 → h3 → body → caption
|
|
84
|
+
- Body: 16px minimum, line-height 1.5-1.7
|
|
85
|
+
- Headings: tighter line-height (1.1-1.3), negative letter-spacing (-0.02em) for display sizes
|
|
86
|
+
- Weight hierarchy: Regular (400) for body, Medium (500) for labels, Semibold (600) for headings, Bold (700) for display
|
|
87
|
+
- Prose content: `max-width: 65ch`. Everything else: fluid full-width.
|
|
88
|
+
- Use `clamp()` for fluid sizing: `clamp(2rem, 1rem + 3vw, 3.75rem)` for h1
|
|
89
|
+
|
|
90
|
+
### 3. Color & Surfaces
|
|
91
|
+
|
|
92
|
+
**Goal:** A palette that looks intentional, not random.
|
|
93
|
+
|
|
94
|
+
- Define all colors as CSS variables or Tailwind config — zero scattered hex values
|
|
95
|
+
- One dominant brand color. One sharp accent for CTAs that pops against the page.
|
|
96
|
+
- Surfaces: layer them. Background → card → elevated card. Use subtle shade differences, not just white-on-white.
|
|
97
|
+
- Dark mode (if present): rethink surfaces, don't just invert. Slightly reduce contrast. Use darker brand colors, not just white→black swap.
|
|
98
|
+
- Semantic colors with non-color indicators: success (green + checkmark), error (red + icon), warning (amber + triangle)
|
|
99
|
+
- Verify WCAG AA: 4.5:1 for normal text, 3:1 for large text (18px+ bold or 24px+)
|
|
100
|
+
|
|
101
|
+
### 4. Layout & Spacing
|
|
102
|
+
|
|
103
|
+
**Goal:** Full-width, fluid, generous. No dead space gutters.
|
|
104
|
+
|
|
105
|
+
- Full-width layouts with fluid padding: `clamp(1rem, 5vw, 4rem)` horizontal
|
|
106
|
+
- 8px spacing grid: 4, 8, 12, 16, 24, 32, 48, 64, 96
|
|
107
|
+
- Tight spacing within groups (related items). Generous spacing between sections.
|
|
108
|
+
- Break symmetry where it serves the design — offset grids, overlapping elements, diagonal flow
|
|
109
|
+
- Varied layouts: not every section should be a centered-text-with-cards-below. Use side-by-side, staggered, asymmetric, full-bleed.
|
|
110
|
+
- Section spacing: `clamp(2rem, 8vw, 6rem)` vertical padding
|
|
111
|
+
|
|
112
|
+
### 5. Interactive States
|
|
129
113
|
|
|
130
|
-
|
|
114
|
+
**Goal:** Every clickable thing responds. Every async operation shows progress.
|
|
115
|
+
|
|
116
|
+
- **Hover:** color shift or underline within 150ms ease-out. `cursor: pointer` on ALL clickables.
|
|
117
|
+
- **Focus:** visible ring (2px+ offset, contrasting color). Never `outline: none` without replacement.
|
|
118
|
+
- **Active/pressed:** subtle scale down (`transform: scale(0.98)`) or color shift.
|
|
119
|
+
- **Disabled:** opacity 0.5 + `cursor: not-allowed` + `aria-disabled="true"`
|
|
120
|
+
- **Loading:** skeleton shimmer or spinner on every async operation. Never a blank void.
|
|
121
|
+
- **Empty:** helpful message + CTA on empty lists/tables. Not just "No results."
|
|
122
|
+
- **Error:** user-friendly message + recovery action. Not raw error text. Use `aria-live="assertive"`.
|
|
123
|
+
|
|
124
|
+
### 6. Motion & Personality
|
|
125
|
+
|
|
126
|
+
**Goal:** The site feels alive, not static. But tasteful — not a circus.
|
|
127
|
+
|
|
128
|
+
- Page load: stagger children entrance (50-80ms delay between items, `fadeUp` animation, 300ms)
|
|
129
|
+
- Hover transitions: 150-200ms ease-out
|
|
130
|
+
- Section transitions: 300-500ms with `cubic-bezier(0.4, 0, 0.2, 1)`
|
|
131
|
+
- One signature motion that gives the site personality (parallax, scroll-triggered reveal, magnetic buttons, morphing shapes)
|
|
132
|
+
- **Always** `prefers-reduced-motion: reduce` — disable non-essential animation
|
|
133
|
+
- CSS-only for static sites, `motion/react` (formerly Framer Motion) for React
|
|
134
|
+
|
|
135
|
+
### 7. Accessibility (Non-Negotiable)
|
|
136
|
+
|
|
137
|
+
- Semantic HTML: `nav`, `main`, `section`, `article`, `header`, `footer` — not div soup
|
|
138
|
+
- One `h1` per page, sequential heading order (no h1 → h3 skip)
|
|
139
|
+
- All images: descriptive `alt` (or `alt=""` + `aria-hidden` if decorative)
|
|
140
|
+
- All form inputs: visible `<label>` with `htmlFor` — not placeholder-only
|
|
141
|
+
- All interactive elements: keyboard accessible (Tab, Enter, Escape, Arrow keys)
|
|
142
|
+
- Touch targets: 44x44px minimum
|
|
143
|
+
- Skip link: `<a href="#main" class="sr-only focus:not-sr-only">` as first focusable element
|
|
144
|
+
- `<html lang="en">` set
|
|
145
|
+
- Color never the sole information carrier — icons, text, patterns as supplements
|
|
146
|
+
- `aria-live="polite"` for toast notifications and dynamic content updates
|
|
147
|
+
|
|
148
|
+
### 8. Responsive (Mobile-First)
|
|
149
|
+
|
|
150
|
+
- Base styles for mobile (320px), scale up with `min-width` breakpoints
|
|
151
|
+
- Test at: 320px (small phone), 375px (iPhone), 768px (iPad), 1024px (laptop), 1440px (desktop)
|
|
152
|
+
- No horizontal scroll at any viewport
|
|
153
|
+
- Navigation: hamburger/drawer on mobile, full horizontal on desktop
|
|
154
|
+
- Stack on mobile, expand on desktop
|
|
155
|
+
- Fluid typography with `clamp()`
|
|
156
|
+
- Images: `max-width: 100%`, responsive `srcset`, `next/image` with width/height
|
|
157
|
+
- Tables: card layout or horizontal scroll on mobile
|
|
158
|
+
|
|
159
|
+
### 9. Harden (Edge Cases)
|
|
160
|
+
|
|
161
|
+
After all visual work, stress-test:
|
|
162
|
+
- Long text: does a 200-character username break the layout?
|
|
163
|
+
- Empty everywhere: all lists empty, all data missing — does it still make sense?
|
|
164
|
+
- Error everywhere: every fetch fails — are error states visible and helpful?
|
|
165
|
+
- 320px viewport: nothing overflows, nothing clips, nothing overlaps
|
|
166
|
+
- Keyboard only: Tab through the entire app — can you reach everything? Is focus visible?
|
|
167
|
+
- Slow network: are loading states visible? Does content stream in or flash?
|
|
168
|
+
|
|
169
|
+
### 10. Verify & Ship
|
|
170
|
+
|
|
171
|
+
```bash
|
|
172
|
+
npx tsc --noEmit 2>&1 | head -20
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
Fix any TypeScript errors.
|
|
131
176
|
|
|
132
177
|
```bash
|
|
133
178
|
git add {changed files}
|
|
134
|
-
git commit -m "polish: design
|
|
179
|
+
git commit -m "polish: design pass — typography, color, states, motion, responsive, a11y"
|
|
135
180
|
```
|
|
136
181
|
|
|
137
182
|
```bash
|
|
138
183
|
node ~/.claude/bin/state.js transition --to polished
|
|
139
184
|
```
|
|
140
|
-
Do NOT manually edit STATE.md or tracking.json — state.js handles both.
|
|
141
|
-
|
|
142
|
-
### 6. Report
|
|
143
185
|
|
|
144
186
|
```bash
|
|
145
187
|
node ~/.claude/bin/qualia-ui.js divider
|
|
146
|
-
node ~/.claude/bin/qualia-ui.js
|
|
147
|
-
node ~/.claude/bin/qualia-ui.js ok "Typography
|
|
148
|
-
node ~/.claude/bin/qualia-ui.js ok "Color
|
|
149
|
-
node ~/.claude/bin/qualia-ui.js ok "Layout
|
|
150
|
-
node ~/.claude/bin/qualia-ui.js ok "States
|
|
151
|
-
node ~/.claude/bin/qualia-ui.js ok "Motion
|
|
152
|
-
node ~/.claude/bin/qualia-ui.js ok "Accessibility
|
|
153
|
-
node ~/.claude/bin/qualia-ui.js ok "Responsive
|
|
154
|
-
node ~/.claude/bin/qualia-ui.js ok "
|
|
155
|
-
node ~/.claude/bin/qualia-ui.js ok "Hardening — {brief}"
|
|
188
|
+
node ~/.claude/bin/qualia-ui.js ok "AI slop: killed"
|
|
189
|
+
node ~/.claude/bin/qualia-ui.js ok "Typography: {brief}"
|
|
190
|
+
node ~/.claude/bin/qualia-ui.js ok "Color: {brief}"
|
|
191
|
+
node ~/.claude/bin/qualia-ui.js ok "Layout: {brief}"
|
|
192
|
+
node ~/.claude/bin/qualia-ui.js ok "States: {brief}"
|
|
193
|
+
node ~/.claude/bin/qualia-ui.js ok "Motion: {brief}"
|
|
194
|
+
node ~/.claude/bin/qualia-ui.js ok "Accessibility: {brief}"
|
|
195
|
+
node ~/.claude/bin/qualia-ui.js ok "Responsive: {brief}"
|
|
196
|
+
node ~/.claude/bin/qualia-ui.js ok "Hardened: {brief}"
|
|
156
197
|
node ~/.claude/bin/qualia-ui.js end "POLISHED" "/qualia-ship"
|
|
157
198
|
```
|
|
199
|
+
|
|
200
|
+
## Rules
|
|
201
|
+
|
|
202
|
+
1. **Read before write.** Understand every file before changing it.
|
|
203
|
+
2. **DESIGN.md is law.** If it exists, follow it. Don't override client decisions.
|
|
204
|
+
3. **Don't break functionality.** Only change styling, never logic.
|
|
205
|
+
4. **AI slop is a bug.** Generic fonts, card grids, blue-purple gradients, centered-everything — treat these as defects, not preferences.
|
|
206
|
+
5. **TypeScript must pass** after every change.
|
|
207
|
+
6. **One commit** at the end — not per category.
|
|
@@ -73,26 +73,35 @@ git commit -m "report: session {YYYY-MM-DD}"
|
|
|
73
73
|
git push
|
|
74
74
|
```
|
|
75
75
|
|
|
76
|
-
### 5. Upload to ERP
|
|
76
|
+
### 5. Upload to ERP (if enabled)
|
|
77
77
|
|
|
78
|
-
|
|
78
|
+
Read `~/.claude/.qualia-config.json` and check the `erp` object:
|
|
79
|
+
- If `erp.enabled` is `false`, skip this step and print: "ERP upload skipped (disabled in config)."
|
|
80
|
+
- If `erp.enabled` is `true` (default) or the `erp` field is missing (backward compatibility), proceed with the upload.
|
|
79
81
|
|
|
80
82
|
```bash
|
|
81
|
-
|
|
83
|
+
# Read ERP config
|
|
84
|
+
ERP_URL=$(node -e "try{const c=JSON.parse(require('fs').readFileSync(require('os').homedir()+'/.claude/.qualia-config.json','utf8'));console.log(c.erp?.url||'https://portal.qualiasolutions.net')}catch{console.log('https://portal.qualiasolutions.net')}")
|
|
85
|
+
ERP_ENABLED=$(node -e "try{const c=JSON.parse(require('fs').readFileSync(require('os').homedir()+'/.claude/.qualia-config.json','utf8'));console.log(c.erp?.enabled!==false)}catch{console.log('true')}")
|
|
86
|
+
|
|
82
87
|
API_KEY=$(cat ~/.claude/.erp-api-key 2>/dev/null)
|
|
83
88
|
REPORT_FILE=".planning/reports/report-{date}.md"
|
|
84
89
|
EMAIL=$(git config user.email)
|
|
85
90
|
PROJECT=$(basename $(pwd))
|
|
86
91
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
+
# Only upload if ERP is enabled
|
|
93
|
+
if [ "$ERP_ENABLED" = "true" ]; then
|
|
94
|
+
curl -s -X POST "$ERP_URL/api/claude/report-upload" \
|
|
95
|
+
-H "X-API-Key: $API_KEY" \
|
|
96
|
+
-F "file=@$REPORT_FILE" \
|
|
97
|
+
-F "employee_email=$EMAIL" \
|
|
98
|
+
-F "project_name=$PROJECT"
|
|
99
|
+
fi
|
|
92
100
|
```
|
|
93
101
|
|
|
94
102
|
If the upload succeeds, print: "Report uploaded to ERP. You can now clock out."
|
|
95
103
|
If it fails (no API key, network error), print the error and tell the employee to ask Fawzi.
|
|
104
|
+
If ERP is disabled, print: "ERP upload skipped (disabled in config)."
|
|
96
105
|
|
|
97
106
|
### 6. Update State
|
|
98
107
|
|