qualia-framework 6.2.10 → 6.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.
Files changed (58) hide show
  1. package/AGENTS.md +1 -0
  2. package/CLAUDE.md +1 -0
  3. package/README.md +16 -23
  4. package/bin/cli.js +49 -2
  5. package/bin/command-surface.js +71 -0
  6. package/bin/harness-eval.js +296 -0
  7. package/bin/install.js +17 -20
  8. package/bin/knowledge-flush.js +21 -10
  9. package/bin/knowledge.js +1 -1
  10. package/bin/project-snapshot.js +20 -0
  11. package/bin/report-payload.js +18 -0
  12. package/bin/runtime-manifest.js +3 -0
  13. package/bin/state.js +31 -0
  14. package/bin/trust-score.js +3 -11
  15. package/bin/work-packet.js +228 -0
  16. package/docs/erp-contract.md +81 -1
  17. package/docs/onboarding.html +0 -11
  18. package/guide.md +14 -15
  19. package/hooks/fawzi-approval-guard.js +143 -0
  20. package/hooks/pre-deploy-gate.js +74 -1
  21. package/hooks/session-start.js +29 -1
  22. package/package.json +1 -1
  23. package/qualia-design/frontend.md +2 -2
  24. package/rules/codex-goal.md +1 -1
  25. package/rules/one-opinion.md +2 -2
  26. package/rules/speed.md +0 -1
  27. package/skills/qualia/SKILL.md +4 -4
  28. package/skills/qualia-feature/SKILL.md +1 -1
  29. package/skills/qualia-fix/SKILL.md +4 -4
  30. package/skills/qualia-learn/SKILL.md +1 -1
  31. package/skills/qualia-polish/REFERENCE.md +1 -1
  32. package/skills/qualia-polish/SKILL.md +19 -4
  33. package/skills/{qualia-vibe/scripts/extract.mjs → qualia-polish/scripts/vibe-extract.mjs} +4 -4
  34. package/skills/{qualia-vibe/scripts/tokens.mjs → qualia-polish/scripts/vibe-tokens.mjs} +6 -6
  35. package/skills/qualia-road/SKILL.md +15 -20
  36. package/skills/qualia-ship/SKILL.md +12 -5
  37. package/skills/qualia-verify/SKILL.md +9 -1
  38. package/templates/help.html +1 -12
  39. package/tests/bin.test.sh +144 -72
  40. package/tests/hooks.test.sh +81 -1
  41. package/tests/install-smoke.test.sh +13 -3
  42. package/tests/lib.test.sh +145 -3
  43. package/tests/published-install-smoke.test.sh +4 -3
  44. package/tests/refs.test.sh +9 -4
  45. package/tests/runner.js +29 -28
  46. package/tests/state.test.sh +68 -0
  47. package/skills/qualia-debug/SKILL.md +0 -193
  48. package/skills/qualia-flush/SKILL.md +0 -198
  49. package/skills/qualia-help/SKILL.md +0 -74
  50. package/skills/qualia-hook-gen/SKILL.md +0 -206
  51. package/skills/qualia-idk/SKILL.md +0 -166
  52. package/skills/qualia-issues/SKILL.md +0 -151
  53. package/skills/qualia-pause/SKILL.md +0 -68
  54. package/skills/qualia-resume/SKILL.md +0 -52
  55. package/skills/qualia-skill-new/SKILL.md +0 -173
  56. package/skills/qualia-triage/SKILL.md +0 -152
  57. package/skills/qualia-vibe/SKILL.md +0 -229
  58. package/skills/qualia-zoom/SKILL.md +0 -51
