qualia-framework 6.2.9 → 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.
- package/AGENTS.md +1 -0
- package/CLAUDE.md +1 -0
- package/README.md +26 -30
- package/agents/builder.md +7 -7
- package/agents/planner.md +39 -3
- package/agents/research-synthesizer.md +1 -1
- package/agents/researcher.md +3 -3
- package/agents/roadmapper.md +7 -7
- package/agents/verifier.md +18 -6
- package/agents/visual-evaluator.md +8 -7
- package/bin/cli.js +160 -16
- package/bin/command-surface.js +71 -0
- package/bin/contract-runner.js +219 -0
- package/bin/harness-eval.js +296 -0
- package/bin/host-adapters.js +66 -0
- package/bin/install.js +116 -172
- package/bin/knowledge-flush.js +21 -10
- package/bin/knowledge.js +1 -1
- package/bin/plan-contract.js +99 -2
- package/bin/planning-hygiene.js +262 -0
- package/bin/project-snapshot.js +20 -0
- package/bin/report-payload.js +18 -0
- package/bin/runtime-manifest.js +35 -0
- package/bin/state-ledger.js +184 -0
- package/bin/state.js +330 -20
- package/bin/trust-score.js +268 -0
- package/bin/work-packet.js +228 -0
- package/docs/erp-contract.md +81 -1
- package/docs/onboarding.html +4 -14
- package/guide.md +16 -16
- package/hooks/fawzi-approval-guard.js +143 -0
- package/hooks/pre-deploy-gate.js +74 -1
- package/hooks/session-start.js +29 -1
- package/package.json +1 -1
- package/qualia-design/design-rubric.md +17 -5
- package/qualia-design/frontend.md +6 -2
- package/qualia-design/graphics.md +47 -0
- package/rules/codex-goal.md +1 -1
- package/rules/command-output.md +35 -0
- package/rules/one-opinion.md +2 -2
- package/rules/speed.md +0 -1
- package/skills/qualia/SKILL.md +12 -12
- package/skills/qualia-build/SKILL.md +20 -14
- package/skills/qualia-discuss/SKILL.md +10 -10
- package/skills/qualia-doctor/SKILL.md +140 -0
- package/skills/qualia-feature/SKILL.md +24 -22
- package/skills/qualia-fix/SKILL.md +216 -0
- package/skills/qualia-handoff/SKILL.md +9 -9
- package/skills/qualia-learn/SKILL.md +11 -11
- package/skills/qualia-map/SKILL.md +2 -2
- package/skills/qualia-milestone/SKILL.md +15 -15
- package/skills/qualia-new/REFERENCE.md +9 -9
- package/skills/qualia-new/SKILL.md +14 -14
- package/skills/qualia-optimize/REFERENCE.md +1 -1
- package/skills/qualia-optimize/SKILL.md +23 -16
- package/skills/qualia-plan/SKILL.md +23 -13
- package/skills/qualia-polish/REFERENCE.md +15 -15
- package/skills/qualia-polish/SKILL.md +81 -21
- package/skills/qualia-polish/scripts/loop.mjs +3 -3
- package/skills/qualia-polish/scripts/score.mjs +9 -3
- package/skills/{qualia-vibe/scripts/extract.mjs → qualia-polish/scripts/vibe-extract.mjs} +5 -5
- package/skills/{qualia-vibe/scripts/tokens.mjs → qualia-polish/scripts/vibe-tokens.mjs} +6 -6
- package/skills/qualia-postmortem/SKILL.md +9 -9
- package/skills/qualia-report/SKILL.md +23 -23
- package/skills/qualia-research/SKILL.md +5 -5
- package/skills/qualia-review/SKILL.md +28 -12
- package/skills/qualia-road/SKILL.md +30 -22
- package/skills/qualia-ship/SKILL.md +31 -24
- package/skills/qualia-test/SKILL.md +5 -5
- package/skills/qualia-verify/SKILL.md +45 -23
- package/skills/zoho-workflow/SKILL.md +1 -1
- package/templates/help.html +11 -20
- package/tests/bin.test.sh +178 -76
- package/tests/hooks.test.sh +81 -1
- package/tests/install-smoke.test.sh +35 -5
- package/tests/lib.test.sh +432 -0
- package/tests/published-install-smoke.test.sh +4 -3
- package/tests/refs.test.sh +9 -4
- package/tests/runner.js +32 -28
- package/tests/skills.test.sh +4 -4
- package/tests/state.test.sh +133 -3
- package/skills/qualia-debug/SKILL.md +0 -185
- package/skills/qualia-flush/SKILL.md +0 -198
- package/skills/qualia-help/SKILL.md +0 -74
- package/skills/qualia-hook-gen/SKILL.md +0 -206
- package/skills/qualia-idk/SKILL.md +0 -166
- package/skills/qualia-issues/SKILL.md +0 -151
- package/skills/qualia-pause/SKILL.md +0 -68
- package/skills/qualia-resume/SKILL.md +0 -52
- package/skills/qualia-skill-new/SKILL.md +0 -173
- package/skills/qualia-triage/SKILL.md +0 -152
- package/skills/qualia-vibe/SKILL.md +0 -226
- package/skills/qualia-zoom/SKILL.md +0 -51
package/docs/onboarding.html
CHANGED
|
@@ -496,9 +496,9 @@
|
|
|
496
496
|
<div class="kit-group">
|
|
497
497
|
<h4>Diagnose & fix</h4>
|
|
498
498
|
<dl>
|
|
499
|
-
<dt>/qualia-
|
|
500
|
-
<dt>/qualia-review</dt><dd>
|
|
501
|
-
<dt>/qualia-optimize</dt><dd>Deep
|
|
499
|
+
<dt>/qualia-fix</dt><dd>Repair lane. Finds root cause, applies a minimal fix, verifies it, writes a fix report.</dd>
|
|
500
|
+
<dt>/qualia-review</dt><dd>Read-only production audit with severity-scored findings. Run before a big deploy.</dd>
|
|
501
|
+
<dt>/qualia-optimize</dt><dd>Deep improvement map for performance, design, alignment, and architecture. Spawns parallel specialists.</dd>
|
|
502
502
|
<dt>/qualia-postmortem</dt><dd>Self-healing layer. After a failed verify, identifies which agent or rule should have caught it and proposes a delta.</dd>
|
|
503
503
|
</dl>
|
|
504
504
|
</div>
|
|
@@ -521,18 +521,14 @@
|
|
|
521
521
|
<div class="kit-group">
|
|
522
522
|
<h4>Build something small</h4>
|
|
523
523
|
<dl>
|
|
524
|
-
<dt>/qualia-feature</dt><dd>Auto-scoped: inline for trivia (
|
|
524
|
+
<dt>/qualia-feature</dt><dd>Auto-scoped: inline for trivia (copy, config tweak), fresh builder spawn for 1-5 file features. Broken existing behavior routes to /qualia-fix.</dd>
|
|
525
525
|
</dl>
|
|
526
526
|
</div>
|
|
527
527
|
<div class="kit-group">
|
|
528
528
|
<h4>Navigate the session</h4>
|
|
529
529
|
<dl>
|
|
530
530
|
<dt>/qualia</dt><dd>State router. Tells you the exact next command.</dd>
|
|
531
|
-
<dt>/qualia-idk</dt><dd>"Something feels off." Diagnoses confusion across .planning + codebase.</dd>
|
|
532
|
-
<dt>/qualia-pause</dt><dd>Save context for handoff to a future session.</dd>
|
|
533
|
-
<dt>/qualia-resume</dt><dd>Restore context and routing from a paused session.</dd>
|
|
534
531
|
<dt>/qualia-road</dt><dd>Terminal map of the workflow. Headless-friendly.</dd>
|
|
535
|
-
<dt>/qualia-help</dt><dd>Open this kind of reference in the browser.</dd>
|
|
536
532
|
</dl>
|
|
537
533
|
</div>
|
|
538
534
|
</div>
|
|
@@ -558,7 +554,6 @@
|
|
|
558
554
|
<h4>Code archaeology</h4>
|
|
559
555
|
<dl>
|
|
560
556
|
<dt>/qualia-map</dt><dd>Brownfield onboarding. Map an existing codebase before adding to it.</dd>
|
|
561
|
-
<dt>/qualia-zoom</dt><dd>Map a small, unfamiliar code area in domain-glossary terms.</dd>
|
|
562
557
|
</dl>
|
|
563
558
|
</div>
|
|
564
559
|
</div>
|
|
@@ -573,21 +568,16 @@
|
|
|
573
568
|
<h4>Knowledge</h4>
|
|
574
569
|
<dl>
|
|
575
570
|
<dt>/qualia-learn</dt><dd>Save a learning, pattern, fix, or client preference. Persists across projects and sessions.</dd>
|
|
576
|
-
<dt>/qualia-flush</dt><dd>Promote daily-log raw entries to the curated knowledge tier.</dd>
|
|
577
571
|
</dl>
|
|
578
572
|
</div>
|
|
579
573
|
<div class="kit-group">
|
|
580
574
|
<h4>Issue queue</h4>
|
|
581
575
|
<dl>
|
|
582
|
-
<dt>/qualia-issues</dt><dd>Break a phase plan into independent vertical-slice GitHub issues.</dd>
|
|
583
|
-
<dt>/qualia-triage</dt><dd>Route open issues into needs-info, ready-for-agent, ready-for-human.</dd>
|
|
584
576
|
</dl>
|
|
585
577
|
</div>
|
|
586
578
|
<div class="kit-group">
|
|
587
579
|
<h4>Extend the framework</h4>
|
|
588
580
|
<dl>
|
|
589
|
-
<dt>/qualia-skill-new</dt><dd>Author a new Qualia skill or agent.</dd>
|
|
590
|
-
<dt>/qualia-hook-gen</dt><dd>Convert an instruction into a deterministic Claude Code hook.</dd>
|
|
591
581
|
</dl>
|
|
592
582
|
</div>
|
|
593
583
|
<div class="kit-group">
|
package/guide.md
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
|
-
# Qualia Developer Guide (v6.
|
|
1
|
+
# Qualia Developer Guide (v6.3.0)
|
|
2
2
|
|
|
3
3
|
> Follow the road. Type the commands. The framework handles the rest.
|
|
4
4
|
> `--auto` chains the whole road end-to-end with only two human checkpoints per project.
|
|
5
5
|
|
|
6
|
-
**v6.
|
|
6
|
+
**v6.3.0 is the harness hardening patch.** The default command surface is 23 active skills, retired helper sources are removed and pruned from older installs, `/qualia-polish --vibe` absorbs the old vibe command, `qualia-framework eval --run --write` produces scored eval artifacts, and PASS transitions now require clean machine evidence when a phase contract exists.
|
|
7
|
+
|
|
8
|
+
**v6.2.7 carries forward.** Codex installs now get native `~/.codex/hooks.json`, TOML agents, bin scripts, rules, skills, templates, knowledge, guide, and role config in addition to `AGENTS.md`.
|
|
7
9
|
|
|
8
10
|
**v6.2.5 carries forward.** `qualia-framework project-snapshot --write` creates a single `.planning/snapshots/project-snapshot-*.json` artifact with project identifiers, current milestone/phase, closed milestones, lifetime counters, and a project progress percentage for explicit ERP/admin import.
|
|
9
11
|
|
|
@@ -13,9 +15,9 @@
|
|
|
13
15
|
|
|
14
16
|
**v6.2.2 carries forward.** Framework builds, Memory remembers, ERP operates. ERP work packets can seed Claude/Codex sessions, `/qualia-report` can carry ERP-native IDs, and release verification now has a public `@latest` install smoke.
|
|
15
17
|
|
|
16
|
-
**v6.2.1 carries forward.** Active docs match the v6.2 no-bot-commit model, the explicit `/qualia-report` ERP contract, the current
|
|
18
|
+
**v6.2.1 carries forward.** Active docs match the v6.2 no-bot-commit model, the explicit `/qualia-report` ERP contract, the current skill surface, and fail-closed `INSUFFICIENT EVIDENCE` behavior. `tests/refs.test.sh` guards those claims.
|
|
17
19
|
|
|
18
|
-
**v6.1.0 ships the design-pivot path you were missing.** New `/qualia-vibe` is fast aesthetic pivot (~3 min): swap design tokens, keep layout. Default proposes ONE direction per `rules/one-opinion.md` (the EventMaster discipline — never give the user a menu). Sub-modes: `--variants N` for the opt-in menu, `--extract URL` reverse-engineers DESIGN.md from a reference site, `--sync` shows code↔DESIGN.md drift and can patch DESIGN.md from code. Slop-detect grew banned fonts (Montserrat/Poppins/Lato/Open Sans) and a `--watch` flag for proactive single-file mode. Several design-surface bugs from v6.0 audit are fixed too (viewport mismatch, slop-detect path resolution in the polish loop, dead `/qualia-design` references, the bounce-easing token that contradicted design-laws).
|
|
20
|
+
**v6.1.0 ships the design-pivot path you were missing.** New `/qualia-polish --vibe` is fast aesthetic pivot (~3 min): swap design tokens, keep layout. Default proposes ONE direction per `rules/one-opinion.md` (the EventMaster discipline — never give the user a menu). Sub-modes: `--variants N` for the opt-in menu, `--extract URL` reverse-engineers DESIGN.md from a reference site, `--sync` shows code↔DESIGN.md drift and can patch DESIGN.md from code. Slop-detect grew banned fonts (Montserrat/Poppins/Lato/Open Sans) and a `--watch` flag for proactive single-file mode. Several design-surface bugs from v6.0 audit are fixed too (viewport mismatch, slop-detect path resolution in the polish loop, dead `/qualia-design` references, the bounce-easing token that contradicted design-laws).
|
|
19
21
|
|
|
20
22
|
**v6.2.0 removes hook-created bot commits.** `pre-push.js` stamps local `tracking.json` telemetry but no longer commits it. `pre-compact.js` is gone because `state.js` already gives stronger crash safety with atomic writes plus a journal. ERP sync remains explicit through `/qualia-report` POSTs, not passive git scraping.
|
|
21
23
|
|
|
@@ -25,7 +27,7 @@
|
|
|
25
27
|
|
|
26
28
|
**v5.9.0 carries forward.** `tests/refs.test.sh` catches dead command references in user-facing surfaces on every release. `bin/erp-retry.js` is a real persistent retry queue for ERP report uploads. Four structured agents (verifier, plan-checker, roadmapper, qa-browser) run on Sonnet for ~40% per-phase cost cut, while builder/planner/researcher/visual-evaluator stay on Opus where the architectural and vision reasoning lives. The verifier downgrades to FAIL on any `INSUFFICIENT EVIDENCE` line.
|
|
27
29
|
|
|
28
|
-
**Surface is
|
|
30
|
+
**Surface is 23 installed skills.** Use `/qualia-fix` for broken existing behavior, `/qualia-feature` for new single-feature work, and `/qualia-discuss` in PROJECT MODE for kickoff capture; `/qualia-polish --loop` for the autonomous visual loop; `/qualia-polish --vibe` for fast layout-preserving aesthetic pivots.
|
|
29
31
|
|
|
30
32
|
## The Road
|
|
31
33
|
|
|
@@ -81,20 +83,18 @@ Append `--auto` to `/qualia-new` and the framework chains every step:
|
|
|
81
83
|
| Single feature | `/qualia-feature` | Auto-scoped: inline for trivia, fresh spawn for 1-5 files |
|
|
82
84
|
| Finishing | `/qualia-polish` | Design and UX pass (scope-adaptive: component / route / app / redesign / critique / quick / loop) |
|
|
83
85
|
| | `/qualia-polish --loop` | Autonomous visual-polish loop: screenshot, vision-eval, fix, repeat |
|
|
84
|
-
| Pivot the vibe | `/qualia-vibe` | Fast aesthetic pivot (~3 min): swap tokens, keep layout. Propose ONE direction. |
|
|
85
|
-
| | `/qualia-vibe --extract <URL>` | Reverse-engineer DESIGN.md from a reference site |
|
|
86
|
-
| | `/qualia-vibe --sync` | Show / patch drift between code (CSS vars + Tailwind) and DESIGN.md |
|
|
86
|
+
| Pivot the vibe | `/qualia-polish --vibe` | Fast aesthetic pivot (~3 min): swap tokens, keep layout. Propose ONE direction. |
|
|
87
|
+
| | `/qualia-polish --vibe --extract <URL>` | Reverse-engineer DESIGN.md from a reference site |
|
|
88
|
+
| | `/qualia-polish --vibe --sync` | Show / patch drift between code (CSS vars + Tailwind) and DESIGN.md |
|
|
87
89
|
| | `/qualia-ship` | Deploy to production |
|
|
88
90
|
| | `/qualia-handoff` | Deliver to client (4 mandatory deliverables) |
|
|
89
91
|
| Reporting | `/qualia-report` | Log what you did (mandatory before clock-out) |
|
|
90
|
-
| Zooming in | `/qualia-zoom` | Focus on a single file or function with full context |
|
|
91
|
-
| Issues | `/qualia-issues` | Break a phase plan into vertical-slice GitHub issues |
|
|
92
|
-
| Triage | `/qualia-triage` | Triage open issues through the ready-for-agent state machine |
|
|
93
92
|
| Optimize | `/qualia-optimize --deepen` | Find shallow modules; v5.3+ spawns 3 parallel interface-design variants per candidate |
|
|
94
|
-
|
|
|
93
|
+
| Harness eval | `qualia-framework eval --run --write` | Run machine contract checks and write scored eval artifacts for ERP/reporting |
|
|
94
|
+
| Planning hygiene | `qualia-framework planning-hygiene scan` | Detect loose `.planning/` reports/assets before they turn into folder bloat |
|
|
95
95
|
| Road view | `/qualia-road` | View and navigate journey/milestone/phase status |
|
|
96
96
|
| Lost? | `/qualia` | Mechanical next-command router |
|
|
97
|
-
| Confused? | `/qualia
|
|
97
|
+
| Confused? | `/qualia` | Diagnostic — scans planning + code, explains what's going on |
|
|
98
98
|
|
|
99
99
|
## Full Journey Hierarchy
|
|
100
100
|
|
|
@@ -119,13 +119,13 @@ Hard rules (enforced by `state.js` and the roadmapper):
|
|
|
119
119
|
3. **MVP first** — build what's asked, nothing extra
|
|
120
120
|
4. **Every task has a `Why`** (story-file format) — if you can't explain why a task matters in one sentence, it probably shouldn't exist
|
|
121
121
|
5. **`/qualia` is your friend** — lost? type it
|
|
122
|
-
6. **`/qualia
|
|
122
|
+
6. **`/qualia` is your deeper friend** — not lost on "what command", but confused about the *situation*? Type `idk`.
|
|
123
123
|
|
|
124
124
|
## When You're Stuck
|
|
125
125
|
|
|
126
126
|
```
|
|
127
127
|
/qualia ← "what command should I run next?" (state-driven, instant)
|
|
128
|
-
/qualia
|
|
128
|
+
/qualia ← "what's actually going on here?" (diagnostic, scans planning + code, ~30s)
|
|
129
129
|
```
|
|
130
130
|
|
|
131
131
|
If neither helps, paste the error and ask Claude directly. If Claude can't fix it, tell Fawzi.
|
|
@@ -154,7 +154,7 @@ If neither helps, paste the error and ask Claude directly. If Claude can't fix i
|
|
|
154
154
|
| Starting a quick throwaway | `/qualia-new --quick` |
|
|
155
155
|
| Brownfield project | `/qualia-map` first, then `/qualia-new` |
|
|
156
156
|
| Stuck picking next command | `/qualia` |
|
|
157
|
-
| Confused about the situation | `/qualia
|
|
157
|
+
| Confused about the situation | `/qualia` |
|
|
158
158
|
| Finished the last phase of a milestone | `/qualia-milestone` |
|
|
159
159
|
| About to ship | `/qualia-ship` |
|
|
160
160
|
| Client is ready to take over | `/qualia-handoff` |
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// Silently records EMPLOYEE attempts to use "Fawzi said OK" style proxy
|
|
3
|
+
// approval. This hook never blocks and never prints: the policy text teaches
|
|
4
|
+
// the agent not to do it; this hook records when it still appears in tool input.
|
|
5
|
+
|
|
6
|
+
const fs = require("fs");
|
|
7
|
+
const path = require("path");
|
|
8
|
+
const os = require("os");
|
|
9
|
+
const crypto = require("crypto");
|
|
10
|
+
|
|
11
|
+
function qualiaHome() {
|
|
12
|
+
if (process.env.QUALIA_HOME) return process.env.QUALIA_HOME;
|
|
13
|
+
const parent = path.basename(path.dirname(__dirname));
|
|
14
|
+
if (parent === ".codex" || parent === ".claude") return path.dirname(__dirname);
|
|
15
|
+
return path.join(os.homedir(), ".claude");
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const QUALIA_HOME = qualiaHome();
|
|
19
|
+
const CONFIG = path.join(QUALIA_HOME, ".qualia-config.json");
|
|
20
|
+
const EVENT_FILE = path.join(QUALIA_HOME, ".approval-policy-events.json");
|
|
21
|
+
|
|
22
|
+
function readJson(file, fallback) {
|
|
23
|
+
try {
|
|
24
|
+
return JSON.parse(fs.readFileSync(file, "utf8"));
|
|
25
|
+
} catch {
|
|
26
|
+
return fallback;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function writeJson(file, data) {
|
|
31
|
+
try {
|
|
32
|
+
const dir = path.dirname(file);
|
|
33
|
+
if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
|
|
34
|
+
const tmp = `${file}.tmp.${process.pid}`;
|
|
35
|
+
fs.writeFileSync(tmp, JSON.stringify(data, null, 2) + "\n", { mode: 0o600 });
|
|
36
|
+
try { fs.chmodSync(tmp, 0o600); } catch {}
|
|
37
|
+
fs.renameSync(tmp, file);
|
|
38
|
+
} catch {}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function collectStrings(value, out = []) {
|
|
42
|
+
if (typeof value === "string") out.push(value);
|
|
43
|
+
else if (Array.isArray(value)) value.forEach((v) => collectStrings(v, out));
|
|
44
|
+
else if (value && typeof value === "object") {
|
|
45
|
+
for (const v of Object.values(value)) collectStrings(v, out);
|
|
46
|
+
}
|
|
47
|
+
return out;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function hookInputText() {
|
|
51
|
+
try {
|
|
52
|
+
if (process.stdin.isTTY) return "";
|
|
53
|
+
const raw = fs.readFileSync(0, "utf8");
|
|
54
|
+
if (!raw) return "";
|
|
55
|
+
try {
|
|
56
|
+
const parsed = JSON.parse(raw);
|
|
57
|
+
return collectStrings(parsed.tool_input || parsed).join("\n");
|
|
58
|
+
} catch {
|
|
59
|
+
return raw;
|
|
60
|
+
}
|
|
61
|
+
} catch {
|
|
62
|
+
return "";
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function approvalClaim(text) {
|
|
67
|
+
const normalized = String(text || "").replace(/\s+/g, " ").trim();
|
|
68
|
+
if (!normalized) return "";
|
|
69
|
+
const patterns = [
|
|
70
|
+
/\bfawzi\b.{0,80}\b(said|says|told|approved|approves|okayed|ok'd|allowed|allows|authorized|authorizes|confirmed)\b.{0,80}\b(ok|okay|fine|yes|ship|deploy|go ahead|do it|allowed|approved)?/i,
|
|
71
|
+
/\bfawzi\s+is\s+(here|with\s+me|beside\s+me)\b.{0,80}\b(ok|okay|fine|yes|approved|approves|allow|allows|ship|deploy|go ahead|do it)\b/i,
|
|
72
|
+
/\b(owner|boss)\b.{0,40}\b(said|says|approved|approves|okayed|ok'd)\b.{0,60}\b(ok|okay|fine|yes|ship|deploy|go ahead|do it)\b/i,
|
|
73
|
+
];
|
|
74
|
+
for (const re of patterns) {
|
|
75
|
+
const m = normalized.match(re);
|
|
76
|
+
if (m) return m[0].slice(0, 220);
|
|
77
|
+
}
|
|
78
|
+
return "";
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function recordLocal(config, sample) {
|
|
82
|
+
const data = readJson(EVENT_FILE, { counts: {}, events: [] });
|
|
83
|
+
if (!data.counts || typeof data.counts !== "object") data.counts = {};
|
|
84
|
+
if (!Array.isArray(data.events)) data.events = [];
|
|
85
|
+
|
|
86
|
+
const key = config.code || config.installed_by || "unknown";
|
|
87
|
+
const prev = data.counts[key] || {};
|
|
88
|
+
const count = (prev.total || 0) + 1;
|
|
89
|
+
const event = {
|
|
90
|
+
type: "proxy_owner_approval_claim",
|
|
91
|
+
actor_code: config.code || "",
|
|
92
|
+
actor_name: config.installed_by || "",
|
|
93
|
+
actor_role: config.role || "",
|
|
94
|
+
count,
|
|
95
|
+
sample,
|
|
96
|
+
project: path.basename(process.cwd()),
|
|
97
|
+
cwd: process.cwd(),
|
|
98
|
+
recorded_at: new Date().toISOString(),
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
data.counts[key] = {
|
|
102
|
+
actor_code: event.actor_code,
|
|
103
|
+
actor_name: event.actor_name,
|
|
104
|
+
actor_role: event.actor_role,
|
|
105
|
+
total: count,
|
|
106
|
+
last_seen_at: event.recorded_at,
|
|
107
|
+
};
|
|
108
|
+
data.events.push(event);
|
|
109
|
+
data.events = data.events.slice(-200);
|
|
110
|
+
writeJson(EVENT_FILE, data);
|
|
111
|
+
return event;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
function enqueueErp(config, event) {
|
|
115
|
+
try {
|
|
116
|
+
const retryPath = path.join(QUALIA_HOME, "bin", "erp-retry.js");
|
|
117
|
+
if (!fs.existsSync(retryPath)) return;
|
|
118
|
+
if (config.erp && config.erp.enabled === false) return;
|
|
119
|
+
const erpUrl = (config.erp && config.erp.url) || "https://portal.qualiasolutions.net";
|
|
120
|
+
const { enqueue } = require(retryPath);
|
|
121
|
+
enqueue({
|
|
122
|
+
client_report_id: `QS-POLICY-${(event.actor_code || "UNKNOWN").replace(/[^A-Z0-9-]/gi, "")}-${event.count}`,
|
|
123
|
+
idempotency_key: crypto.randomUUID ? crypto.randomUUID() : "",
|
|
124
|
+
url: `${erpUrl.replace(/\/$/, "")}/api/v1/policy-events`,
|
|
125
|
+
payload: JSON.stringify(event),
|
|
126
|
+
last_error: "",
|
|
127
|
+
});
|
|
128
|
+
} catch {}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
try {
|
|
132
|
+
const config = readJson(CONFIG, {});
|
|
133
|
+
if ((config.role || "").toUpperCase() === "OWNER") process.exit(0);
|
|
134
|
+
if ((config.role || "").toUpperCase() !== "EMPLOYEE") process.exit(0);
|
|
135
|
+
|
|
136
|
+
const sample = approvalClaim(hookInputText());
|
|
137
|
+
if (!sample) process.exit(0);
|
|
138
|
+
|
|
139
|
+
const event = recordLocal(config, sample);
|
|
140
|
+
enqueueErp(config, event);
|
|
141
|
+
} catch {}
|
|
142
|
+
|
|
143
|
+
process.exit(0);
|
package/hooks/pre-deploy-gate.js
CHANGED
|
@@ -21,6 +21,8 @@ function qualiaHome() {
|
|
|
21
21
|
}
|
|
22
22
|
|
|
23
23
|
const QUALIA_HOME = qualiaHome();
|
|
24
|
+
const CONFIG = path.join(QUALIA_HOME, ".qualia-config.json");
|
|
25
|
+
let HOOK_COMMAND = null;
|
|
24
26
|
|
|
25
27
|
// Self-filter on the proposed bash command — only act when the user is
|
|
26
28
|
// actually trying to deploy. Claude Code's `if: "Bash(vercel --prod*)"` does
|
|
@@ -44,7 +46,8 @@ const QUALIA_HOME = qualiaHome();
|
|
|
44
46
|
}
|
|
45
47
|
} catch {}
|
|
46
48
|
if (command === null) return; // malformed or empty stdin — run full gate
|
|
47
|
-
|
|
49
|
+
HOOK_COMMAND = command;
|
|
50
|
+
if (!/^\s*(?:[A-Za-z_][A-Za-z0-9_]*=\S+\s+)*(npx\s+)?vercel\s+(--prod|deploy\s+--prod)\b/.test(command)) {
|
|
48
51
|
process.exit(0);
|
|
49
52
|
}
|
|
50
53
|
})();
|
|
@@ -107,6 +110,76 @@ function hasScript(name) {
|
|
|
107
110
|
}
|
|
108
111
|
}
|
|
109
112
|
|
|
113
|
+
function readConfig() {
|
|
114
|
+
try {
|
|
115
|
+
return JSON.parse(fs.readFileSync(CONFIG, "utf8"));
|
|
116
|
+
} catch {
|
|
117
|
+
return {};
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
function readTrackingState() {
|
|
122
|
+
try {
|
|
123
|
+
const tracking = JSON.parse(fs.readFileSync(path.join(process.cwd(), ".planning", "tracking.json"), "utf8"));
|
|
124
|
+
return {
|
|
125
|
+
status: tracking.status || "",
|
|
126
|
+
verification: tracking.verification || "",
|
|
127
|
+
next_command: tracking.next_command || "",
|
|
128
|
+
};
|
|
129
|
+
} catch {
|
|
130
|
+
return null;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
function readState() {
|
|
135
|
+
const stateJs = path.join(QUALIA_HOME, "bin", "state.js");
|
|
136
|
+
if (fs.existsSync(stateJs)) {
|
|
137
|
+
try {
|
|
138
|
+
const r = spawnSync(process.execPath, [stateJs, "check"], {
|
|
139
|
+
encoding: "utf8",
|
|
140
|
+
timeout: 3000,
|
|
141
|
+
stdio: ["ignore", "pipe", "ignore"],
|
|
142
|
+
});
|
|
143
|
+
if (r.status === 0 && r.stdout) return JSON.parse(r.stdout);
|
|
144
|
+
} catch {}
|
|
145
|
+
}
|
|
146
|
+
return readTrackingState();
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
function blockDeploy(reason, nextCommand) {
|
|
150
|
+
console.error(`BLOCKED: ${reason}`);
|
|
151
|
+
if (nextCommand) console.error(`Run: ${nextCommand}`);
|
|
152
|
+
_trace("pre-deploy-gate", "block", { reason, next_command: nextCommand || "" });
|
|
153
|
+
process.exit(2);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
function enforceShipPolicy() {
|
|
157
|
+
if (!HOOK_COMMAND) return;
|
|
158
|
+
|
|
159
|
+
const config = readConfig();
|
|
160
|
+
const role = String(config.role || "").toUpperCase();
|
|
161
|
+
const force = process.env.QUALIA_SHIP_FORCE === "1" || /\bQUALIA_SHIP_FORCE=1\b/.test(HOOK_COMMAND);
|
|
162
|
+
const state = readState();
|
|
163
|
+
const status = state && state.status ? String(state.status) : "";
|
|
164
|
+
const verification = state && state.verification ? String(state.verification) : "";
|
|
165
|
+
const nextCommand = (state && state.next_command) || "/qualia";
|
|
166
|
+
|
|
167
|
+
if (force && role !== "OWNER") {
|
|
168
|
+
blockDeploy("QUALIA_SHIP_FORCE is OWNER-only.", nextCommand);
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
// If this is not a Qualia-managed project, keep the legacy behavior: run the
|
|
172
|
+
// quality/security gates but do not invent state.
|
|
173
|
+
if (!state || !status) return;
|
|
174
|
+
|
|
175
|
+
const shippable = status === "polished" || (status === "verified" && verification === "pass");
|
|
176
|
+
if (!shippable && !force) {
|
|
177
|
+
blockDeploy(`Ship refused from state '${status}' (verification: ${verification || "none"}).`, nextCommand);
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
enforceShipPolicy();
|
|
182
|
+
|
|
110
183
|
// Directories that should never be walked (build outputs, deps, caches).
|
|
111
184
|
const EXCLUDED_DIRS = new Set([
|
|
112
185
|
"node_modules",
|
package/hooks/session-start.js
CHANGED
|
@@ -25,6 +25,9 @@ function qualiaHome() {
|
|
|
25
25
|
if (process.env.QUALIA_HOME) return process.env.QUALIA_HOME;
|
|
26
26
|
const parent = path.basename(path.dirname(__dirname));
|
|
27
27
|
if (parent === ".codex" || parent === ".claude") return path.dirname(__dirname);
|
|
28
|
+
if (fs.existsSync(path.join(path.dirname(__dirname), "bin", "qualia-ui.js"))) {
|
|
29
|
+
return path.dirname(__dirname);
|
|
30
|
+
}
|
|
28
31
|
return path.join(HOME, ".claude");
|
|
29
32
|
}
|
|
30
33
|
|
|
@@ -36,6 +39,7 @@ const NOTIF_FILE = path.join(QUALIA_HOME, ".qualia-update-available.json");
|
|
|
36
39
|
const HEALTH_FILE = path.join(QUALIA_HOME, ".qualia-install-health.json");
|
|
37
40
|
const ERP_RETRY = path.join(QUALIA_HOME, "bin", "erp-retry.js");
|
|
38
41
|
const ERP_QUEUE = path.join(QUALIA_HOME, ".erp-retry-queue.json");
|
|
42
|
+
const WORK_PACKET_BIN = path.join(QUALIA_HOME, "bin", "work-packet.js");
|
|
39
43
|
|
|
40
44
|
// Critical files referenced by skills via @-import. If any are missing, skills
|
|
41
45
|
// silently get empty context and produce ungrounded output. We spot-check these
|
|
@@ -97,6 +101,29 @@ function getNextCommand() {
|
|
|
97
101
|
}
|
|
98
102
|
}
|
|
99
103
|
|
|
104
|
+
function readWorkPacket() {
|
|
105
|
+
try {
|
|
106
|
+
if (!fs.existsSync(WORK_PACKET_BIN)) return null;
|
|
107
|
+
const mod = require(WORK_PACKET_BIN);
|
|
108
|
+
if (!mod || typeof mod.readLocalWorkPacket !== "function") return null;
|
|
109
|
+
return mod.readLocalWorkPacket(process.cwd());
|
|
110
|
+
} catch {
|
|
111
|
+
return null;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
function renderWorkPacketContext() {
|
|
116
|
+
const packet = readWorkPacket();
|
|
117
|
+
if (!packet) return;
|
|
118
|
+
const project = packet.project && packet.project.name ? packet.project.name : "ERP mission";
|
|
119
|
+
const deadline = packet.deadline_date || "no deadline";
|
|
120
|
+
const next = packet.next_command || "/qualia";
|
|
121
|
+
const employee = packet.employee && packet.employee.name ? ` · ${packet.employee.name}` : "";
|
|
122
|
+
const text = `${project}: due ${deadline} · next ${next}${employee}`;
|
|
123
|
+
if (fs.existsSync(UI)) runUi("info", text);
|
|
124
|
+
else console.log(`QUALIA: ${text}`);
|
|
125
|
+
}
|
|
126
|
+
|
|
100
127
|
function readConfig() {
|
|
101
128
|
try {
|
|
102
129
|
return JSON.parse(fs.readFileSync(path.join(QUALIA_HOME, ".qualia-config.json"), "utf8"));
|
|
@@ -178,6 +205,7 @@ try {
|
|
|
178
205
|
fallbackText();
|
|
179
206
|
} else if (fs.existsSync(STATE_FILE)) {
|
|
180
207
|
runUi("banner", "router");
|
|
208
|
+
renderWorkPacketContext();
|
|
181
209
|
const next = getNextCommand();
|
|
182
210
|
if (next) {
|
|
183
211
|
console.log("");
|
|
@@ -185,7 +213,7 @@ try {
|
|
|
185
213
|
}
|
|
186
214
|
} else if (fs.existsSync(CONTINUE_HERE)) {
|
|
187
215
|
runUi("banner", "resume");
|
|
188
|
-
runUi("warn", "Previous session found — type /qualia
|
|
216
|
+
runUi("warn", "Previous session found — type /qualia to pick up where you left off");
|
|
189
217
|
console.log("");
|
|
190
218
|
} else {
|
|
191
219
|
// No project — show a welcoming first-run experience
|
package/package.json
CHANGED
|
@@ -4,7 +4,7 @@ globs: ["*.tsx", "*.jsx", "*.css", "*.scss", "*.html", "*.vue", "*.svelte"]
|
|
|
4
4
|
|
|
5
5
|
# Design Rubric
|
|
6
6
|
|
|
7
|
-
Anchored 1-5 scoring across
|
|
7
|
+
Anchored 1-5 scoring across 9 dimensions. Used by the verifier agent to score frontend phases. Used by `/qualia-polish --critique` for read-only audits.
|
|
8
8
|
|
|
9
9
|
## How to score
|
|
10
10
|
|
|
@@ -25,9 +25,9 @@ If a vision model is critiquing screenshots, it must score against this rubric.
|
|
|
25
25
|
|
|
26
26
|
Score only what is scope-relevant. A `/qualia-polish src/components/Button.tsx` review scores Typography, Color, States, Motion, Microcopy. Skip Layout Originality and Container Depth — they're component-internal concerns at most.
|
|
27
27
|
|
|
28
|
-
A whole-app `/qualia-polish` scores all
|
|
28
|
+
A whole-app `/qualia-polish` scores all 9 dimensions across multiple representative routes.
|
|
29
29
|
|
|
30
|
-
## The
|
|
30
|
+
## The 9 dimensions
|
|
31
31
|
|
|
32
32
|
### 1. Typography
|
|
33
33
|
|
|
@@ -125,10 +125,22 @@ Evidence: grep for banned phrases, sample of empty/error states
|
|
|
125
125
|
|
|
126
126
|
Evidence: max DOM nesting depth on cards/panels, grep for `border-left` decorative usage
|
|
127
127
|
|
|
128
|
+
### 9. Visual system & graphics
|
|
129
|
+
|
|
130
|
+
| Score | Criteria |
|
|
131
|
+
|---|---|
|
|
132
|
+
| 1 | Page is only generic cards/text where product, state, data, or brand object should be visible. Or visual is decorative noise unrelated to meaning. |
|
|
133
|
+
| 2 | Simple icon/illustration exists but could fit any project. No product/domain specificity. |
|
|
134
|
+
| 3 | Visual supports the page: screenshot, product image, simple diagram, chart, or meaningful icon system. |
|
|
135
|
+
| 4 | Visual system is custom to the product/domain: annotated diagram, varied chart, bespoke hero composition, real media, or meaningful motion. |
|
|
136
|
+
| 5 | Complex visual is memorable and useful: product-in-context scene, interactive graph/map/timeline, 3D/canvas/WebGL, or data visualization with clear insight and accessible fallback. |
|
|
137
|
+
|
|
138
|
+
Evidence: visual type, file:line references, relationship to PRODUCT.md/CONTEXT.md, reduced-motion or static fallback
|
|
139
|
+
|
|
128
140
|
## Aggregate score
|
|
129
141
|
|
|
130
142
|
```
|
|
131
|
-
total = sum of dimension scores (max
|
|
143
|
+
total = sum of dimension scores (max 45)
|
|
132
144
|
average = total / count_of_scored_dimensions
|
|
133
145
|
phase_pass = ALL scored dimensions ≥ 3
|
|
134
146
|
phase_fail = ANY scored dimension < 3
|
|
@@ -149,7 +161,7 @@ A phase fails if any dimension is below 3. Same gate as functional verification.
|
|
|
149
161
|
| Layout originality | 2 | `app/page.tsx:42-78` is a three-column feature grid in section 2 — first-order slop. Rework. |
|
|
150
162
|
| ... | ... | ... |
|
|
151
163
|
|
|
152
|
-
**Aggregate:**
|
|
164
|
+
**Aggregate:** 32/45 (avg 3.56)
|
|
153
165
|
**Phase verdict:** FAIL — Layout Originality at 2 blocks the phase.
|
|
154
166
|
**Fix priority:** Rework section 2. Replace three-column grid with varied-height layout per `design-brand.md` §Layout.
|
|
155
167
|
```
|
|
@@ -109,10 +109,14 @@ These are Qualia brand standards — mandatory for every frontend component. Not
|
|
|
109
109
|
If `.planning/DESIGN.md` exists in the project, it takes precedence over these defaults.
|
|
110
110
|
Read it before any frontend work. It contains project-specific: palette, typography, spacing, component patterns.
|
|
111
111
|
|
|
112
|
+
For redesigns and full-app polish, also read:
|
|
113
|
+
- `qualia-design/design-reference.md` for motion, accessibility, responsive, and performance depth
|
|
114
|
+
- `qualia-design/graphics.md` for complex graphics, charts, canvas, 3D, visual systems, and media rules
|
|
115
|
+
|
|
112
116
|
## Qualia design commands
|
|
113
117
|
- `/qualia-polish` — design pass, scope-adaptive (component / section / app / redesign / critique / quick / loop)
|
|
114
|
-
- `/qualia-vibe` — fast aesthetic pivot (swap tokens, keep layout) + reverse-engineer from URL + code↔DESIGN.md sync
|
|
118
|
+
- `/qualia-polish --vibe` — fast aesthetic pivot (swap tokens, keep layout) + reverse-engineer from URL + code↔DESIGN.md sync
|
|
115
119
|
- `/qualia-review` — scored production audit
|
|
116
120
|
|
|
117
121
|
### Recommended workflow
|
|
118
|
-
1. Build feature → 2. `/qualia-polish` to polish within the current vibe → 3. `/qualia-vibe` when the vibe itself needs to change → 4. `/qualia-polish --loop` for autonomous visual QA → ship.
|
|
122
|
+
1. Build feature → 2. `/qualia-polish` to polish within the current vibe → 3. `/qualia-polish --vibe` when the vibe itself needs to change → 4. `/qualia-polish --redesign` when the whole surface needs stronger visual concept/graphics → 5. `/qualia-polish --loop` for autonomous visual QA → ship.
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
---
|
|
2
|
+
globs: ["*.tsx", "*.jsx", "*.css", "*.scss", "*.html", "*.svg", "*.canvas", "*.webgl"]
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# Complex Graphics & Visual Systems
|
|
6
|
+
|
|
7
|
+
Loaded by `/qualia-polish --redesign`, `/qualia-polish --loop`, and any polish pass where the page needs stronger visual identity than typography and spacing alone can provide.
|
|
8
|
+
|
|
9
|
+
## When To Add Complex Visuals
|
|
10
|
+
|
|
11
|
+
Use richer graphics when they clarify the product, reveal state, or create a memorable first-viewport signal:
|
|
12
|
+
|
|
13
|
+
- Product object, venue, person, or service that needs immediate recognition
|
|
14
|
+
- Operational dashboard where relationships, flow, status, or hierarchy matter
|
|
15
|
+
- Brand site whose current page is only text blocks and cards
|
|
16
|
+
- Demo or portfolio page where the work itself should be visible
|
|
17
|
+
- Game, spatial tool, voice/AI workflow, analytics surface, map, timeline, graph, or process flow
|
|
18
|
+
|
|
19
|
+
Do not add complex visuals as decoration. A visual must either explain, orient, compare, or make the brand/product unforgettable.
|
|
20
|
+
|
|
21
|
+
## Visual Types
|
|
22
|
+
|
|
23
|
+
Pick the strongest type for the job:
|
|
24
|
+
|
|
25
|
+
| Need | Prefer |
|
|
26
|
+
|---|---|
|
|
27
|
+
| Show real product/place/person | Photo, screenshot, generated bitmap, or image search asset |
|
|
28
|
+
| Show relationships | Node graph, map, flow field, timeline, Sankey, chord, matrix |
|
|
29
|
+
| Show data | Custom chart with annotations, small multiples, sparklines, heatmap |
|
|
30
|
+
| Show process | Step path, layered diagram, animated system map |
|
|
31
|
+
| Create brand memory | Bespoke hero composition, editorial collage, product-in-context scene |
|
|
32
|
+
| Need depth/spatiality | Three.js full-bleed scene, CSS 3D, canvas/WebGL |
|
|
33
|
+
| Need icons | One icon family, ideally lucide if available |
|
|
34
|
+
|
|
35
|
+
## Quality Rules
|
|
36
|
+
|
|
37
|
+
1. Use real or generated bitmap imagery when the user needs to inspect a real thing. Do not substitute abstract SVG blobs.
|
|
38
|
+
2. For 3D, use Three.js and verify the canvas is nonblank at desktop and mobile viewports.
|
|
39
|
+
3. For charts, annotate the insight. A chart without labels or a takeaway is decoration.
|
|
40
|
+
4. For diagrams, keep text short and legible at 375px width.
|
|
41
|
+
5. For generated assets, save them under project assets, not `.planning/`.
|
|
42
|
+
6. For motion, connect animation to meaning: reveal sequence, state change, data transition, or spatial relationship.
|
|
43
|
+
7. Respect reduced motion. Complex visuals must have a static fallback.
|
|
44
|
+
|
|
45
|
+
## Redesign Expectation
|
|
46
|
+
|
|
47
|
+
`/qualia-polish --redesign` must consider at least one complex-visual concept for the first viewport. It may reject the concept only if it explains why typography/layout alone is stronger for that product.
|
package/rules/codex-goal.md
CHANGED
|
@@ -39,7 +39,7 @@ If the answer is `claude`, **skip this entire rule** — Claude Code has no equi
|
|
|
39
39
|
|
|
40
40
|
- The user is on Claude Code (no `/goal` surface).
|
|
41
41
|
- A goal is already active for this thread (Codex rejects `update_goal` when one exists — call `thread/goal/get` first if you're using the tool API directly).
|
|
42
|
-
- The work is open-ended exploration with no clear objective (e.g. `/qualia
|
|
42
|
+
- The work is open-ended exploration with no clear objective (e.g. `/qualia`, `/qualia-discuss`). Goals are for executing a defined scope.
|
|
43
43
|
|
|
44
44
|
## Why
|
|
45
45
|
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
---
|
|
2
|
+
alwaysApply: true
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# Command Output Contract
|
|
6
|
+
|
|
7
|
+
Every Qualia command must be transparent before, during, and after work. Users should never wonder what the command is doing, what it can change, or what the next step is.
|
|
8
|
+
|
|
9
|
+
## Required Shape
|
|
10
|
+
|
|
11
|
+
Every command should expose these seven lines or their equivalent:
|
|
12
|
+
|
|
13
|
+
```text
|
|
14
|
+
Command: /qualia-{name} {mode}
|
|
15
|
+
Scope: {files/routes/project area}
|
|
16
|
+
Intent: {audit|investigate|repair|build|polish|ship|report}
|
|
17
|
+
Mutation: none | planned | active | blocked
|
|
18
|
+
Evidence: {files read, commands run, sources checked}
|
|
19
|
+
Output: {files/reports/commits produced}
|
|
20
|
+
Next: {next command or done}
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## Rules
|
|
24
|
+
|
|
25
|
+
1. Start with a `qualia-ui.js banner` whenever the command has an existing banner mode.
|
|
26
|
+
2. State whether the command is read-only or mutating before editing.
|
|
27
|
+
3. For mutating commands, name the exact files or route family before writing.
|
|
28
|
+
4. For audit or investigation commands, name the evidence commands and report path.
|
|
29
|
+
5. For design commands, name the design substrate loaded from `qualia-design/` and `.planning/DESIGN.md`.
|
|
30
|
+
6. End with a `qualia-ui.js end` next command. If there is no next command, say `done`.
|
|
31
|
+
7. If the command blocks, say why and route to the smallest useful next command.
|
|
32
|
+
|
|
33
|
+
## Anti-Pattern
|
|
34
|
+
|
|
35
|
+
Do not answer with only a prose paragraph like "Done, I fixed it." The command must tell the user what happened and where the evidence lives.
|
package/rules/one-opinion.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# One Opinion (design-decision discipline)
|
|
2
2
|
|
|
3
|
-
Loaded on demand by design-adjacent skills: `/qualia-vibe`, `/qualia-polish`, `/qualia-new` (DESIGN.md creation step), `/qualia-discuss` PROJECT MODE. Not always-on — most skills don't need it.
|
|
3
|
+
Loaded on demand by design-adjacent skills: `/qualia-polish --vibe`, `/qualia-polish`, `/qualia-new` (DESIGN.md creation step), `/qualia-discuss` PROJECT MODE. Not always-on — most skills don't need it.
|
|
4
4
|
|
|
5
5
|
## The rule
|
|
6
6
|
|
|
@@ -34,7 +34,7 @@ Owners and clients have a strong sense of what they DON'T want and a weaker sens
|
|
|
34
34
|
- The user explicitly asked for options ("show me 3 directions", "give me a menu").
|
|
35
35
|
- The decision is technical, not aesthetic (e.g. "use Postgres or MongoDB?" — those have objectively different tradeoffs and should be discussed, not opinionated).
|
|
36
36
|
- A locked decision in `.planning/decisions/*.md` already exists — surface it, don't re-decide.
|
|
37
|
-
- The framework command explicitly supports a `--variants` mode (e.g. `/qualia-vibe --variants 3`), which is the user opting into the menu surface.
|
|
37
|
+
- The framework command explicitly supports a `--variants` mode (e.g. `/qualia-polish --vibe --variants 3`), which is the user opting into the menu surface.
|
|
38
38
|
|
|
39
39
|
## Output shape
|
|
40
40
|
|