qualia-framework 6.2.9 → 6.2.10
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/README.md +14 -11
- 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 +111 -14
- package/bin/contract-runner.js +219 -0
- package/bin/host-adapters.js +66 -0
- package/bin/install.js +99 -152
- package/bin/plan-contract.js +99 -2
- package/bin/planning-hygiene.js +262 -0
- package/bin/runtime-manifest.js +32 -0
- package/bin/state-ledger.js +184 -0
- package/bin/state.js +299 -20
- package/bin/trust-score.js +276 -0
- package/docs/onboarding.html +5 -4
- package/guide.md +3 -2
- package/package.json +1 -1
- package/qualia-design/design-rubric.md +17 -5
- package/qualia-design/frontend.md +5 -1
- package/qualia-design/graphics.md +47 -0
- package/rules/command-output.md +35 -0
- package/skills/qualia/SKILL.md +10 -10
- package/skills/qualia-build/SKILL.md +20 -14
- package/skills/qualia-debug/SKILL.md +16 -8
- package/skills/qualia-discuss/SKILL.md +10 -10
- package/skills/qualia-doctor/SKILL.md +140 -0
- package/skills/qualia-feature/SKILL.md +23 -21
- package/skills/qualia-fix/SKILL.md +216 -0
- package/skills/qualia-flush/SKILL.md +9 -9
- package/skills/qualia-handoff/SKILL.md +9 -9
- package/skills/qualia-help/SKILL.md +3 -3
- package/skills/qualia-hook-gen/SKILL.md +1 -1
- package/skills/qualia-idk/SKILL.md +4 -4
- package/skills/qualia-issues/SKILL.md +2 -2
- package/skills/qualia-learn/SKILL.md +10 -10
- 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-pause/SKILL.md +2 -2
- package/skills/qualia-plan/SKILL.md +23 -13
- package/skills/qualia-polish/REFERENCE.md +14 -14
- package/skills/qualia-polish/SKILL.md +64 -19
- package/skills/qualia-polish/scripts/loop.mjs +3 -3
- package/skills/qualia-polish/scripts/score.mjs +9 -3
- 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-resume/SKILL.md +4 -4
- package/skills/qualia-review/SKILL.md +28 -12
- package/skills/qualia-road/SKILL.md +18 -5
- package/skills/qualia-ship/SKILL.md +22 -22
- package/skills/qualia-skill-new/SKILL.md +13 -13
- package/skills/qualia-test/SKILL.md +5 -5
- package/skills/qualia-triage/SKILL.md +1 -1
- package/skills/qualia-verify/SKILL.md +37 -23
- package/skills/qualia-vibe/SKILL.md +13 -10
- package/skills/qualia-vibe/scripts/extract.mjs +1 -1
- package/skills/zoho-workflow/SKILL.md +1 -1
- package/templates/help.html +12 -10
- package/tests/bin.test.sh +34 -4
- package/tests/install-smoke.test.sh +22 -2
- package/tests/lib.test.sh +290 -0
- package/tests/runner.js +3 -0
- package/tests/skills.test.sh +4 -4
- package/tests/state.test.sh +65 -3
|
@@ -0,0 +1,276 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// Qualia trust score — compact harness health summary.
|
|
3
|
+
|
|
4
|
+
const fs = require("fs");
|
|
5
|
+
const path = require("path");
|
|
6
|
+
const os = require("os");
|
|
7
|
+
const pc = require("./plan-contract.js");
|
|
8
|
+
const ledger = require("./state-ledger.js");
|
|
9
|
+
const { binFiles } = require("./runtime-manifest.js");
|
|
10
|
+
|
|
11
|
+
const HOMES = [
|
|
12
|
+
{ name: "Claude", dir: path.join(os.homedir(), ".claude") },
|
|
13
|
+
{ name: "Codex", dir: path.join(os.homedir(), ".codex") },
|
|
14
|
+
];
|
|
15
|
+
|
|
16
|
+
const REQUIRED_BIN = binFiles();
|
|
17
|
+
|
|
18
|
+
const REQUIRED_HOOKS = [
|
|
19
|
+
"session-start.js", "auto-update.js", "branch-guard.js", "pre-push.js",
|
|
20
|
+
"pre-deploy-gate.js", "migration-guard.js", "git-guardrails.js",
|
|
21
|
+
"stop-session-log.js", "vercel-account-guard.js", "env-empty-guard.js",
|
|
22
|
+
"supabase-destructive-guard.js",
|
|
23
|
+
];
|
|
24
|
+
|
|
25
|
+
const REQUIRED_DESIGN_FILES = [
|
|
26
|
+
"design-laws.md",
|
|
27
|
+
"design-rubric.md",
|
|
28
|
+
"design-brand.md",
|
|
29
|
+
"design-product.md",
|
|
30
|
+
"design-reference.md",
|
|
31
|
+
"frontend.md",
|
|
32
|
+
"graphics.md",
|
|
33
|
+
];
|
|
34
|
+
|
|
35
|
+
const REQUIRED_EMPLOYEE_SKILLS = [
|
|
36
|
+
"qualia-doctor",
|
|
37
|
+
"qualia-road",
|
|
38
|
+
"qualia-resume",
|
|
39
|
+
"qualia-pause",
|
|
40
|
+
"qualia-report",
|
|
41
|
+
];
|
|
42
|
+
|
|
43
|
+
function exists(p) {
|
|
44
|
+
try { return fs.existsSync(p); } catch { return false; }
|
|
45
|
+
}
|
|
46
|
+
function readJson(p) {
|
|
47
|
+
try { return JSON.parse(fs.readFileSync(p, "utf8")); } catch { return null; }
|
|
48
|
+
}
|
|
49
|
+
function readText(p) {
|
|
50
|
+
try { return fs.readFileSync(p, "utf8"); } catch { return ""; }
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function installedHomes() {
|
|
54
|
+
return HOMES.filter((h) => exists(path.join(h.dir, ".qualia-config.json")));
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function inspectInstall(homes) {
|
|
58
|
+
if (homes.length === 0) {
|
|
59
|
+
return { status: "fail", score: 0, issues: ["no Qualia install config found"], targets: [] };
|
|
60
|
+
}
|
|
61
|
+
const issues = [];
|
|
62
|
+
for (const home of homes) {
|
|
63
|
+
for (const f of REQUIRED_BIN) {
|
|
64
|
+
if (!exists(path.join(home.dir, "bin", f))) issues.push(`${home.name}: missing bin/${f}`);
|
|
65
|
+
}
|
|
66
|
+
if (home.name === "Claude") {
|
|
67
|
+
if (!exists(path.join(home.dir, "CLAUDE.md"))) issues.push("Claude: missing CLAUDE.md");
|
|
68
|
+
if (!exists(path.join(home.dir, "settings.json"))) issues.push("Claude: missing settings.json");
|
|
69
|
+
} else {
|
|
70
|
+
if (!exists(path.join(home.dir, "AGENTS.md"))) issues.push("Codex: missing AGENTS.md");
|
|
71
|
+
if (!exists(path.join(home.dir, "hooks.json"))) issues.push("Codex: missing hooks.json");
|
|
72
|
+
if (!exists(path.join(home.dir, "config.toml"))) issues.push("Codex: missing config.toml");
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
return {
|
|
76
|
+
status: issues.length ? "degraded" : "pass",
|
|
77
|
+
score: issues.length ? Math.max(6, 20 - issues.length * 2) : 20,
|
|
78
|
+
issues,
|
|
79
|
+
targets: homes.map((h) => h.name),
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
function inspectHooks(homes) {
|
|
84
|
+
if (homes.length === 0) return { status: "fail", score: 0, issues: ["no install targets"] };
|
|
85
|
+
const issues = [];
|
|
86
|
+
for (const home of homes) {
|
|
87
|
+
for (const h of REQUIRED_HOOKS) {
|
|
88
|
+
if (!exists(path.join(home.dir, "hooks", h))) issues.push(`${home.name}: missing hooks/${h}`);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
return {
|
|
92
|
+
status: issues.length ? "degraded" : "pass",
|
|
93
|
+
score: issues.length ? Math.max(4, 12 - issues.length) : 12,
|
|
94
|
+
issues,
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
function inspectProject(cwd) {
|
|
99
|
+
const planning = path.join(cwd, ".planning");
|
|
100
|
+
if (!exists(planning)) return { status: "not_applicable", score: 12, issues: [], phase: null };
|
|
101
|
+
const tracking = readJson(path.join(planning, "tracking.json"));
|
|
102
|
+
const stateText = readText(path.join(planning, "STATE.md"));
|
|
103
|
+
const issues = [];
|
|
104
|
+
if (!tracking) issues.push("tracking.json missing or invalid");
|
|
105
|
+
if (!stateText) issues.push("STATE.md missing");
|
|
106
|
+
const phaseMatch = stateText.match(/^Phase:\s*(\d+)/m);
|
|
107
|
+
const statusMatch = stateText.match(/^Status:\s*(.+)$/m);
|
|
108
|
+
const phase = phaseMatch ? Number(phaseMatch[1]) : (tracking && Number(tracking.phase)) || 1;
|
|
109
|
+
if (!phaseMatch && stateText) issues.push("STATE.md phase header missing");
|
|
110
|
+
if (!statusMatch && stateText) issues.push("STATE.md status missing");
|
|
111
|
+
return {
|
|
112
|
+
status: issues.length ? "degraded" : "pass",
|
|
113
|
+
score: issues.length ? Math.max(4, 12 - issues.length * 4) : 12,
|
|
114
|
+
issues,
|
|
115
|
+
phase,
|
|
116
|
+
project_status: statusMatch ? statusMatch[1].trim() : tracking?.status || "",
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
function inspectContracts(cwd, phase) {
|
|
121
|
+
const planning = path.join(cwd, ".planning");
|
|
122
|
+
if (!exists(planning) || !phase) return { status: "not_applicable", score: 18, issues: [] };
|
|
123
|
+
const planPath = path.join(planning, `phase-${phase}-plan.md`);
|
|
124
|
+
const contractPath = path.join(planning, `phase-${phase}-contract.json`);
|
|
125
|
+
if (!exists(planPath)) return { status: "not_applicable", score: 18, issues: [] };
|
|
126
|
+
if (!exists(contractPath)) return { status: "degraded", score: 6, issues: [`phase ${phase}: JSON contract missing`] };
|
|
127
|
+
const loaded = pc.readContractFile(contractPath);
|
|
128
|
+
if (!loaded.ok) return { status: "fail", score: 0, issues: [`phase ${phase}: contract unreadable (${loaded.message || loaded.error})`] };
|
|
129
|
+
const errors = pc.validate(loaded.contract);
|
|
130
|
+
if (errors.length) return { status: "fail", score: 0, issues: [`phase ${phase}: contract invalid (${errors.length} issue(s))`] };
|
|
131
|
+
const drift = pc.checkDrift(contractPath, planPath);
|
|
132
|
+
if (drift.ok && drift.drift) return { status: "fail", score: 0, issues: [`phase ${phase}: contract drifted from plan`] };
|
|
133
|
+
return { status: "pass", score: 18, issues: [], contract: path.relative(cwd, contractPath) };
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
function inspectLedger(cwd) {
|
|
137
|
+
const planning = path.join(cwd, ".planning");
|
|
138
|
+
if (!exists(planning)) return { status: "not_applicable", score: 10, issues: [] };
|
|
139
|
+
const file = ledger.ledgerPath(cwd);
|
|
140
|
+
if (!exists(file)) return { status: "degraded", score: 4, issues: ["state ledger missing"] };
|
|
141
|
+
const result = ledger.validate(cwd);
|
|
142
|
+
if (!result.ok) return { status: "fail", score: 0, issues: result.errors };
|
|
143
|
+
if (result.count === 0) return { status: "degraded", score: 4, issues: ["state ledger empty"] };
|
|
144
|
+
return { status: "pass", score: 10, issues: [], events: result.count };
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
function inspectMemory(homes) {
|
|
148
|
+
if (homes.length === 0) return { status: "fail", score: 0, issues: ["no install targets"] };
|
|
149
|
+
const issues = [];
|
|
150
|
+
for (const home of homes) {
|
|
151
|
+
if (!exists(path.join(home.dir, "knowledge", "index.md"))) issues.push(`${home.name}: missing knowledge/index.md`);
|
|
152
|
+
if (!exists(path.join(home.dir, "knowledge", "agents.md"))) issues.push(`${home.name}: missing knowledge/agents.md`);
|
|
153
|
+
if (!exists(path.join(home.dir, "knowledge", "daily-log"))) issues.push(`${home.name}: missing knowledge/daily-log`);
|
|
154
|
+
}
|
|
155
|
+
return {
|
|
156
|
+
status: issues.length ? "degraded" : "pass",
|
|
157
|
+
score: issues.length ? Math.max(2, 5 - issues.length) : 5,
|
|
158
|
+
issues,
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
function inspectDesign(homes) {
|
|
163
|
+
if (homes.length === 0) return { status: "fail", score: 0, issues: ["no install targets"] };
|
|
164
|
+
const issues = [];
|
|
165
|
+
for (const home of homes) {
|
|
166
|
+
for (const f of REQUIRED_DESIGN_FILES) {
|
|
167
|
+
if (!exists(path.join(home.dir, "qualia-design", f))) issues.push(`${home.name}: missing qualia-design/${f}`);
|
|
168
|
+
}
|
|
169
|
+
if (!exists(path.join(home.dir, "skills", "qualia-polish", "SKILL.md"))) {
|
|
170
|
+
issues.push(`${home.name}: missing qualia-polish skill`);
|
|
171
|
+
}
|
|
172
|
+
if (!exists(path.join(home.dir, "skills", "qualia-vibe", "SKILL.md"))) {
|
|
173
|
+
issues.push(`${home.name}: missing qualia-vibe skill`);
|
|
174
|
+
}
|
|
175
|
+
if (!exists(path.join(home.dir, "agents", home.name === "Codex" ? "visual-evaluator.toml" : "visual-evaluator.md"))) {
|
|
176
|
+
issues.push(`${home.name}: missing visual-evaluator agent`);
|
|
177
|
+
}
|
|
178
|
+
if (!exists(path.join(home.dir, "bin", "slop-detect.mjs"))) {
|
|
179
|
+
issues.push(`${home.name}: missing slop-detect.mjs`);
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
return {
|
|
183
|
+
status: issues.length ? "degraded" : "pass",
|
|
184
|
+
score: issues.length ? Math.max(2, 8 - issues.length) : 8,
|
|
185
|
+
issues,
|
|
186
|
+
};
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
function inspectEmployeeExperience(homes) {
|
|
190
|
+
if (homes.length === 0) return { status: "fail", score: 0, issues: ["no install targets"] };
|
|
191
|
+
const issues = [];
|
|
192
|
+
for (const home of homes) {
|
|
193
|
+
for (const skill of REQUIRED_EMPLOYEE_SKILLS) {
|
|
194
|
+
if (!exists(path.join(home.dir, "skills", skill, "SKILL.md"))) issues.push(`${home.name}: missing ${skill} skill`);
|
|
195
|
+
}
|
|
196
|
+
if (!exists(path.join(home.dir, "qualia-guide.md"))) issues.push(`${home.name}: missing qualia-guide.md`);
|
|
197
|
+
if (!exists(path.join(home.dir, "qualia-templates", "help.html"))) issues.push(`${home.name}: missing help.html`);
|
|
198
|
+
}
|
|
199
|
+
return {
|
|
200
|
+
status: issues.length ? "degraded" : "pass",
|
|
201
|
+
score: issues.length ? Math.max(1, 5 - issues.length) : 5,
|
|
202
|
+
issues,
|
|
203
|
+
};
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
function inspectErp(homes) {
|
|
207
|
+
if (homes.length === 0) return { status: "not_applicable", score: 10, issues: [] };
|
|
208
|
+
const issues = [];
|
|
209
|
+
let enabled = false;
|
|
210
|
+
let queueCount = 0;
|
|
211
|
+
for (const home of homes) {
|
|
212
|
+
const cfg = readJson(path.join(home.dir, ".qualia-config.json")) || {};
|
|
213
|
+
if (cfg.erp && cfg.erp.enabled !== false) {
|
|
214
|
+
enabled = true;
|
|
215
|
+
const keyFile = path.join(home.dir, cfg.erp.api_key_file || ".erp-api-key");
|
|
216
|
+
if (!exists(keyFile)) issues.push(`${home.name}: ERP enabled but API key missing`);
|
|
217
|
+
}
|
|
218
|
+
const queue = readJson(path.join(home.dir, ".erp-retry-queue.json"));
|
|
219
|
+
if (Array.isArray(queue)) queueCount += queue.length;
|
|
220
|
+
}
|
|
221
|
+
if (!enabled) return { status: "not_applicable", score: 10, issues: [], queue_count: queueCount };
|
|
222
|
+
if (queueCount > 0) issues.push(`ERP retry queue has ${queueCount} item(s)`);
|
|
223
|
+
return {
|
|
224
|
+
status: issues.length ? "degraded" : "pass",
|
|
225
|
+
score: issues.length ? Math.max(3, 10 - issues.length * 3) : 10,
|
|
226
|
+
issues,
|
|
227
|
+
queue_count: queueCount,
|
|
228
|
+
};
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
function buildTrustScore(cwd = process.cwd()) {
|
|
232
|
+
const homes = installedHomes();
|
|
233
|
+
const install = inspectInstall(homes);
|
|
234
|
+
const hooks = inspectHooks(homes);
|
|
235
|
+
const project = inspectProject(cwd);
|
|
236
|
+
const contracts = inspectContracts(cwd, project.phase);
|
|
237
|
+
const state_ledger = inspectLedger(cwd);
|
|
238
|
+
const memory = inspectMemory(homes);
|
|
239
|
+
const erp = inspectErp(homes);
|
|
240
|
+
const design = inspectDesign(homes);
|
|
241
|
+
const employee_experience = inspectEmployeeExperience(homes);
|
|
242
|
+
const checks = { install, hooks, project, contracts, state_ledger, memory, erp, design, employee_experience };
|
|
243
|
+
const score = Math.max(0, Math.min(100, Object.values(checks).reduce((n, c) => n + (c.score || 0), 0)));
|
|
244
|
+
const failCount = Object.values(checks).filter((c) => c.status === "fail").length;
|
|
245
|
+
const degradedCount = Object.values(checks).filter((c) => c.status === "degraded").length;
|
|
246
|
+
const status = failCount ? "FAIL" : degradedCount ? "DEGRADED" : "PASS";
|
|
247
|
+
return { ok: failCount === 0, status, score, generated_at: new Date().toISOString(), checks };
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
function printHuman(result) {
|
|
251
|
+
console.log(`Trust score: ${result.score}/100 (${result.status})`);
|
|
252
|
+
for (const [name, check] of Object.entries(result.checks)) {
|
|
253
|
+
const label = `${name[0].toUpperCase()}${name.slice(1)}`;
|
|
254
|
+
console.log(`${label}: ${check.status} (${check.score})`);
|
|
255
|
+
for (const issue of check.issues || []) console.log(` - ${issue}`);
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
function main(argv) {
|
|
260
|
+
const result = buildTrustScore(process.cwd());
|
|
261
|
+
if (argv.includes("--json")) console.log(JSON.stringify(result, null, 2));
|
|
262
|
+
else printHuman(result);
|
|
263
|
+
return result.status === "FAIL" ? 1 : 0;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
module.exports = {
|
|
267
|
+
buildTrustScore,
|
|
268
|
+
inspectInstall,
|
|
269
|
+
inspectProject,
|
|
270
|
+
inspectContracts,
|
|
271
|
+
inspectLedger,
|
|
272
|
+
inspectDesign,
|
|
273
|
+
inspectEmployeeExperience,
|
|
274
|
+
};
|
|
275
|
+
|
|
276
|
+
if (require.main === module) process.exit(main(process.argv));
|
package/docs/onboarding.html
CHANGED
|
@@ -496,9 +496,10 @@
|
|
|
496
496
|
<div class="kit-group">
|
|
497
497
|
<h4>Diagnose & fix</h4>
|
|
498
498
|
<dl>
|
|
499
|
-
<dt>/qualia-
|
|
500
|
-
<dt>/qualia-
|
|
501
|
-
<dt>/qualia-
|
|
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-debug</dt><dd>Investigative debugging. Use when the failure is unclear and you need evidence before repair.</dd>
|
|
501
|
+
<dt>/qualia-review</dt><dd>Read-only production audit with severity-scored findings. Run before a big deploy.</dd>
|
|
502
|
+
<dt>/qualia-optimize</dt><dd>Deep improvement map for performance, design, alignment, and architecture. Spawns parallel specialists.</dd>
|
|
502
503
|
<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
504
|
</dl>
|
|
504
505
|
</div>
|
|
@@ -521,7 +522,7 @@
|
|
|
521
522
|
<div class="kit-group">
|
|
522
523
|
<h4>Build something small</h4>
|
|
523
524
|
<dl>
|
|
524
|
-
<dt>/qualia-feature</dt><dd>Auto-scoped: inline for trivia (
|
|
525
|
+
<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
526
|
</dl>
|
|
526
527
|
</div>
|
|
527
528
|
<div class="kit-group">
|
package/guide.md
CHANGED
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
|
|
14
14
|
**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
15
|
|
|
16
|
-
**v6.2.1 carries forward.** Active docs match the v6.2 no-bot-commit model, the explicit `/qualia-report` ERP contract, the current
|
|
16
|
+
**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
17
|
|
|
18
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).
|
|
19
19
|
|
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
|
|
26
26
|
**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
27
|
|
|
28
|
-
**Surface is
|
|
28
|
+
**Surface is 35 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-vibe` for fast layout-preserving aesthetic pivots.
|
|
29
29
|
|
|
30
30
|
## The Road
|
|
31
31
|
|
|
@@ -91,6 +91,7 @@ Append `--auto` to `/qualia-new` and the framework chains every step:
|
|
|
91
91
|
| Issues | `/qualia-issues` | Break a phase plan into vertical-slice GitHub issues |
|
|
92
92
|
| Triage | `/qualia-triage` | Triage open issues through the ready-for-agent state machine |
|
|
93
93
|
| Optimize | `/qualia-optimize --deepen` | Find shallow modules; v5.3+ spawns 3 parallel interface-design variants per candidate |
|
|
94
|
+
| Planning hygiene | `qualia-framework planning-hygiene scan` | Detect loose `.planning/` reports/assets before they turn into folder bloat |
|
|
94
95
|
| Hook gen | `/qualia-hook-gen` | Convert a CLAUDE.md/rules instruction into a deterministic hook (v5.3+) |
|
|
95
96
|
| Road view | `/qualia-road` | View and navigate journey/milestone/phase status |
|
|
96
97
|
| Lost? | `/qualia` | Mechanical next-command router |
|
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
118
|
- `/qualia-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-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.
|
|
@@ -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/skills/qualia/SKILL.md
CHANGED
|
@@ -17,7 +17,7 @@ Read project state. Classify your situation. Tell you the exact next command.
|
|
|
17
17
|
### 1. Get State
|
|
18
18
|
|
|
19
19
|
```bash
|
|
20
|
-
node
|
|
20
|
+
node ${QUALIA_BIN}/state.js check 2>/dev/null
|
|
21
21
|
```
|
|
22
22
|
|
|
23
23
|
Also gather context:
|
|
@@ -50,8 +50,8 @@ Use the state.js JSON output plus gathered context:
|
|
|
50
50
|
| `polished` | status == "polished" | → `/qualia-ship` |
|
|
51
51
|
| `shipped` | status == "shipped" | → `/qualia-handoff` |
|
|
52
52
|
| `handed-off` | status == "handed_off" | → `/qualia-report` then done |
|
|
53
|
-
| `blocked` | STATE.md lists blockers or same error 3+ times | → Analyze,
|
|
54
|
-
| `bug-loop` | Same files edited 3+ times, user frustrated | → Different approach, `/qualia-debug` |
|
|
53
|
+
| `blocked` | STATE.md lists blockers or same error 3+ times | → Analyze; `/qualia-fix` if expected behavior is known, `/qualia-debug` if not |
|
|
54
|
+
| `bug-loop` | Same files edited 3+ times, user frustrated | → Different approach, `/qualia-fix` if actionable, `/qualia-debug` if evidence is missing |
|
|
55
55
|
| `need-tests` | User mentions "tests", "coverage", "test this" | → `/qualia-test` |
|
|
56
56
|
|
|
57
57
|
**Employee escalation:** If role is EMPLOYEE and situation is `gap-limit` or `bug-loop`, suggest: "Want to flag this for Fawzi?"
|
|
@@ -60,16 +60,16 @@ Use the state.js JSON output plus gathered context:
|
|
|
60
60
|
|
|
61
61
|
**Clear next step** (use the UI helper — it reads state.js itself):
|
|
62
62
|
```bash
|
|
63
|
-
node
|
|
63
|
+
node ${QUALIA_BIN}/qualia-ui.js banner router
|
|
64
64
|
# If a project is loaded, show the journey position first (one-glance orientation)
|
|
65
|
-
test -f .planning/JOURNEY.md && node
|
|
66
|
-
node
|
|
65
|
+
test -f .planning/JOURNEY.md && node ${QUALIA_BIN}/qualia-ui.js journey-tree .planning/JOURNEY.md
|
|
66
|
+
node ${QUALIA_BIN}/qualia-ui.js next "{next_command from state.js}"
|
|
67
67
|
```
|
|
68
68
|
|
|
69
69
|
**Ambiguous situation (multiple options):**
|
|
70
70
|
Print the banner first, then use plain markdown for the options:
|
|
71
71
|
```bash
|
|
72
|
-
node
|
|
72
|
+
node ${QUALIA_BIN}/qualia-ui.js banner router
|
|
73
73
|
```
|
|
74
74
|
```
|
|
75
75
|
## Where You Are
|
|
@@ -87,9 +87,9 @@ node ~/.claude/bin/qualia-ui.js banner router
|
|
|
87
87
|
|
|
88
88
|
**Blocker detected** (gap-limit, bug-loop, employee escalation):
|
|
89
89
|
```bash
|
|
90
|
-
node
|
|
91
|
-
node
|
|
92
|
-
node
|
|
90
|
+
node ${QUALIA_BIN}/qualia-ui.js banner router
|
|
91
|
+
node ${QUALIA_BIN}/qualia-ui.js fail "{blocker description}"
|
|
92
|
+
node ${QUALIA_BIN}/qualia-ui.js warn "Escalate to Fawzi or re-plan from scratch"
|
|
93
93
|
```
|
|
94
94
|
|
|
95
95
|
User can respond with a number, "just do it", or natural language.
|
|
@@ -32,9 +32,11 @@ Per `rules/codex-goal.md` — set the thread goal at phase start with scope `pha
|
|
|
32
32
|
|
|
33
33
|
```bash
|
|
34
34
|
cat .planning/phase-{N}-plan.md
|
|
35
|
+
cat .planning/phase-{N}-contract.json
|
|
36
|
+
node ${QUALIA_BIN}/plan-contract.js validate .planning/phase-{N}-contract.json
|
|
35
37
|
```
|
|
36
38
|
|
|
37
|
-
Parse tasks, waves, file refs.
|
|
39
|
+
Parse tasks, waves, file refs. Prefer the JSON contract for task ids, dependencies, file lists, and verification checks; use the Markdown plan as the human-readable context.
|
|
38
40
|
|
|
39
41
|
### 1b. Recovery Reference
|
|
40
42
|
|
|
@@ -45,7 +47,7 @@ git tag -f "pre-build-phase-{N}" HEAD 2>/dev/null
|
|
|
45
47
|
```
|
|
46
48
|
|
|
47
49
|
```bash
|
|
48
|
-
node
|
|
50
|
+
node ${QUALIA_BIN}/qualia-ui.js info "Recovery point: pre-build-phase-{N}"
|
|
49
51
|
```
|
|
50
52
|
|
|
51
53
|
Wave fail → stop, inspect status + output. Preserve work; fix forward or ask before reverting.
|
|
@@ -57,19 +59,19 @@ git diff --stat
|
|
|
57
59
|
### 2. Execute Waves
|
|
58
60
|
|
|
59
61
|
```bash
|
|
60
|
-
node
|
|
62
|
+
node ${QUALIA_BIN}/qualia-ui.js banner build {N} "{phase name}"
|
|
61
63
|
```
|
|
62
64
|
|
|
63
65
|
**For each wave (sequential):**
|
|
64
66
|
|
|
65
67
|
```bash
|
|
66
|
-
node
|
|
68
|
+
node ${QUALIA_BIN}/qualia-ui.js wave {W} {total_waves} {tasks_in_wave}
|
|
67
69
|
```
|
|
68
70
|
|
|
69
71
|
**Per task in wave: spawn ALL as separate `Agent()` calls in SAME turn (concurrent). Do NOT await one before spawning next.**
|
|
70
72
|
|
|
71
73
|
```bash
|
|
72
|
-
node
|
|
74
|
+
node ${QUALIA_BIN}/qualia-ui.js task {task_num} "{task title}"
|
|
73
75
|
```
|
|
74
76
|
|
|
75
77
|
**Pre-inline context** (saves 3-5 Read calls per builder):
|
|
@@ -84,7 +86,7 @@ Spawn builder:
|
|
|
84
86
|
|
|
85
87
|
```
|
|
86
88
|
Agent(prompt="
|
|
87
|
-
Role:
|
|
89
|
+
Role: @${QUALIA_AGENTS}/builder.md
|
|
88
90
|
|
|
89
91
|
<phase_context>
|
|
90
92
|
# PROJECT.md
|
|
@@ -110,6 +112,10 @@ Parallel tasks Wave {W} (do NOT touch their files):
|
|
|
110
112
|
{task block from plan: title, wave, persona, files, depends-on, why, AC, action, validation, context}
|
|
111
113
|
</task>
|
|
112
114
|
|
|
115
|
+
<task_contract>
|
|
116
|
+
{matching task object from .planning/phase-{N}-contract.json}
|
|
117
|
+
</task_contract>
|
|
118
|
+
|
|
113
119
|
Context tags already loaded. Only Read project code you modify.
|
|
114
120
|
Execute. Commit. Return DONE/BLOCKED/PARTIAL.
|
|
115
121
|
", subagent_type="qualia-builder", description="Task {N}: {title}")
|
|
@@ -121,7 +127,7 @@ Execute. Commit. Return DONE/BLOCKED/PARTIAL.
|
|
|
121
127
|
- Verify commit: `git log --oneline -1`
|
|
122
128
|
- Show:
|
|
123
129
|
```bash
|
|
124
|
-
node
|
|
130
|
+
node ${QUALIA_BIN}/qualia-ui.js done {task_num} "{title}" {commit_hash}
|
|
125
131
|
```
|
|
126
132
|
|
|
127
133
|
**After each wave:** move to next, show summary.
|
|
@@ -131,10 +137,10 @@ node ~/.claude/bin/qualia-ui.js done {task_num} "{title}" {commit_hash}
|
|
|
131
137
|
All waves done:
|
|
132
138
|
|
|
133
139
|
```bash
|
|
134
|
-
node
|
|
135
|
-
node
|
|
136
|
-
node
|
|
137
|
-
node
|
|
140
|
+
node ${QUALIA_BIN}/qualia-ui.js divider
|
|
141
|
+
node ${QUALIA_BIN}/qualia-ui.js ok "Tasks: {done}/{total}"
|
|
142
|
+
node ${QUALIA_BIN}/qualia-ui.js ok "Commits: {count}"
|
|
143
|
+
node ${QUALIA_BIN}/qualia-ui.js ok "Waves: {count}"
|
|
138
144
|
```
|
|
139
145
|
|
|
140
146
|
### 4. Handle Failures
|
|
@@ -147,7 +153,7 @@ Builder returns deviation/blocker:
|
|
|
147
153
|
### 5. Update State
|
|
148
154
|
|
|
149
155
|
```bash
|
|
150
|
-
node
|
|
156
|
+
node ${QUALIA_BIN}/state.js transition --to built --phase {N} --tasks-done {done} --tasks-total {total} --wave {wave}
|
|
151
157
|
```
|
|
152
158
|
Error → show, stop.
|
|
153
159
|
Do NOT edit STATE.md or tracking.json manually; state.js handles both.
|
|
@@ -157,7 +163,7 @@ Do NOT edit STATE.md or tracking.json manually; state.js handles both.
|
|
|
157
163
|
**`--auto`:** invoke `/qualia-verify {N} --auto` inline. No pause.
|
|
158
164
|
|
|
159
165
|
```bash
|
|
160
|
-
node
|
|
166
|
+
node ${QUALIA_BIN}/qualia-ui.js info "Auto mode — chaining into /qualia-verify {N}"
|
|
161
167
|
```
|
|
162
168
|
|
|
163
169
|
Then invoke `qualia-verify` inline with `--auto`.
|
|
@@ -165,5 +171,5 @@ Then invoke `qualia-verify` inline with `--auto`.
|
|
|
165
171
|
**Guided mode:** stop, show next step:
|
|
166
172
|
|
|
167
173
|
```bash
|
|
168
|
-
node
|
|
174
|
+
node ${QUALIA_BIN}/qualia-ui.js end "PHASE {N} BUILT" "/qualia-verify {N}"
|
|
169
175
|
```
|