qualia-framework 4.4.0 → 5.1.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.
Files changed (70) hide show
  1. package/AGENTS.md +24 -0
  2. package/CLAUDE.md +12 -63
  3. package/README.md +24 -18
  4. package/agents/builder.md +13 -33
  5. package/agents/plan-checker.md +18 -0
  6. package/agents/planner.md +17 -0
  7. package/agents/verifier.md +70 -0
  8. package/agents/visual-evaluator.md +132 -0
  9. package/bin/cli.js +64 -23
  10. package/bin/install.js +375 -29
  11. package/bin/qualia-ui.js +208 -1
  12. package/bin/slop-detect.mjs +362 -0
  13. package/bin/state.js +218 -2
  14. package/docs/erp-contract.md +5 -0
  15. package/docs/install-redesign-builder-prompt.md +290 -0
  16. package/docs/install-redesign-pilot.md +234 -0
  17. package/docs/playwright-loop-builder-prompt.md +185 -0
  18. package/docs/playwright-loop-design-notes.md +108 -0
  19. package/docs/playwright-loop-pilot-results.md +170 -0
  20. package/docs/playwright-loop-review-2026-05-03.md +65 -0
  21. package/docs/playwright-loop-tester-prompt.md +213 -0
  22. package/docs/reviews/matt-pocock-skills-analysis.md +300 -0
  23. package/guide.md +9 -5
  24. package/hooks/env-empty-guard.js +74 -0
  25. package/hooks/pre-compact.js +19 -9
  26. package/hooks/pre-deploy-gate.js +8 -2
  27. package/hooks/pre-push.js +26 -12
  28. package/hooks/supabase-destructive-guard.js +62 -0
  29. package/hooks/vercel-account-guard.js +91 -0
  30. package/package.json +2 -1
  31. package/rules/design-brand.md +114 -0
  32. package/rules/design-laws.md +148 -0
  33. package/rules/design-product.md +114 -0
  34. package/rules/design-rubric.md +157 -0
  35. package/rules/grounding.md +4 -0
  36. package/skills/qualia-build/SKILL.md +40 -46
  37. package/skills/qualia-discuss/SKILL.md +51 -68
  38. package/skills/qualia-handoff/SKILL.md +1 -0
  39. package/skills/qualia-issues/SKILL.md +151 -0
  40. package/skills/qualia-map/SKILL.md +78 -35
  41. package/skills/qualia-new/REFERENCE.md +139 -0
  42. package/skills/qualia-new/SKILL.md +85 -124
  43. package/skills/qualia-optimize/REFERENCE.md +202 -0
  44. package/skills/qualia-optimize/SKILL.md +72 -237
  45. package/skills/qualia-plan/SKILL.md +58 -65
  46. package/skills/qualia-polish/SKILL.md +180 -136
  47. package/skills/qualia-polish-loop/REFERENCE.md +265 -0
  48. package/skills/qualia-polish-loop/SKILL.md +201 -0
  49. package/skills/qualia-polish-loop/fixtures/broken.html +117 -0
  50. package/skills/qualia-polish-loop/fixtures/clean.html +196 -0
  51. package/skills/qualia-polish-loop/scripts/loop.mjs +302 -0
  52. package/skills/qualia-polish-loop/scripts/playwright-capture.mjs +197 -0
  53. package/skills/qualia-polish-loop/scripts/score.mjs +176 -0
  54. package/skills/qualia-report/SKILL.md +141 -180
  55. package/skills/qualia-research/SKILL.md +28 -33
  56. package/skills/qualia-road/SKILL.md +103 -0
  57. package/skills/qualia-ship/SKILL.md +1 -0
  58. package/skills/qualia-task/SKILL.md +1 -1
  59. package/skills/qualia-test/SKILL.md +50 -2
  60. package/skills/qualia-triage/SKILL.md +152 -0
  61. package/skills/qualia-verify/SKILL.md +63 -104
  62. package/skills/qualia-zoom/SKILL.md +51 -0
  63. package/skills/zoho-workflow/SKILL.md +64 -0
  64. package/templates/CONTEXT.md +36 -0
  65. package/templates/DESIGN.md +229 -435
  66. package/templates/PRODUCT.md +95 -0
  67. package/templates/decisions/ADR-template.md +30 -0
  68. package/tests/bin.test.sh +451 -7
  69. package/tests/state.test.sh +58 -0
  70. package/skills/qualia-design/SKILL.md +0 -169