@@ -1,193 +0,0 @@
1
- ---
2
- name: qualia-debug
3
- description: "Investigation lane for unclear bugs and weird behavior. Parses symptoms, runs diagnostic scans, identifies root cause, and either reports insufficient evidence or routes actionable repair work to /qualia-fix. Trigger on 'debug', 'find bug', 'why is this broken', 'something is weird', 'investigate', 'root cause', 'not sure what's failing', 'CSS issue', 'slow page', 'performance'."
4
- allowed-tools:
5
- - Bash
6
- - Read
7
- - Edit
8
- - Write
9
- - Grep
10
- - Glob
11
- - Agent
12
- ---
13
-
14
- # /qualia-debug — Investigative Debugging (one-shot)
15
-
16
- Parse the symptom. Run diagnostics. Find root cause. Write report, or route to `/qualia-fix` when the repair is actionable. **One-shot — no mandatory user questions.**
17
-
18
- ## Usage
19
-
20
- - `/qualia-debug {symptom}` — investigate a specific symptom
21
- - `/qualia-debug` — no symptom given: investigate recently-changed files for obvious bugs
22
- - `/qualia-debug --frontend {symptom}` — layout/z-index/overflow bias
23
- - `/qualia-debug --perf {symptom}` — performance bias
24
-
25
- If the user says "fix it" and the expected behavior is known, prefer `/qualia-fix`. Debug is for uncertainty; fix is for repair.
26
-
27
- ## Tool Budget
28
-
29
- Max 10 Read/Grep/Bash calls for investigation. If you haven't narrowed to root cause in 10, return `INSUFFICIENT EVIDENCE after 10 steps. Narrowed to: {files}. Recommend: {next diagnostic}.` Do not keep guessing.
30
-
31
- ## Process
32
-
33
- ```bash
34
- node ${QUALIA_BIN}/qualia-ui.js banner debug
35
- ```
36
-
37
- ### 1. Parse Symptom from $ARGUMENTS
38
-
39
- - If arguments provided → that's the symptom. Extract: what's broken, where (file/page/feature), when (on click? on load? after change?).
40
- - If arguments empty → run `git diff HEAD~3 --stat` to find recently-touched files. Treat those as the suspect set. Symptom = "something in recent changes".
41
-
42
- ### 2. Check Known Fixes First (cheap)
43
-
44
- ```bash
45
- node ${QUALIA_BIN}/knowledge.js search "{symptom_keywords}"
46
- ```
47
-
48
- If a known fix matches, apply it and jump to step 5 (verify). Known fixes are pre-verified patterns — no need to re-investigate.
49
-
50
- ### 3. Diagnostic Scan
51
-
52
- Run the scan matching the symptom type. All commands in a scan block run as parallel Bash calls in a single response turn.
53
-
54
- **General mode (default):**
55
- ```bash
56
- # Compile errors
57
- npx tsc --noEmit 2>&1 | grep "error TS" | head -20
58
-
59
- # Empty catch / swallowed errors
60
- grep -rn "catch\s*{}\|catch\s*(.*)\s*{\s*}" --include="*.ts" --include="*.tsx" app/ components/ src/ lib/ 2>/dev/null | head -10
61
-
62
- # Recent console.error or thrown errors
63
- grep -rn "console\.error\|throw new" --include="*.ts" --include="*.tsx" app/ components/ src/ lib/ 2>/dev/null | head -10
64
-
65
- # Broken imports
66
- npx tsc --noEmit 2>&1 | grep -i "Cannot find module\|has no exported"
67
- ```
68
-
69
- **Frontend mode (`--frontend`):**
70
- ```bash
71
- # Stacking context audit (z-index issues)
72
- grep -rn "z-index\|z-\[" --include="*.tsx" --include="*.css" app/ components/ src/ 2>/dev/null | head -20
73
-
74
- # Overflow candidates (horizontal scroll, clipping)
75
- grep -rn "100vw\|overflow.*hidden\|overflow-x\|position.*fixed" --include="*.tsx" --include="*.css" app/ components/ src/ 2>/dev/null | head -15
76
-
77
- # Fixed dimensions breaking mobile
78
- grep -rn "width:.*[0-9]\+px\|height:.*[0-9]\+px\|w-\[[0-9]\+px\|h-\[[0-9]\+px" --include="*.tsx" --include="*.css" app/ components/ src/ 2>/dev/null | grep -v "min-\|max-" | head -10
79
-
80
- # Flex/grid blowout candidates
81
- grep -rn "flex\|grid" --include="*.tsx" app/ components/ src/ 2>/dev/null | grep -v "min-w-0\|minmax(0" | wc -l
82
- ```
83
-
84
- **Perf mode (`--perf`):**
85
- ```bash
86
- # Sequential awaits that should be Promise.all
87
- grep -rn "const.*=.*await" --include="*.tsx" --include="*.ts" app/ src/ 2>/dev/null | grep -v "Promise.all\|Promise.allSettled" | head -15
88
-
89
- # Large files
90
- find app/ components/ src/ -name "*.tsx" -o -name "*.ts" 2>/dev/null | xargs wc -l 2>/dev/null | sort -rn | head -10
91
-
92
- # Missing next/image
93
- grep -rn "<img " --include="*.tsx" --include="*.jsx" app/ components/ src/ 2>/dev/null | grep -v "next/image" | wc -l
94
-
95
- # No dynamic imports (possible big bundles)
96
- grep -rn "import(\|next/dynamic" --include="*.tsx" --include="*.ts" app/ src/ 2>/dev/null | wc -l
97
-
98
- # Client-boundary usage
99
- grep -rln "'use client'" --include="*.tsx" app/ components/ src/ 2>/dev/null | wc -l
100
- ```
101
-
102
- ### 4. Form Hypothesis + Route or Apply Minimal Fix
103
-
104
- From the diagnostic output, state the root cause in one sentence with `file:line` citation. No hedging — either you have evidence or you write `INSUFFICIENT EVIDENCE` and return (step 6).
105
-
106
- If the user explicitly asked for repair and the fix is <= 3 files, route to `/qualia-fix {symptom}` with the root cause summary. If this debug invocation is already mid-repair, apply the minimal fix here for backward compatibility.
107
-
108
- Apply the minimal fix:
109
- - Only edit files whose contents caused the symptom
110
- - One concept per commit — don't fold in cleanup
111
- - Don't refactor adjacent code
112
- - If the fix touches > 3 files, stop and ask the user first (major refactor disguised as a debug)
113
-
114
- ### 5. Verify Fix
115
-
116
- ```bash
117
- # TypeScript still compiles?
118
- npx tsc --noEmit 2>&1 | grep -c "error TS" # Expect 0
119
-
120
- # Symptom reproduction — ideally a grep that would have matched the bug
121
- # and now returns empty:
122
- grep -rn "{pattern that represented the bug}" {scope} 2>/dev/null
123
- ```
124
-
125
- If the verification fails, revert and return to step 3 with narrower hypothesis.
126
-
127
- ### 6. Write DEBUG Report
128
-
129
- Create the report directory and write to `.planning/reports/debug/DEBUG-{YYYY-MM-DD-HHMM}.md`:
130
-
131
- ```bash
132
- mkdir -p .planning/reports/debug
133
- ```
134
-
135
- ```markdown
136
- # Debug Report — {YYYY-MM-DD HH:MM}
137
-
138
- **Symptom:** {user description or "recent changes" if no args}
139
- **Mode:** general | frontend | perf
140
- **Tool calls used:** {N}/10
141
-
142
- ## Investigation
143
- - Diagnostic scans run: {list}
144
- - Files examined: {list}
145
- - Patterns searched: {list}
146
-
147
- ## Root Cause
148
- {file:line} — "{quoted problematic code}" — {explanation of why it caused the symptom}
149
-
150
- ## Fix Applied
151
- - Files: {list}
152
- - Diff summary: {one paragraph}
153
- - Verification: {commands run + results}
154
-
155
- ## Related Observations
156
- - {any adjacent issues noticed but NOT fixed in this debug pass}
157
- ```
158
-
159
- ### 7. Commit
160
-
161
- ```bash
162
- git add {specific files you changed}
163
- git commit -m "fix: {what was broken and why}"
164
- ```
165
-
166
- ## INSUFFICIENT EVIDENCE Return
167
-
168
- If you exhaust the 10-call budget without a confident root cause:
169
-
170
- ```markdown
171
- # Debug Report — {YYYY-MM-DD HH:MM}
172
-
173
- **Symptom:** {description}
174
- **Outcome:** INSUFFICIENT EVIDENCE after 10 inspection steps
175
-
176
- ## Narrowed To
177
- - Files examined: {list}
178
- - Ruled out: {list}
179
- - Remaining suspects: {list}
180
-
181
- ## Recommended Next Diagnostic
182
- - {specific next step for the user — e.g., "run `npm run dev` and watch browser console for the specific error", or "add console.log at file:line and reproduce"}
183
- ```
184
-
185
- Do NOT apply a speculative fix. Return the report and stop.
186
-
187
- ## Rules
188
-
189
- - **No mandatory questions.** This is one-shot. If symptom args are missing, investigate recent changes.
190
- - **Root cause or INSUFFICIENT EVIDENCE** — no "probably" fixes.
191
- - **Minimal fix only.** One concept, one commit. No refactors dressed as debug. Prefer `/qualia-fix` for explicit repair requests.
192
- - **Tool budget is hard.** 10 calls, then stop.
193
- - **Every investigation gets a DEBUG report in `.planning/reports/debug/`** — creates a searchable record without cluttering the root.
@@ -1,198 +0,0 @@
1
- ---
2
- name: qualia-flush
3
- description: "Promote daily-log raw entries to the curated knowledge tier — Karpathy-style raw→wiki flush. Reads ${QUALIA_KNOWLEDGE}/daily-log/*.md, identifies recurring patterns and decisions, writes them to ${QUALIA_KNOWLEDGE}/concepts/{topic}.md, updates index.md. Trigger on 'flush memory', 'promote learnings', 'consolidate logs', 'qualia-flush', 'process daily logs', or run weekly."
4
- allowed-tools:
5
- - Bash
6
- - Read
7
- - Write
8
- - Edit
9
- - Grep
10
- - Glob
11
- ---
12
-
13
- # /qualia-flush — Promote Raw Daily Logs to Curated Concepts
14
-
15
- Closes the **raw → wiki** loop in the Qualia memory layer. The Stop hook
16
- (`hooks/stop-session-log.js`) appends mechanical session checkpoints to
17
- `${QUALIA_KNOWLEDGE}/daily-log/{date}.md`.
18
- Those entries accumulate but stay raw — they describe what happened, not
19
- what to do about it. This skill reads the recent daily-log entries with an
20
- LLM (you) and writes durable concepts that the builder, planner, and
21
- debug skills will surface later via `node ${QUALIA_BIN}/knowledge.js`.
22
-
23
- Inspired by Karpathy's LLM knowledge bases and Cole Medin's self-evolving
24
- Claude memory pattern (NotebookLM, 2026-04-25). Both run a daily/weekly
25
- flush that promotes raw observations into structured wiki articles. We do
26
- the same — manually-triggered, internal-data only, no vector DB.
27
-
28
- ## When to run
29
-
30
- - **Manually:** `/qualia-flush` whenever the daily-log feels rich. Once a week
31
- is the recommended cadence. More than once a day is wasteful — the
32
- signal-to-noise ratio is too low at single-day windows.
33
- - **CLI runner:** `qualia-framework flush` wraps the cron-friendly
34
- `bin/knowledge-flush.js` non-interactive runner.
35
-
36
- ## Inputs
37
-
38
- - `--days N` (optional, default 14) — how many days of daily-log to consider
39
- - `--project NAME` (optional) — only flush entries for one project
40
- - `--dry-run` (optional) — print the proposed writes, don't touch disk
41
-
42
- If the user invokes the skill bare (no args), default to `--days 14` and
43
- all projects. Show a one-line preview before writing anything destructive.
44
-
45
- ## Process
46
-
47
- ### 1. Banner + check the floor
48
-
49
- ```bash
50
- node ${QUALIA_BIN}/qualia-ui.js banner flush 2>/dev/null || true
51
-
52
- # Resolve the knowledge dir. Fail loud if it doesn't exist — flush is
53
- # meaningless without a daily-log to read.
54
- KNOWLEDGE_DIR="$HOME/.claude/knowledge"
55
- DAILY_DIR="$KNOWLEDGE_DIR/daily-log"
56
- if [ ! -d "$DAILY_DIR" ]; then
57
- echo "QUALIA: No daily-log at $DAILY_DIR — Stop hook hasn't run yet, or knowledge layer wasn't initialized."
58
- echo "Run: npx qualia-framework@latest install"
59
- exit 1
60
- fi
61
-
62
- # Default 14-day window. Date math is cross-platform-safe with Node.
63
- WINDOW_DAYS="${WINDOW_DAYS:-14}"
64
- node -e "
65
- const d = new Date();
66
- d.setDate(d.getDate() - $WINDOW_DAYS);
67
- console.log(d.toISOString().split('T')[0]);
68
- " > /tmp/qualia-flush-cutoff
69
- CUTOFF=$(cat /tmp/qualia-flush-cutoff)
70
- ```
71
-
72
- ### 2. Collect the daily-log entries in window
73
-
74
- ```bash
75
- # Iterate every file in daily-log/ whose name (YYYY-MM-DD.md) is >= CUTOFF.
76
- # Concatenate them into one stream so the LLM (you) can scan as one corpus.
77
- ls "$DAILY_DIR"/*.md 2>/dev/null | while read -r f; do
78
- base=$(basename "$f" .md)
79
- if [ "$base" \> "$CUTOFF" ] || [ "$base" = "$CUTOFF" ]; then
80
- echo "=== $base ==="
81
- cat "$f"
82
- echo ""
83
- fi
84
- done
85
- ```
86
-
87
- You now have the raw stream. Read it.
88
-
89
- ### 3. Identify what's worth promoting
90
-
91
- Read every entry. Group by project. Look for these signals — these are
92
- the things that promote into the wiki:
93
-
94
- | Signal in raw entry | What to extract | Goes to |
95
- |---|---|---|
96
- | Same fix appears in 2+ sessions | A common fix recipe | `common-fixes.md` (via `knowledge.js append --type fix`) |
97
- | A pattern shows up in 3+ projects | A reusable pattern | `learned-patterns.md` (via `knowledge.js append --type pattern`) |
98
- | A client-name or project preference recurs | A client preference | `client-prefs.md` (via `knowledge.js append --type client`) |
99
- | A new technology/library used successfully | A stack note | `concepts/{tech}.md` (new file, Write directly) |
100
- | A recurring failure mode (verify-fail, regression) | A pitfall | `learned-patterns.md` framed as "anti-pattern: …" |
101
-
102
- Things to **NOT** promote:
103
- - Single-occurrence quirks (they're noise until they recur).
104
- - Bare commit/branch info — that's already in git, no value duplicating.
105
- - Anything containing secrets, tokens, customer PII. The knowledge layer
106
- is plain markdown, never put secrets here.
107
- - Entries from `--dry-run` runs of other skills (they'll show as activity
108
- but didn't actually do anything).
109
-
110
- ### 4. Write the promotions
111
-
112
- For each thing worth promoting, use the loader's `append`:
113
-
114
- ```bash
115
- node ${QUALIA_BIN}/knowledge.js append \
116
- --type {pattern|fix|client} \
117
- --title "{Concise title — what's the recurring thing?}" \
118
- --body "{The promoted lesson. Be specific. Include the project name(s) and dates where this pattern was observed so future you can verify.}" \
119
- --project "{specific project, or 'general' if cross-project}" \
120
- --context "Promoted by /qualia-flush from daily-log entries on {dates}"
121
- ```
122
-
123
- For a brand-new topic that doesn't fit pattern/fix/client (e.g. a Stripe
124
- integration approach worth its own file), Write to
125
- `${QUALIA_KNOWLEDGE}/concepts/{topic}.md`. Then **update `index.md`** so the
126
- new file is reachable — list it under "What's where" with one line:
127
-
128
- ```bash
129
- # After writing concepts/stripe-checkout.md:
130
- node ${QUALIA_BIN}/knowledge.js path stripe-checkout
131
- # Returned path = ${QUALIA_KNOWLEDGE}/stripe-checkout.md (NOTE: top-level, not concepts/)
132
- ```
133
-
134
- > **Loader behavior:** `knowledge.js load <name>` resolves bare names by walking
135
- > top-level + subdirectories (`concepts/`, `daily-log/`) for an exact match.
136
- > Write durable entries to `concepts/{topic}.md`; the loader will find them.
137
-
138
- ### 5. Mark the window as flushed
139
-
140
- Write a stamp file so subsequent flushes can default to "since the last
141
- flush" instead of "last 14 days":
142
-
143
- ```bash
144
- date -u +%Y-%m-%dT%H:%M:%SZ > "$HOME/.claude/.qualia-last-flush"
145
- ```
146
-
147
- ### 6. Summarize
148
-
149
- Print to the user, in plain language:
150
-
151
- - N daily-log files scanned (date range)
152
- - M promotions written (with file:title for each)
153
- - K things considered but not promoted (single-occurrence — wait for them to recur)
154
-
155
- Format:
156
-
157
- ```
158
- ⬢ Flushed daily-log {start} → {end} ({N} files, {total entries} entries)
159
- Promoted to wiki:
160
- + learned-patterns.md "Supabase RLS in same migration" (3 sessions, 2 projects)
161
- + common-fixes.md "next/font crash on Vercel" (2 sessions)
162
- + concepts/voice-agent-call-state.md (new file)
163
- Skipped {K} single-occurrence entries — will revisit if they recur.
164
- ```
165
-
166
- ## Style
167
-
168
- - **Be conservative.** False-positive promotions (writing noise as if it's a
169
- pattern) pollute the wiki and erode trust. Better to skip a candidate and
170
- let it recur next week than to inflate the curated tier.
171
- - **Cite your sources.** Every promoted entry should reference the
172
- daily-log dates that sourced it, in the `--context` field. If a future
173
- flush wants to update it, the trail is there.
174
- - **Keep titles short.** `--title "Supabase RLS same migration"` not `"You should always remember that when working with Supabase you need to..."`. The body is for nuance.
175
- - **Don't promote private projects across boundaries.** A pattern from
176
- Project A is fine to promote as cross-project ONLY if it generalizes.
177
- Client-specific things stay client-specific (`--type client --project X`).
178
-
179
- ## Anti-patterns
180
-
181
- - **Mass-promoting everything:** if you found "promotions" for 90% of
182
- daily-log entries, you're labeling, not promoting. Be selective.
183
- - **Re-promoting on every flush:** before appending, run
184
- `node ${QUALIA_BIN}/knowledge.js search "{title keywords}"` to check if
185
- the pattern already exists. If it does, either update it (find by `**ID:**`
186
- line) or skip — never duplicate.
187
- - **Hand-writing to `learned-patterns.md` etc. directly:** always go
188
- through `knowledge.js append` so the canonical entry format and ID
189
- generation stay consistent. This skill is the only sanctioned promoter,
190
- but even it uses the loader for writes.
191
-
192
- ## Output contract
193
-
194
- If invoked with `--dry-run`, print the proposed writes and exit without
195
- touching disk. Otherwise, after step 6 returns the summary, the skill is
196
- done — no follow-up prompts. The user sees the summary and the wiki tier
197
- has new entries that are immediately reachable to every other skill via
198
- the loader.
@@ -1,74 +0,0 @@
1
- ---
2
- name: qualia-help
3
- description: "Open the BROWSER HTML reference for the Qualia Framework — themed page with all commands, rules, services, and the road. The default when a browser is available. For terminal-only output (SSH, headless), use /qualia-road. Triggers: 'help', 'how does this work', 'show me the commands', 'qualia help', 'reference', 'open the docs'."
4
- allowed-tools:
5
- - Bash
6
- - Read
7
- ---
8
-
9
- # /qualia-help — Framework Reference
10
-
11
- Opens a Qualia-themed HTML reference guide in your default browser.
12
-
13
- ## Process
14
-
15
- ### 1. Generate the HTML
16
-
17
- ```bash
18
- # Read the template and inject the current version.
19
- # Prefer .qualia-config.json; fall back to the framework package.json; last resort is the
20
- # literal string "latest" so the UI never lies about a specific version.
21
- VERSION=$(node -e "
22
- const fs = require('fs'), path = require('path'), os = require('os');
23
- const cfg = path.join(os.homedir(), '.claude', '.qualia-config.json');
24
- const pkg = path.join(os.homedir(), '.claude', 'qualia-framework', 'package.json');
25
- try { const v = JSON.parse(fs.readFileSync(cfg,'utf8')).version; if (v) { console.log(v); process.exit(0); } } catch {}
26
- try { const v = JSON.parse(fs.readFileSync(pkg,'utf8')).version; if (v) { console.log('v'+v); process.exit(0); } } catch {}
27
- console.log('latest');
28
- " 2>/dev/null || echo "latest")
29
- TEMPLATE="$HOME/.claude/qualia-templates/help.html"
30
- OUTPUT="/tmp/qualia-help.html"
31
-
32
- # If template doesn't exist in the user home, check the installed framework copy.
33
- if [ ! -f "$TEMPLATE" ]; then
34
- for CANDIDATE in "$HOME/.claude/qualia-framework/templates/help.html"; do
35
- if [ -f "$CANDIDATE" ]; then TEMPLATE="$CANDIDATE"; break; fi
36
- done
37
- fi
38
- ```
39
-
40
- ### 2. Inject version and open
41
-
42
- ```bash
43
- # Replace {{VERSION}} placeholder with actual version
44
- sed "s/{{VERSION}}/$VERSION/g" "$TEMPLATE" > "$OUTPUT"
45
-
46
- # Open in default browser (cross-platform)
47
- if command -v xdg-open &>/dev/null; then
48
- xdg-open "$OUTPUT" # Linux
49
- elif command -v open &>/dev/null; then
50
- open "$OUTPUT" # macOS
51
- elif command -v start &>/dev/null; then
52
- start "$OUTPUT" # Windows (Git Bash)
53
- else
54
- echo "Open this file in your browser: $OUTPUT"
55
- fi
56
- ```
57
-
58
- ### 3. Confirm
59
-
60
- ```bash
61
- node ${QUALIA_BIN}/qualia-ui.js banner router
62
- node ${QUALIA_BIN}/qualia-ui.js ok "Reference guide opened in browser"
63
- node ${QUALIA_BIN}/qualia-ui.js info "File: /tmp/qualia-help.html"
64
- ```
65
-
66
- If the browser does not open automatically, tell the user the file path so they can open it manually.
67
-
68
- ## Notes
69
-
70
- - The HTML file is self-contained — no external dependencies except Google Fonts
71
- - Works offline after first load (fonts cache)
72
- - Qualia-themed: dark background, teal accents, Outfit + Inter fonts
73
- - Shows: The Road, all commands grouped, verification scoring, rules, stack, GitHub orgs
74
- - Version is injected dynamically from .qualia-config.json
@@ -1,206 +0,0 @@
1
- ---
2
- name: qualia-hook-gen
3
- description: "Take a project's CLAUDE.md or rules/*.md instruction and convert it deterministically into a Claude Code pre-tool-use hook. Generates block-{cmd}.sh + the settings.json patch + activation steps. Lets users actually shrink their CLAUDE.md instead of just hearing the instruction-budget advice. Trigger on 'qualia-hook-gen', 'turn this rule into a hook', 'enforce this deterministically', 'block npm', 'force pnpm', 'convert claude.md to hooks', 'shrink my instruction budget'."
4
- allowed-tools:
5
- - Bash
6
- - Read
7
- - Write
8
- - Edit
9
- - Grep
10
- - Glob
11
- argument-hint: "[--rule \"text\"] [--from CLAUDE.md] [--name HOOK_NAME] [--scope global|project] [--dry-run]"
12
- ---
13
-
14
- # /qualia-hook-gen — Convert instructions → deterministic hooks
15
-
16
- LLMs have a realistic instruction budget of ~300-500 instructions before quality degrades (Matt Pocock). A line in CLAUDE.md like "use pnpm not npm" burns budget on EVERY request — even when the task has nothing to do with package management. Worse, it's non-deterministic: the model can still run `npm install` if it forgets.
17
-
18
- The fix: convert that instruction into a deterministic `pre-tool-use` hook. The hook blocks the wrong command (or rewrites it to the right one) at execution time, frees the instruction budget, and works regardless of context window state.
19
-
20
- ## When to use
21
-
22
- - Your CLAUDE.md has 50+ lines and you want to slim it
23
- - A specific instruction is enforceable as a CLI rule (use X not Y, never run Z, redirect A to B)
24
- - You want a hook for a specific failure mode (e.g., "always use --force-with-lease, never --force")
25
-
26
- ## What it does NOT do
27
-
28
- - Hooks for stylistic guidance (e.g., "prefer composition over inheritance") — that's not enforceable by command match. Stays in skills.
29
- - Hooks for non-deterministic checks (e.g., "validate the design feel"). Use `/qualia-polish` instead.
30
- - Hooks that need state across multiple commands. Use Qualia's existing state.js machinery.
31
-
32
- ## Process
33
-
34
- ### 1. Identify the rule
35
-
36
- Three input modes:
37
-
38
- | Mode | Source |
39
- |---|---|
40
- | `--rule "..."` | Direct argument (e.g. `--rule "use pnpm not npm"`) |
41
- | `--from CLAUDE.md` | Pull instructions from the file, list them, let user pick |
42
- | (no arg) | Read CLAUDE.md, scan for enforceable rules, propose top 3 candidates |
43
-
44
- ### 2. Classify enforceability
45
-
46
- For the chosen rule, classify into one of three patterns:
47
-
48
- | Pattern | Example | Hook shape |
49
- |---|---|---|
50
- | **Block** | "never use `git push --force` to main" | exit 2 with message if pattern matches |
51
- | **Rewrite** | "use pnpm not npm" | exit 2 with message guiding to alternative |
52
- | **Warn** | "prefer next/image over <img>" | exit 0 but print warning to stderr |
53
-
54
- If the rule isn't classifiable as any of these — i.e. it's stylistic or judgment-based — HALT with: "This rule isn't deterministically enforceable. Keep it in CLAUDE.md or move to a skill. Examples of enforceable rules: package-manager redirects, destructive-command blocks, file-path enforcement."
55
-
56
- ### 3. Generate the hook script
57
-
58
- Write to `hooks/block-{name}.js` (Node, cross-platform — same shape as existing hooks):
59
-
60
- ```javascript
61
- #!/usr/bin/env node
62
- // hooks/block-{name}.js — auto-generated by /qualia-hook-gen
63
- // Original instruction: "{rule text}"
64
- // Pattern: {block | rewrite | warn}
65
- // Generated: {ISO date}
66
-
67
- const { readFileSync } = require("fs");
68
- let payload;
69
- try { payload = JSON.parse(readFileSync(0, "utf8")); } catch { process.exit(0); }
70
- const cmd = (payload.tool_input && payload.tool_input.command) || "";
71
-
72
- // Match condition (regex from rule classification)
73
- if (!/{matcher}/i.test(cmd)) process.exit(0); // not our concern
74
-
75
- // Action
76
- console.error("⚠ Qualia hook ({name}): {message}");
77
- console.error(" Suggested: {suggested_alt}");
78
- process.exit(2); // 2 = BLOCK in Claude Code hook protocol
79
- ```
80
-
81
- The exact matcher + message + suggestion are filled by the synthesizer based on the rule classification.
82
-
83
- ### 4. Generate the settings.json patch
84
-
85
- ```json
86
- {
87
- "hooks": {
88
- "PreToolUse": [
89
- {
90
- "matcher": "Bash",
91
- "hooks": [
92
- {
93
- "type": "command",
94
- "if": "Bash({if-condition})",
95
- "command": "node \"${HOME}/.claude/hooks/block-{name}.js\"",
96
- "timeout": 5,
97
- "statusMessage": "⬢ Checking {what}..."
98
- }
99
- ]
100
- }
101
- ]
102
- }
103
- }
104
- ```
105
-
106
- The `if` condition narrows when the hook fires (e.g., `Bash(npm*)` to fire only on npm). Saves cycles by skipping the hook entirely on irrelevant commands.
107
-
108
- ### 5. Test the hook
109
-
110
- ```bash
111
- # Simulate a triggering command
112
- echo '{"tool_input":{"command":"{triggering_example}"}}' | \
113
- node hooks/block-{name}.js
114
- echo "Exit: $?" # should be 2
115
-
116
- # Simulate a non-triggering command
117
- echo '{"tool_input":{"command":"{safe_example}"}}' | \
118
- node hooks/block-{name}.js
119
- echo "Exit: $?" # should be 0
120
- ```
121
-
122
- If the test passes, proceed. If not, debug the matcher regex.
123
-
124
- ### 6. Activate
125
-
126
- Two scopes:
127
-
128
- | Scope | Action |
129
- |---|---|
130
- | `--scope project` (default for project rules) | Add the patch to `.claude/settings.json` in the project root |
131
- | `--scope global` | Add to `${QUALIA_HOME}/settings.json`. Use only if rule applies to ALL projects |
132
-
133
- Use the existing settings-merge logic from `bin/install.js:756-778` (preserves user fields, atomic write, backup-before-overwrite).
134
-
135
- ### 7. Suggest CLAUDE.md slim
136
-
137
- After activating, scan CLAUDE.md / `rules/*.md` for the original instruction. If found, suggest the user remove it (don't auto-remove — let the user verify the hook works first):
138
-
139
- ```
140
- ✓ Hook installed: hooks/block-{name}.js
141
- ✓ Settings patched: .claude/settings.json
142
- ℹ You can now remove this line from CLAUDE.md (the hook enforces it deterministically):
143
- > "{original instruction}"
144
- ℹ Test with: echo '{"tool_input":{"command":"{triggering_example}"}}' | node hooks/block-{name}.js
145
- ```
146
-
147
- ### 8. Commit
148
-
149
- ```bash
150
- git add hooks/block-{name}.js .claude/settings.json
151
- git -c user.name="Qualia Solutions" -c user.email="info@qualiasolutions.net" \
152
- commit -m "feat(hook): block-{name} — enforces \"{rule}\" deterministically"
153
- ```
154
-
155
- ## Examples
156
-
157
- **Block npm in favor of pnpm:**
158
- ```
159
- /qualia-hook-gen --rule "use pnpm not npm"
160
- → hooks/block-npm.js (matches /^\s*npm\s+(install|i|run|exec)/, exit 2)
161
- → .claude/settings.json (PreToolUse > Bash > if: Bash(npm*))
162
- → "npm install" now blocks with: "Use pnpm not npm. Run: pnpm install"
163
- ```
164
-
165
- **Block destructive git on main:**
166
- ```
167
- /qualia-hook-gen --rule "never push --force to main"
168
- → hooks/block-force-push-main.js (matches /git push.*--force.*main/)
169
- → Already covered by hooks/git-guardrails.js — surface this overlap and skip
170
- ```
171
-
172
- **Force /server/ for service_role usage:**
173
- ```
174
- /qualia-hook-gen --rule "service_role only in lib/server/*"
175
- → Not enforceable as a CLI hook (it's a code-level rule).
176
- → HALT with recommendation: ESLint rule or pre-deploy-gate.js entry instead.
177
- ```
178
-
179
- ## Token discipline
180
-
181
- This skill itself is short by design (~150 lines SKILL.md). REFERENCE.md (if added later) only carries verbatim hook templates. The whole point of `/qualia-hook-gen` is to REDUCE token cost across a project, not add to it.
182
-
183
- Per-invocation: ~3K tokens for the rule-classification + hook-template synthesis. Net savings: every subsequent request saves the ~50-200 tokens that the moved CLAUDE.md instruction was costing.
184
-
185
- ## Failure modes
186
-
187
- | Symptom | Cause | Action |
188
- |---|---|---|
189
- | Rule isn't a CLI command | Stylistic / judgment-based | HALT with recommendation: skill or ESLint rule |
190
- | Matcher would catch too much | Regex too greedy | Tighten with `--name` and explicit pattern; user-confirm before write |
191
- | Hook conflicts with existing | Same command already hooked | Surface the conflict; refuse to overwrite without `--force` |
192
- | Settings.json malformed | Pre-existing bad JSON | Refuse to patch; ask user to fix settings.json first |
193
- | `node` not on hook PATH | Cross-platform issue | Use `process.execPath` resolution; framework's existing hooks handle this |
194
-
195
- ## Rules
196
-
197
- 1. **Hook is determinism, skill is guidance.** Hooks can only block/rewrite/warn on CLI patterns. Stylistic rules stay in skills.
198
- 2. **Never overwrite an existing hook silently.** If `hooks/block-{name}.js` exists, surface and ask.
199
- 3. **Test before committing.** The hook must pass the trigger + non-trigger smoke tests before commit.
200
- 4. **Suggest CLAUDE.md cleanup.** After install, surface the now-redundant CLAUDE.md line. Don't auto-delete — user verifies the hook works first.
201
- 5. **Match Qualia's hook shape.** All hooks are pure Node, cross-platform, exit 0/2. No `.sh` scripts (Windows compat).
202
-
203
- ## Pairs with
204
-
205
- - `/qualia-optimize --deepen` — runs sometimes after a hook-gen pass when CLAUDE.md gets short enough that the codebase architecture becomes the next bottleneck
206
- - Existing hooks: `git-guardrails.js`, `pre-deploy-gate.js`, `vercel-account-guard.js`, `env-empty-guard.js`, `supabase-destructive-guard.js`. New hooks generated by this skill follow the same conventions.