@@ -0,0 +1,300 @@
1
+ # Matt Pocock's Skills — Deep Analysis & Qualia 5.0 Proposal
2
+
3
+ **Source material**
4
+ - Repo: https://github.com/mattpocock/skills (46k stars, #1 on GitHub Trending the day it dropped)
5
+ - Course: https://www.aihero.dev/cohorts/claude-code-for-real-engineers-2026-04
6
+ - Talk: https://www.youtube.com/watch?v=kZ-zzHVUrO4
7
+
8
+ **Author of this analysis:** Synthesized 2026-05-03 from a full read of Matt's CLAUDE.md, CONTEXT.md, and every SKILL.md in `engineering/`, `productivity/`, and `misc/`.
9
+
10
+ ---
11
+
12
+ ## Part 1 — Matt's worldview, distilled
13
+
14
+ Matt is teaching one thing: **the real bottleneck on AI-coding quality is not the model, it's the alignment between human, agent, code, and domain.** Every skill exists to fix one alignment failure.
15
+
16
+ ### The four pillars (from his CLAUDE.md)
17
+
18
+ | Pillar | Source | What it fixes |
19
+ |---|---|---|
20
+ | **Alignment Before Coding** | Pragmatic Programmer — "no-one knows exactly what they want" | Misalignment is the #1 failure mode. Cure: relentless one-question grilling until every branch of the decision tree is resolved. |
21
+ | **Domain Language Matters** | DDD ubiquitous language | Shared vocabulary reduces tokens, improves agent navigation, prevents "what do you mean by user?" rework. |
22
+ | **Feedback Loops Drive Quality** | Pragmatic Programmer — "the rate of feedback is your speed limit" | Without a fast deterministic pass/fail signal, agents fly blind. Cure: build the loop FIRST, then debug. |
23
+ | **Design Discipline** | Ousterhout — "the best modules are deep" | Daily attention to architecture or entropy wins. Cure: deepening refactors framed in domain language. |
24
+
25
+ ### The structural innovations
26
+
27
+ 1. **CONTEXT.md as a domain glossary** — not a project README, not a spec. A glossary of terms with **`Avoid`** lists. The agent literally reads "use *milestone*, not *sprint*" and conforms. Reduces token waste from disambiguation rounds.
28
+ 2. **ADRs (Architecture Decision Records)** in `docs/adr/` — created sparingly, only for hard-to-reverse, surprising-without-context decisions with real trade-offs. Becomes the load-bearing memory.
29
+ 3. **Vertical slices everywhere** — both for issues (each issue = a complete path through schema → API → UI → tests) and for TDD (one test → one impl → repeat). Anti-horizontal as a **rule**.
30
+ 4. **Skill descriptions are the API surface** — "the only thing your agent sees." Discriminative descriptions beat clever prose. <1024 chars. Third-person. Always include "Use when {context}".
31
+ 5. **Skills under 100 lines** — overflow goes to `REFERENCE.md` / `EXAMPLES.md` / `scripts/` (progressive disclosure).
32
+ 6. **`disable-model-invocation: true`** — some skills (e.g. `zoom-out`) are user-fired-only. Prevents auto-firing on weak signals.
33
+ 7. **scripts/ co-located with skills** — for deterministic operations. "Trade tokens for reliability" — the script can't hallucinate.
34
+
35
+ ### The 21 skills, mapped
36
+
37
+ | Bucket | Skill | One-liner | Maps to (Qualia equivalent) |
38
+ |---|---|---|---|
39
+ | eng | **diagnose** | Build feedback loop FIRST, then reproduce → hypothesize → instrument → fix → regression-test | `qualia-debug` (weaker — doesn't enforce loop-first) |
40
+ | eng | **grill-with-docs** | Interview the user, update CONTEXT.md/ADRs inline as decisions crystallize | `qualia-discuss` (much weaker — no glossary update) |
41
+ | eng | **improve-codebase-architecture** | Find shallow modules, propose deepening refactors, use domain language | `qualia-optimize` (broader but lacks Ousterhout language) |
42
+ | eng | **tdd** | Vertical-slice tracer-bullet loop. ANTI horizontal slicing (writing all tests then all code) | `qualia-test` (lacks the methodology rule) |
43
+ | eng | **to-prd** | Conversation → PRD → GH Issue with `needs-triage` label | `qualia-new` (stays internal; never touches GH issues) |
44
+ | eng | **to-issues** | PRD → independent vertical-slice GH Issues, dependency-ordered | **NO EQUIVALENT** |
45
+ | eng | **triage** | State machine: needs-triage / needs-info / ready-for-agent / ready-for-human / wontfix | **NO EQUIVALENT** (we use tracking.json status fields, not GH labels) |
46
+ | eng | **zoom-out** | "Map this area using the project glossary" — 5-line skill, user-only | **NO EQUIVALENT** |
47
+ | eng | **setup-matt-pocock-skills** | Detect repo state, write `docs/agents/{tracker,labels,domain}.md`, append to CLAUDE.md | `qualia-map` (broader, but doesn't externalize agent config) |
48
+ | prod | **caveman** | 75% token reduction via dropped articles/fillers, fragment sentences, abbreviations, arrows | **NO EQUIVALENT** |
49
+ | prod | **grill-me** | Aggressive one-question-at-a-time interview until decision tree resolves | partial overlap with `qualia-discuss` |
50
+ | prod | **write-a-skill** | Meta-skill for authoring skills — frontmatter rules, file split rules | `qualia-skill-new` (similar) |
51
+ | misc | **git-guardrails** | Block dangerous git commands | partial — we have hooks |
52
+ | misc | **migrate-to-shoehorn** | Codemod-y tool | n/a |
53
+ | misc | **scaffold-exercises** | Course-specific | n/a |
54
+ | misc | **setup-pre-commit** | Husky setup | n/a |
55
+
56
+ ---
57
+
58
+ ## Part 2 — Where Qualia is already strong
59
+
60
+ We should NOT abandon what's working:
61
+
62
+ 1. **Phase/wave/task hierarchy** — Matt has nothing equivalent to `JOURNEY.md → ROADMAP.md → phase plans → tasks with verification contracts`. This is a Qualia advantage.
63
+ 2. **Fresh-context subagent spawning** — task-level context isolation prevents rot. Matt mentions subagents conceptually; we do it systematically.
64
+ 3. **The verifier loop with goal-backward checks** — `qualia-verify` is sharper than anything Matt ships.
65
+ 4. **Design substrate (v4.5.0)** — DESIGN.md + design-laws.md + slop-detect + 8-dimension scoring. Matt has nothing on visual design.
66
+ 5. **Smart router (`qualia` skill)** — state-driven next-action recommendation. Matt's flow is more linear.
67
+ 6. **The 4 mandatory Handoff deliverables** — client-delivery rigor that doesn't exist in Matt's repo (he targets engineers building in their own repos, not agencies shipping to clients).
68
+
69
+ The combination of Matt's alignment discipline + Qualia's execution machinery is the play.
70
+
71
+ ---
72
+
73
+ ## Part 3 — Qualia 5.0 proposal: 15 changes ranked by ROI
74
+
75
+ ### Tier 1 — Adopt these immediately (high ROI, low effort)
76
+
77
+ #### 1. **CONTEXT.md substrate (domain glossary)** — `.planning/CONTEXT.md`
78
+
79
+ The single biggest miss. Every Qualia agent currently re-derives domain terms from PROJECT.md prose. Matt's pattern: a structured glossary with `Avoid` lists.
80
+
81
+ **Format:**
82
+ ```markdown
83
+ ## Language
84
+
85
+ ### Milestone
86
+ A bounded slice of the journey. Always one of: Foundation, MVP, Polish, Handoff.
87
+ **Avoid:** sprint, iteration, release.
88
+
89
+ ### Phase
90
+ A unit of work inside a milestone, 2–5 tasks, ends in a verification gate.
91
+ **Avoid:** epic, story, ticket.
92
+
93
+ ### Task
94
+ A single commit-sized unit with one verification contract.
95
+ **Avoid:** subtask, chore.
96
+
97
+ ## Relationships
98
+ - Project holds many Milestones
99
+ - Milestone holds many Phases
100
+ - Phase holds many Tasks
101
+ - Task carries one Verification Contract
102
+
103
+ ## Flagged ambiguities
104
+ - "User" was previously used for both `auth.users` row and customer profile. Now: **AuthUser** (auth row), **Customer** (profile).
105
+ ```
106
+
107
+ - Generated by `/qualia-new` from the discovery questioning
108
+ - Loaded **first** by every subagent (before PROJECT.md, before DESIGN.md)
109
+ - Updated inline by `/qualia-discuss` and the new `/qualia-grill`
110
+ - **Expected impact:** ~30% reduction in disambiguation back-and-forth, fewer wrong-assumption rework cycles
111
+
112
+ #### 2. **ADR pattern** — `.planning/decisions/ADR-{N}-{slug}.md`
113
+
114
+ Replace the ad-hoc `phase-{N}-context.md` with structured ADRs. Created **sparingly**: only when the decision is hard-to-reverse, surprising-without-context, AND involves real trade-offs.
115
+
116
+ **Format:**
117
+ ```markdown
118
+ # ADR-007 — Use Supabase RLS instead of API-layer auth checks
119
+ Date: 2026-05-03
120
+ Phase: 2
121
+ Status: Accepted
122
+
123
+ ## Context
124
+ {why this decision is being made now}
125
+
126
+ ## Decision
127
+ {what we are doing}
128
+
129
+ ## Consequences
130
+ {what becomes easier; what becomes harder}
131
+
132
+ ## Alternatives considered
133
+ {what we rejected and why}
134
+ ```
135
+
136
+ - Loaded by relevant phases via `@.planning/decisions/ADR-007-*.md`
137
+ - Listed in CONTEXT.md "Flagged ambiguities" when they resolve a term
138
+
139
+ #### 3. **`/qualia-zoom`** — 5-line user-only skill
140
+
141
+ ```yaml
142
+ ---
143
+ name: qualia-zoom
144
+ description: Zoom out and map the surrounding modules using project glossary terms. Use when you don't know an area of code well or need to orient before editing.
145
+ disable-model-invocation: true
146
+ ---
147
+
148
+ I don't know this area well. Go up a layer of abstraction. Give me a map of all relevant modules and callers using the vocabulary in `.planning/CONTEXT.md`.
149
+ ```
150
+
151
+ Tiny. Used 50× a day in mature projects. Replaces ad-hoc "explain this code" requests with a glossary-anchored response.
152
+
153
+ #### 4. **Caveman mode for subagent spawning** (cost reduction)
154
+
155
+ Add to the prompt-cache template in `rules/grounding.md`:
156
+
157
+ > **Subagent compression**: All in-flight spawned-subagent system prompts use compressed form — drop articles, fillers, pleasantries. Use abbreviations (DB, auth, fn, impl, req, res). Fragment sentences over full clauses. Arrow notation for causality. Suspend compression for security warnings, irreversible action confirmations, and multi-step sequences where brevity risks misinterpretation.
158
+
159
+ The verifier and builder spawn 50+ times per project. ~25% token reduction per spawn. Real money at scale.
160
+
161
+ #### 5. **Tighten skill descriptions** (the API surface)
162
+
163
+ Audit all 74 skills. Each description must:
164
+ - Be ≤ 1024 chars
165
+ - Be in third person
166
+ - Include "Use when {specific context}" with **discriminative** triggers
167
+ - Have **zero overlap** with sibling skills
168
+
169
+ Currently `/qualia`, `/qualia-idk`, `/qualia-resume` all overlap on "lost? what next?" triggers. Wrong-skill-firing happens. Fix it.
170
+
171
+ ### Tier 2 — Adopt these next (high ROI, medium effort)
172
+
173
+ #### 6. **`/qualia-grill`** — replace or augment `/qualia-discuss`
174
+
175
+ Aggressive one-question-at-a-time grilling. Walks every branch of the decision tree. Updates CONTEXT.md inline.
176
+
177
+ **Critical rule from Matt's grill-me:** *"For each question, provide your recommended answer."* — the agent isn't just asking, it's proposing. The user accepts, edits, or rejects. Way faster than open-ended interview.
178
+
179
+ Used **before** `/qualia-plan` for high-stakes phases (auth, payments, multi-tenant, anything with regulatory weight).
180
+
181
+ #### 7. **Restructure `/qualia-debug` around feedback-loop-first**
182
+
183
+ Current `qualia-debug` jumps to symptom analysis. Matt's diagnose enforces **build the loop first, then everything else is mechanical**. New phase structure:
184
+
185
+ 1. Build a fast deterministic agent-runnable pass/fail signal (failing test > curl > CLI invocation > headless browser > trace replay > minimal harness > property test > bisection > differential > human-in-loop bash). Pick the highest-tier feasible.
186
+ 2. Reproduce against the loop
187
+ 3. Generate 3–5 ranked falsifiable hypotheses BEFORE testing
188
+ 4. Instrument with `[DEBUG-{tag}]` prefixes (cleanup later)
189
+ 5. Change one variable at a time
190
+ 6. Fix at the correct seam, write regression test there
191
+ 7. Cleanup `[DEBUG-*]` markers, verify scenario, document architectural finding answering "what would have prevented this?"
192
+
193
+ #### 8. **`/qualia-deepen`** — split out from `/qualia-optimize`
194
+
195
+ `/qualia-optimize` is currently a kitchen sink (perf + UI + backend + alignment). Pull out architecture-deepening as its own skill that uses Ousterhout's vocabulary explicitly: **depth, locality, leverage, seam, deletion test**.
196
+
197
+ Process:
198
+ 1. Read `.planning/CONTEXT.md` glossary first
199
+ 2. Walk codebase noting friction points: shallow modules where interface ≈ implementation, modules requiring bouncing across many files for one concept, pure functions extracted only for testability (no locality), tightly-coupled cross-seam leakage
200
+ 3. Present candidates with **Files / Problem / Solution / Benefits**
201
+ 4. Grilling loop: walk the design tree with the user, update CONTEXT.md/ADRs as decisions crystallize
202
+
203
+ #### 9. **`/qualia-tdd`** — vertical-slice rule enforcement
204
+
205
+ ```
206
+ WRONG (horizontal): RED test1-5 → GREEN impl1-5
207
+ RIGHT (vertical): RED→GREEN test1→impl1, test2→impl2, ...
208
+ ```
209
+
210
+ One test at a time. Only enough code to pass. Tests describe **behavior through public interface**, never implementation. Never refactor while red.
211
+
212
+ This is the #1 missing engineering discipline in the framework. We have `/qualia-test` (generate tests) but no test-first methodology.
213
+
214
+ #### 10. **Skill file structure cleanup** (progressive disclosure)
215
+
216
+ Audit pass: every SKILL.md must be **<100 lines**. Overflow goes to:
217
+ - `REFERENCE.md` (advanced/rare features)
218
+ - `EXAMPLES.md` (worked examples)
219
+ - `scripts/` (deterministic operations co-located with the skill)
220
+
221
+ Move `bin/state.js` and `bin/qualia-ui.js` from `~/.claude/bin/` into `skills/qualia/scripts/` (or symlink). The script being co-located with the skill means it's discoverable when reading the skill.
222
+
223
+ ### Tier 3 — Strategic bets (very high ROI, larger effort)
224
+
225
+ #### 11. **`/qualia-issues`** — externalize work to GitHub
226
+
227
+ Convert the current phase plan into independent vertical-slice GH issues. Each issue:
228
+ - Title describing the slice
229
+ - End-to-end behavior description
230
+ - Acceptance criteria checklist
231
+ - Blocking-dependencies field
232
+ - Label: `needs-triage`
233
+
234
+ This **unlocks the autonomous loop**: other agents (or other Claude sessions, or Codex, or human contributors) can pull issues from the queue. Currently Qualia only runs in the originating session.
235
+
236
+ #### 12. **`/qualia-triage`** — state machine over the issue queue
237
+
238
+ Pulls open issues. Applies labels: `needs-triage` / `needs-info` / `ready-for-agent` / `ready-for-human` / `wontfix`. Routes:
239
+ - `ready-for-agent` → autonomous `/qualia-build` or `/qualia-quick`
240
+ - `ready-for-human` → notification to Fawzi
241
+ - `needs-info` → questions back to reporter
242
+
243
+ Combined with `/qualia-issues`, this is the **Ralph Wiggum loop** Matt teaches: agent pulls from backlog, builds, verifies, ships, picks next. Human-in-loop is optional, not required.
244
+
245
+ #### 13. **AGENTS.md emission** alongside CLAUDE.md
246
+
247
+ `/qualia-new` should write **both** `CLAUDE.md` (Anthropic) and `AGENTS.md` (the cross-vendor open standard now adopted by Codex, Cursor, Continue, Devin, Aider, etc.). Same content, different file. One project, multi-agent compatible. Costs nothing, expands the ecosystem.
248
+
249
+ #### 14. **`/qualia-onboard`** — adapt-to-existing-repo skill
250
+
251
+ Matt's `setup-matt-pocock-skills` is the model. Companion to `/qualia-map`. Detects:
252
+ - Existing issue tracker (GH, GL, Jira, local `.scratch/`)
253
+ - Existing labels — maps them to canonical roles
254
+ - Existing CONTEXT.md / docs/adr / glossary structure
255
+
256
+ Writes `.planning/agents/{tracker.md, labels.md, domain.md}` and appends an `## Agent skills` block to existing CLAUDE.md/AGENTS.md. **Adapts Qualia to the repo's conventions** instead of forcing Qualia conventions on the repo.
257
+
258
+ This is what makes the framework usable on brownfield client projects without ripping their existing process out.
259
+
260
+ #### 15. **`disable-model-invocation` flag adoption**
261
+
262
+ Add to skills that should never auto-fire on a weak trigger: `qualia-zoom`, `qualia-caveman`, anything destructive (`qualia-ship`, `qualia-handoff` arguably). Reduces accidental invocations.
263
+
264
+ ---
265
+
266
+ ## Part 4 — Sequencing recommendation
267
+
268
+ ### Wave 1 (immediate, ~1 day)
269
+ - 1, 2, 3, 4, 5 (CONTEXT.md, ADRs, qualia-zoom, caveman mode, description audit)
270
+
271
+ ### Wave 2 (short, ~3 days)
272
+ - 6, 7, 8, 9, 10 (qualia-grill, debug restructure, qualia-deepen, qualia-tdd, file structure cleanup)
273
+
274
+ ### Wave 3 (strategic, ~1 week)
275
+ - 11, 12 (qualia-issues, qualia-triage) — these together unlock autonomous operation
276
+
277
+ ### Wave 4 (polish, ~2 days)
278
+ - 13, 14, 15 (AGENTS.md, qualia-onboard, disable-model-invocation)
279
+
280
+ ### Ship as v5.0
281
+ - New release: "Qualia 5.0 — alignment discipline" — leans into Matt's framing
282
+
283
+ ---
284
+
285
+ ## Part 5 — What we should NOT copy
286
+
287
+ - **Matt's flat skill list (no router)**. Our `/qualia` smart router and state machine are better for non-trivial projects.
288
+ - **Matt's lack of design discipline**. Our v4.5.0 design substrate is genuinely ahead. Don't dilute it.
289
+ - **Matt's per-project `.scratch/` dir as default tracker**. We need real GH issues for client work and ERP integration.
290
+ - **Matt's "scaffold-exercises"** etc. — course-specific, not relevant.
291
+
292
+ ---
293
+
294
+ ## Part 6 — The honest assessment
295
+
296
+ Matt is teaching **alignment as the primary engineering discipline**. The framework currently treats alignment as a one-shot at `/qualia-new` and assumes it holds for the rest of the project. It doesn't. Decisions drift. Terms overload. Hypotheses go untested. Feedback loops degrade.
297
+
298
+ The 15 changes above are not features — they're **rituals** that keep alignment from rotting between phases. That's the x20 unlock. Not more skills. Better-disciplined skills, anchored to a domain glossary, with feedback loops built first.
299
+
300
+ The single highest-ROI change is **#1 (CONTEXT.md)**. If you do nothing else from this list, do that one. Every other change compounds off it.
package/guide.md CHANGED
@@ -1,7 +1,7 @@
1
- # Qualia Developer Guide (v4)
1
+ # Qualia Developer Guide (v5)
2
2
 
3
3
  > Follow the road. Type the commands. The framework handles the rest.
4
- > v4 adds a `--auto` flag that chains the whole road end-to-end with only two human checkpoints per project.
4
+ > `--auto` chains the whole road end-to-end with only two human checkpoints per project.
5
5
 
6
6
  ## The Road
7
7
 
@@ -24,7 +24,7 @@ For each phase of the current milestone:
24
24
  Done.
25
25
  ```
26
26
 
27
- ## Auto Mode (v4)
27
+ ## Auto Mode
28
28
 
29
29
  Append `--auto` to `/qualia-new` and the framework chains every step:
30
30
 
@@ -58,10 +58,14 @@ Append `--auto` to `/qualia-new` and the framework chains every step:
58
58
  | | `/qualia-ship` | Deploy to production |
59
59
  | | `/qualia-handoff` | Deliver to client (4 mandatory deliverables) |
60
60
  | Reporting | `/qualia-report` | Log what you did (mandatory before clock-out) |
61
+ | Zooming in | `/qualia-zoom` | Focus on a single file or function with full context |
62
+ | Issues | `/qualia-issues` | Scan codebase for issues, tech debt, and improvement opportunities |
63
+ | Triage | `/qualia-triage` | Prioritize and categorize a backlog of issues |
64
+ | Road view | `/qualia-road` | View and navigate journey/milestone/phase status |
61
65
  | Lost? | `/qualia` | Mechanical next-command router |
62
66
  | Confused? | `/qualia-idk` | Diagnostic — scans planning + code, explains what's going on |
63
67
 
64
- ## Full Journey Hierarchy (v4)
68
+ ## Full Journey Hierarchy
65
69
 
66
70
  ```
67
71
  Project
@@ -109,7 +113,7 @@ If neither helps, paste the error and ask Claude directly. If Claude can't fix i
109
113
  - **Story-file plans:** Every task has Why / Acceptance Criteria / Depends on / Validation inline — the plan IS the brief.
110
114
  - **Wave execution:** Independent tasks run in parallel. Dependent tasks wait.
111
115
  - **Milestone-boundary pauses:** In `--auto` mode, the framework pauses only at real decision points. Everything else runs on rails.
112
- - **tracking.json:** Updated on every push. The ERP reads it automatically. v4 adds `milestone_name` + `milestones[]` so the ERP renders a proper tree instead of a flat list.
116
+ - **tracking.json:** Updated on every push. The ERP reads it automatically. Includes `milestone_name` + `milestones[]` so the ERP renders a proper tree instead of a flat list.
113
117
 
114
118
  ## Quick Reference
115
119
 
@@ -0,0 +1,74 @@
1
+ #!/usr/bin/env node
2
+ // hooks/env-empty-guard.js — block empty env var values on Vercel.
3
+ // PreToolUse hook on `Bash`. Blocks `vercel env add NAME ""` (empty value).
4
+ // Exits 2 to BLOCK, 0 to allow. Escape: QUALIA_ALLOW_EMPTY_ENV=1.
5
+
6
+ const fs = require("fs");
7
+ const path = require("path");
8
+ const os = require("os");
9
+
10
+ const _traceStart = Date.now();
11
+
12
+ function _trace(result, extra) {
13
+ try {
14
+ const traceDir = path.join(os.homedir(), ".claude", ".qualia-traces");
15
+ if (!fs.existsSync(traceDir)) fs.mkdirSync(traceDir, { recursive: true });
16
+ const entry = {
17
+ hook: "env-empty-guard", result,
18
+ timestamp: new Date().toISOString(),
19
+ duration_ms: Date.now() - _traceStart, ...extra,
20
+ };
21
+ const file = path.join(traceDir, `${new Date().toISOString().split("T")[0]}.jsonl`);
22
+ fs.appendFileSync(file, JSON.stringify(entry) + "\n");
23
+ } catch {}
24
+ }
25
+
26
+ // Read hook payload from stdin.
27
+ let payload = "";
28
+ try { if (!process.stdin.isTTY) payload = fs.readFileSync(0, "utf8"); } catch {}
29
+
30
+ let command = "";
31
+ try {
32
+ if (payload) command = (JSON.parse(payload).tool_input || {}).command || "";
33
+ } catch {
34
+ console.error("BLOCKED: env-empty-guard could not parse hook payload.");
35
+ _trace("block", { reason: "parse-error" });
36
+ process.exit(2);
37
+ }
38
+
39
+ // Only act on vercel env commands.
40
+ if (!/\bvercel\s+env\s+(add|pull)\b/.test(command)) {
41
+ _trace("allow", { reason: "no-match" });
42
+ process.exit(0);
43
+ }
44
+
45
+ // vercel env pull is always fine.
46
+ if (/\bvercel\s+env\s+pull\b/.test(command)) {
47
+ _trace("allow", { reason: "env-pull" });
48
+ process.exit(0);
49
+ }
50
+
51
+ // Detect empty value patterns in vercel env add.
52
+ const emptyPatterns = [
53
+ /\bvercel\s+env\s+add\s+\S+\s+(""|'')\s*$/, // vercel env add KEY "" / ''
54
+ /\bvercel\s+env\s+add\s+\S+=\s*$/, // vercel env add KEY=
55
+ /\bvercel\s+env\b.*\s+""\s*/, // "" anywhere after vercel env
56
+ /\bvercel\s+env\b.*\s+''\s*/, // '' anywhere after vercel env
57
+ ];
58
+
59
+ if (emptyPatterns.some((re) => re.test(command))) {
60
+ if (process.env.QUALIA_ALLOW_EMPTY_ENV === "1") {
61
+ process.stderr.write("Warning: Empty env var allowed by QUALIA_ALLOW_EMPTY_ENV=1\n");
62
+ _trace("bypassed", { command_preview: command.slice(0, 80) });
63
+ process.exit(0);
64
+ }
65
+ process.stderr.write(
66
+ `BLOCKED: empty env var value detected in: \`${command}\`. ` +
67
+ "Confirm the value is intentional, then re-run with QUALIA_ALLOW_EMPTY_ENV=1 to bypass.\n"
68
+ );
69
+ _trace("block", { command_preview: command.slice(0, 80) });
70
+ process.exit(2);
71
+ }
72
+
73
+ _trace("allow", { command_preview: command.slice(0, 80) });
74
+ process.exit(0);
@@ -26,6 +26,8 @@ const { spawnSync } = require("child_process");
26
26
  const _traceStart = Date.now();
27
27
 
28
28
  const STATE_FILE = path.join(".planning", "STATE.md");
29
+ const TRACKING_FILE = path.join(".planning", "tracking.json");
30
+ const PLANNING_FILES = [STATE_FILE, TRACKING_FILE];
29
31
  const CONFIG_FILE = path.join(os.homedir(), ".claude", ".qualia-config.json");
30
32
 
31
33
  function readCompactConfig() {
@@ -46,12 +48,18 @@ function git(args, opts = {}) {
46
48
  });
47
49
  }
48
50
 
49
- function stateHasPendingChanges() {
50
- const diff = git(["diff", "--name-only", "--", STATE_FILE]);
51
- if ((diff.stdout || "").split(/\r?\n/).includes(STATE_FILE)) return true;
51
+ function planningHasPendingChanges() {
52
+ // v5.0: also stage tracking.json. The CLAUDE.md compaction contract says to
53
+ // preserve tracking.json across compactions, but pre-v5 only committed
54
+ // STATE.md — tracking.json mutations from state.js transitions were lost
55
+ // across compactions, leaving the ERP with stale milestone/phase/tasks data.
56
+ const diff = git(["diff", "--name-only", "--", ...PLANNING_FILES]);
57
+ const diffLines = (diff.stdout || "").split(/\r?\n/);
58
+ if (PLANNING_FILES.some((f) => diffLines.includes(f))) return true;
52
59
 
53
- const untracked = git(["ls-files", "--others", "--exclude-standard", "--", STATE_FILE]);
54
- return (untracked.stdout || "").split(/\r?\n/).includes(STATE_FILE);
60
+ const untracked = git(["ls-files", "--others", "--exclude-standard", "--", ...PLANNING_FILES]);
61
+ const untrackedLines = (untracked.stdout || "").split(/\r?\n/);
62
+ return PLANNING_FILES.some((f) => untrackedLines.includes(f));
55
63
  }
56
64
 
57
65
  let _commitStatus = null;
@@ -62,15 +70,17 @@ try {
62
70
  if (fs.existsSync(STATE_FILE)) {
63
71
  console.log("QUALIA: Saving state before compaction...");
64
72
  _commitReason = "state-clean";
65
- // Check if STATE.md has tracked or untracked changes.
66
- if (stateHasPendingChanges()) {
67
- const addRes = git(["add", STATE_FILE]);
73
+ // Check if STATE.md or tracking.json has tracked or untracked changes.
74
+ if (planningHasPendingChanges()) {
75
+ // Stage both planning files. `git add` silently no-ops on files that don't exist
76
+ // or have no changes, so passing both is safe even when only one is dirty.
77
+ const addRes = git(["add", ...PLANNING_FILES]);
68
78
  const cfg = readCompactConfig();
69
79
  const commitArgs = ["commit"];
70
80
  if (!cfg.respect_user_hooks) commitArgs.push("--no-verify");
71
81
  if (!cfg.respect_gpg_signing) commitArgs.push("--no-gpg-sign");
72
82
  commitArgs.push("--author=Qualia Framework <bot@qualia.solutions>");
73
- commitArgs.push("-m", "state: pre-compaction save");
83
+ commitArgs.push("-m", "state: pre-compaction save (STATE.md + tracking.json)");
74
84
  _commitFlags = {
75
85
  no_verify: !cfg.respect_user_hooks,
76
86
  no_gpg_sign: !cfg.respect_gpg_signing,
@@ -170,9 +170,15 @@ if (fs.existsSync("tsconfig.json")) {
170
170
  runGate("TypeScript", "npx", ["tsc", "--noEmit"]);
171
171
  }
172
172
 
173
- // Lint
173
+ // Lint (with QUALIA_SKIP_LINT=1 escape — for the documented "lint blocks
174
+ // ship" friction when the lint failures are pre-existing or auto-fixer-broken)
174
175
  if (hasScript("lint")) {
175
- runGate("Lint", "npm", ["run", "lint"]);
176
+ if (process.env.QUALIA_SKIP_LINT === "1") {
177
+ console.log(" ⚠ Lint skipped (QUALIA_SKIP_LINT=1)");
178
+ _trace("pre-deploy-gate", "skip-lint", { reason: "QUALIA_SKIP_LINT=1" });
179
+ } else {
180
+ runGate("Lint", "npm", ["run", "lint"]);
181
+ }
176
182
  }
177
183
 
178
184
  // Tests
package/hooks/pre-push.js CHANGED
@@ -103,12 +103,21 @@ function commitStamp() {
103
103
  }
104
104
 
105
105
  function shouldBlock(result) {
106
- const hardSkips = new Set([
107
- "tracking-unreadable",
108
- "git-add-failed",
109
- "git-commit-failed",
110
- ]);
111
- return result && hardSkips.has(result.skipped);
106
+ // v5.0: tracking.json sync failures are now WARN not BLOCK. Rationale:
107
+ // tracking.json is ERP metadata, not load-bearing for the push itself. A
108
+ // corrupt tracking.json should NEVER prevent a production hotfix. The
109
+ // self-service fix is `git checkout HEAD -- .planning/tracking.json` and
110
+ // gets surfaced in the warning message below.
111
+ // To restore old fail-closed behavior set QUALIA_BLOCK_ON_TRACKING_FAIL=1.
112
+ if (process.env.QUALIA_BLOCK_ON_TRACKING_FAIL === "1") {
113
+ const hardSkips = new Set([
114
+ "tracking-unreadable",
115
+ "git-add-failed",
116
+ "git-commit-failed",
117
+ ]);
118
+ return result && hardSkips.has(result.skipped);
119
+ }
120
+ return false;
112
121
  }
113
122
 
114
123
  function _trace(result, extra) {
@@ -131,19 +140,24 @@ try {
131
140
  const result = commitStamp();
132
141
  if (shouldBlock(result)) {
133
142
  const detail = result.error ? ` ${String(result.error).slice(0, 500)}` : "";
134
- const msg = `BLOCKED: tracking.json sync failed (${result.skipped}). Fix before pushing.${detail}`;
143
+ const msg = `BLOCKED: tracking.json sync failed (${result.skipped}). Fix before pushing.${detail}\nSelf-service fix: git checkout HEAD -- .planning/tracking.json`;
135
144
  console.error(msg);
136
145
  console.log(msg);
137
146
  _trace("block", result);
138
147
  process.exit(2);
139
148
  }
149
+ // v5.0: warn-not-block on tracking.json failures. The push proceeds; the user
150
+ // sees a clear message and a self-service fix path. Production hotfixes are
151
+ // never blocked by ERP-metadata corruption.
152
+ if (result && (result.skipped === "tracking-unreadable" || result.skipped === "git-add-failed" || result.skipped === "git-commit-failed")) {
153
+ const detail = result.error ? ` (${String(result.error).slice(0, 200)})` : "";
154
+ console.error(`⚠ tracking.json sync failed: ${result.skipped}${detail}. Push proceeding. Self-service fix: git checkout HEAD -- .planning/tracking.json`);
155
+ }
140
156
  _trace("allow", result);
141
157
  } catch (err) {
142
- const msg = `BLOCKED: tracking.json sync failed (${err.message}). Fix before pushing.`;
143
- console.error(msg);
144
- console.log(msg);
145
- _trace("block", { error: err.message });
146
- process.exit(2);
158
+ // Exception during commit stamping warn, don't block (same v5.0 rationale).
159
+ console.error(`⚠ tracking.json sync threw: ${err.message}. Push proceeding. Self-service fix: git checkout HEAD -- .planning/tracking.json`);
160
+ _trace("warn", { error: err.message });
147
161
  }
148
162
 
149
163
  process.exit(0);
@@ -0,0 +1,62 @@
1
+ #!/usr/bin/env node
2
+ // hooks/supabase-destructive-guard.js — block destructive Supabase CLI commands.
3
+ // PreToolUse hook on `Bash`. Exits 2 to BLOCK, 0 to allow.
4
+ //
5
+ // Blocked: supabase db reset, supabase db push --force, supabase migration repair.
6
+ // Escape: QUALIA_ALLOW_DESTRUCTIVE=1 (shared with git-guardrails.js).
7
+ // Why: DB wipes left orphan rows requiring full re-wipe (insights friction).
8
+
9
+ const fs = require("fs");
10
+ const path = require("path");
11
+ const os = require("os");
12
+
13
+ const _traceStart = Date.now();
14
+ function _trace(result, extra) {
15
+ try {
16
+ const traceDir = path.join(os.homedir(), ".claude", ".qualia-traces");
17
+ if (!fs.existsSync(traceDir)) fs.mkdirSync(traceDir, { recursive: true });
18
+ const entry = {
19
+ hook: "supabase-destructive-guard", result,
20
+ timestamp: new Date().toISOString(),
21
+ duration_ms: Date.now() - _traceStart, ...extra,
22
+ };
23
+ const file = path.join(traceDir, `${new Date().toISOString().split("T")[0]}.jsonl`);
24
+ fs.appendFileSync(file, JSON.stringify(entry) + "\n");
25
+ } catch {}
26
+ }
27
+
28
+ const DESTRUCTIVE = [
29
+ /\b(npx\s+)?supabase\s+db\s+reset\b/,
30
+ /\b(npx\s+)?supabase\s+db\s+push\s+.*--force\b/,
31
+ /\b(npx\s+)?supabase\s+migration\s+repair\b/,
32
+ ];
33
+
34
+ // Read hook payload from stdin.
35
+ let payload = "";
36
+ try { if (!process.stdin.isTTY) payload = fs.readFileSync(0, "utf8"); } catch {}
37
+ let command = "";
38
+ try { if (payload) command = (JSON.parse(payload).tool_input || {}).command || ""; } catch {}
39
+
40
+ if (!command) { _trace("allow", { reason: "no-command" }); process.exit(0); }
41
+
42
+ const matched = DESTRUCTIVE.find((re) => re.test(command));
43
+ if (!matched) { _trace("allow", {}); process.exit(0); }
44
+
45
+ const preview = command.slice(0, 80);
46
+
47
+ if (process.env.QUALIA_ALLOW_DESTRUCTIVE === "1") {
48
+ console.error("Warning: Destructive Supabase command allowed by QUALIA_ALLOW_DESTRUCTIVE=1");
49
+ _trace("bypassed", { pattern_matched: matched.source, command_preview: preview });
50
+ process.exit(0);
51
+ }
52
+
53
+ const msg = [
54
+ `BLOCKED: destructive Supabase command: \`${preview}\`.`,
55
+ "This will destroy production data.",
56
+ "Run with QUALIA_ALLOW_DESTRUCTIVE=1 if intentional,",
57
+ "OR use safer alternatives: `supabase db diff` to preview,",
58
+ "`supabase migration new` to add reversible changes.",
59
+ ].join(" ");
60
+ console.error(msg);
61
+ _trace("block", { pattern_matched: matched.source, command_preview: preview });
62
+ process.exit(2);