qualia-framework 5.9.1 → 6.2.7
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 +2 -1
- package/CLAUDE.md +2 -1
- package/README.md +45 -29
- package/agents/builder.md +1 -5
- package/agents/plan-checker.md +1 -1
- package/agents/planner.md +2 -6
- package/agents/qa-browser.md +3 -3
- package/agents/roadmapper.md +2 -2
- package/agents/verifier.md +7 -9
- package/agents/visual-evaluator.md +1 -3
- package/bin/cli.js +370 -205
- package/bin/erp-retry.js +11 -3
- package/bin/install.js +383 -55
- package/bin/knowledge-flush.js +25 -13
- package/bin/knowledge.js +11 -1
- package/bin/project-snapshot.js +293 -0
- package/bin/qualia-ui.js +13 -2
- package/bin/report-payload.js +137 -0
- package/bin/slop-detect.mjs +81 -9
- package/bin/state.js +8 -1
- package/bin/statusline.js +14 -2
- package/docs/archive/CHANGELOG-pre-v4.md +855 -0
- package/docs/changelog-v6.html +864 -0
- package/docs/ecosystem-operating-model.md +121 -0
- package/docs/erp-contract.md +74 -21
- package/docs/onboarding.html +2 -2
- package/docs/release.md +44 -0
- package/docs/reviews/v6.2.1-revival-audit.md +53 -0
- package/docs/reviews/v6.2.2-memory-erp-audit.md +41 -0
- package/docs/reviews/v6.2.3-erp-id-guard.md +15 -0
- package/guide.md +28 -3
- package/hooks/auto-update.js +20 -10
- package/hooks/branch-guard.js +10 -2
- package/hooks/env-empty-guard.js +15 -5
- package/hooks/git-guardrails.js +10 -1
- package/hooks/migration-guard.js +4 -1
- package/hooks/pre-deploy-gate.js +11 -1
- package/hooks/pre-push.js +43 -106
- package/hooks/session-start.js +22 -14
- package/hooks/stop-session-log.js +11 -3
- package/hooks/supabase-destructive-guard.js +11 -1
- package/hooks/vercel-account-guard.js +12 -3
- package/package.json +4 -3
- package/qualia-design/design-reference.md +2 -1
- package/qualia-design/frontend.md +4 -4
- package/rules/one-opinion.md +59 -0
- package/rules/trust-boundary.md +35 -0
- package/skills/qualia-feature/SKILL.md +5 -5
- package/skills/qualia-flush/SKILL.md +5 -7
- package/skills/qualia-hook-gen/SKILL.md +1 -1
- package/skills/qualia-learn/SKILL.md +1 -0
- package/skills/qualia-map/SKILL.md +2 -1
- package/skills/qualia-milestone/SKILL.md +2 -2
- package/skills/qualia-new/SKILL.md +6 -6
- package/skills/qualia-optimize/SKILL.md +1 -1
- package/skills/qualia-plan/SKILL.md +1 -1
- package/skills/qualia-polish/REFERENCE.md +8 -6
- package/skills/qualia-polish/SKILL.md +11 -9
- package/skills/qualia-polish/scripts/loop.mjs +18 -6
- package/skills/qualia-postmortem/SKILL.md +1 -1
- package/skills/qualia-report/SKILL.md +6 -42
- package/skills/qualia-road/SKILL.md +17 -5
- package/skills/qualia-verify/SKILL.md +3 -3
- package/skills/qualia-vibe/SKILL.md +226 -0
- package/skills/qualia-vibe/scripts/extract.mjs +141 -0
- package/skills/qualia-vibe/scripts/tokens.mjs +342 -0
- package/templates/help.html +10 -3
- package/templates/knowledge/agents.md +3 -3
- package/templates/knowledge/index.md +1 -1
- package/templates/tracking.json +3 -0
- package/templates/work-packet.md +46 -0
- package/tests/bin.test.sh +423 -25
- package/tests/hooks.test.sh +1 -8
- package/tests/install-smoke.test.sh +137 -0
- package/tests/published-install-smoke.test.sh +126 -0
- package/tests/refs.test.sh +43 -1
- package/tests/run-all.sh +49 -0
- package/tests/runner.js +19 -33
- package/tests/slop-detect.test.sh +11 -5
- package/tests/state.test.sh +4 -1
- package/hooks/pre-compact.js +0 -125
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
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'.
|
|
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
4
|
allowed-tools:
|
|
5
5
|
- Bash
|
|
6
6
|
- Read
|
|
@@ -8,6 +8,7 @@ allowed-tools:
|
|
|
8
8
|
- Grep
|
|
9
9
|
- Glob
|
|
10
10
|
- Agent
|
|
11
|
+
- AskUserQuestion
|
|
11
12
|
---
|
|
12
13
|
|
|
13
14
|
# /qualia-map — Codebase Mapping (Brownfield)
|
|
@@ -162,7 +163,7 @@ Read `.planning/codebase/onboarding.md`. Per detected dimension:
|
|
|
162
163
|
- Domain docs at non-default path → `.planning/agents/domain.md`
|
|
163
164
|
- CLAUDE.md/AGENTS.md found → APPEND `## Qualia substrate` (never overwrite)
|
|
164
165
|
|
|
165
|
-
"none" →
|
|
166
|
+
"none" → report that no preference was provided; defaults apply.
|
|
166
167
|
|
|
167
168
|
### 6. Commit
|
|
168
169
|
|
|
@@ -38,7 +38,7 @@ node ~/.claude/bin/state.js check
|
|
|
38
38
|
|
|
39
39
|
If either fires (without `--force`), stop and show the error. The user must verify remaining phases first (or add `--force` for explicit bypass on a preview/demo milestone).
|
|
40
40
|
|
|
41
|
-
### 1b. Demo-Extension Branch
|
|
41
|
+
### 1b. Demo-Extension Branch
|
|
42
42
|
|
|
43
43
|
Detect if this is a demo project closing its only milestone:
|
|
44
44
|
|
|
@@ -276,6 +276,6 @@ node ~/.claude/bin/qualia-ui.js end "M{N} CLOSED · M{N+1} OPEN" "/qualia-plan 1
|
|
|
276
276
|
2. **JOURNEY.md is the source of truth for next milestone.** Don't ask the user to name it unless JOURNEY.md is missing (legacy project).
|
|
277
277
|
3. **Archive, don't delete.** Old phase work stays accessible via `.planning/archive/`.
|
|
278
278
|
4. **New milestone = fresh phase numbering.** First phase of the new milestone is Phase 1, not Phase {N+1}.
|
|
279
|
-
5. **
|
|
279
|
+
5. **Report aware.** `tracking.json.milestones[]` gets a summary entry on close so local status and `/qualia-report` have milestone context.
|
|
280
280
|
6. **Handoff is the final milestone (full projects).** If the current milestone IS Handoff, there is no "next" — route to `/qualia-report` and the project is done.
|
|
281
281
|
7. **Demo closes via the demo-extension branch (Step 1b).** A demo's single milestone closing triggers the "client signed?" question. The framework never silently auto-extends a demo without asking — the conversion is a real business decision.
|
|
@@ -153,7 +153,7 @@ git add .planning/PROJECT.md
|
|
|
153
153
|
git commit -m "docs: initialize project"
|
|
154
154
|
```
|
|
155
155
|
|
|
156
|
-
### Step 8a. Seed CONTEXT.md and decisions/ (
|
|
156
|
+
### Step 8a. Seed CONTEXT.md and decisions/ (REQUIRED)
|
|
157
157
|
|
|
158
158
|
The domain glossary is the single highest-leverage piece of substrate — every road agent loads it BEFORE PROJECT.md/DESIGN.md. Misalignment is the #1 failure mode in AI coding; CONTEXT.md kills it.
|
|
159
159
|
|
|
@@ -166,7 +166,7 @@ mkdir -p .planning/decisions
|
|
|
166
166
|
cp ~/.claude/qualia-templates/decisions/ADR-template.md .planning/decisions/_template.md
|
|
167
167
|
```
|
|
168
168
|
|
|
169
|
-
Then **seed the glossary from the questioning answers**. For each domain term that came up during Step
|
|
169
|
+
Then **seed the glossary from the questioning answers**. For each domain term that came up during the Step 4 `/qualia-discuss` interview — entities, actions, statuses, key nouns the user repeatedly said — add an entry to `.planning/CONTEXT.md` under `## Language` with:
|
|
170
170
|
- the term
|
|
171
171
|
- a one-sentence definition
|
|
172
172
|
- an `Avoid:` line listing rejected synonyms (terms the team should NOT use for this concept)
|
|
@@ -182,7 +182,7 @@ git commit -m "docs: seed CONTEXT.md domain glossary + decisions/ folder"
|
|
|
182
182
|
|
|
183
183
|
The glossary stays terse — one sentence per entry. It's loaded into every agent spawn; bloat costs tokens. `/qualia-discuss` will grow it inline as decisions crystallize during phase planning.
|
|
184
184
|
|
|
185
|
-
### Step 8b. Write PRODUCT.md (
|
|
185
|
+
### Step 8b. Write PRODUCT.md (REQUIRED)
|
|
186
186
|
|
|
187
187
|
`PRODUCT.md` is the "who and why" every road agent reads before designing or building. It is **required** — the planner, builder, and verifier all load it as substrate.
|
|
188
188
|
|
|
@@ -216,9 +216,9 @@ git commit -m "docs: PRODUCT.md — register, users, voice, anti-references"
|
|
|
216
216
|
}
|
|
217
217
|
```
|
|
218
218
|
|
|
219
|
-
**Note:** `workflow.research` is
|
|
219
|
+
**Note:** `workflow.research` is always `true`. It exists for telemetry but is no longer read as a gate.
|
|
220
220
|
|
|
221
|
-
### Step 10. Create DESIGN.md (frontend projects —
|
|
221
|
+
### Step 10. Create DESIGN.md (frontend projects — OKLCH-first)
|
|
222
222
|
|
|
223
223
|
If frontend work is involved, generate `.planning/DESIGN.md` from `templates/DESIGN.md`. The generation MUST commit to four things upfront (these go in §1 of DESIGN.md):
|
|
224
224
|
|
|
@@ -419,7 +419,7 @@ Do NOT use `--quick` for: client projects, anything with compliance stakes, anyt
|
|
|
419
419
|
1. **Project type is the first question, period.** Step 1 (Demo / Full / Quick) is the literal first interaction with the user — even before "what are you building". Every downstream step branches on the answer. Don't skip it, don't infer it, don't ask anything before it.
|
|
420
420
|
2. **AskUserQuestion for every discrete-choice question.** Project type, brownfield gate, design vibe, client type, approval gate, auto-chain — all use the interactive UI. The ONLY free-text question in the kickoff flow is the Step 3 one-line pitch. No plain-text prompts for anything that has a closed set of answers.
|
|
421
421
|
3. **No ad-hoc clarification questioning.** After Step 3 (one-line pitch), the next tool call is `/qualia-discuss`. No "let me ask a few quick things first", no "that's too broad, can you clarify". Depth is the discuss skill's job — not yours.
|
|
422
|
-
4. **Discovery interview is mandatory
|
|
422
|
+
4. **Discovery interview is mandatory.** Step 4 always invokes `/qualia-discuss` in PROJECT MODE. No free-form questioning loop, no "I'll just sketch PROJECT.md from the user's first message." The interview is 8 questions for demo, 14 for full project.
|
|
423
423
|
5. **Research runs automatically.** No permission ask. Only `--quick` skips it. Demo path uses `<scope>quick</scope>` (3-call budget per researcher); full project uses standard 8-call budget.
|
|
424
424
|
6. **Demo design philosophy is non-negotiable.** Real backend always (Supabase, real auth), DESIGN.md mandatory, slop-detect hard-block, 1 milestone, focus on real agent/platform functionality + design quality. No mock data, no lorem ipsum, no broken flows. Speed comes from skipping multi-milestone planning, never from skipping design quality, mocking the backend, or cutting corners on the core flow. A demo that uses mock data is not a Qualia demo.
|
|
425
425
|
7. **Demos are 1 milestone, full projects are 2-5.** Demo journeys have no "Handoff" — the demo IS the artifact. Full projects always end in Handoff (fixed 4 phases). The journey-tree adapts to both shapes.
|
|
@@ -41,7 +41,7 @@ Modes: `full`, `perf`, `ui`, `backend`, `alignment`, `deepen`, `fix`.
|
|
|
41
41
|
|
|
42
42
|
### Step 2: Load Planning Context (MANDATORY)
|
|
43
43
|
|
|
44
|
-
Read all (
|
|
44
|
+
Read all (use the shown NO_* marker when missing):
|
|
45
45
|
|
|
46
46
|
```bash
|
|
47
47
|
cat .planning/PROJECT.md 2>/dev/null || echo "NO_PROJECT"
|
|
@@ -212,7 +212,7 @@ With `--gaps`, planner enters gap-closure mode:
|
|
|
212
212
|
## Rules
|
|
213
213
|
|
|
214
214
|
1. **Plan-checker mandatory by default.** Skip only with `--skip-check`.
|
|
215
|
-
2. **Max
|
|
215
|
+
2. **Max 2 revision cycles.** 2 fails → escalate; scope probably wrong.
|
|
216
216
|
3. **Honor locked decisions.** phase-{N}-context.md locked decisions non-negotiable.
|
|
217
217
|
4. **One plan file per phase.** No phase-1-plan-v2.md. Edit in place.
|
|
218
218
|
5. **Revision is surgical.** Fix only what checker flagged; no scope creep.
|
|
@@ -256,10 +256,12 @@ Per the spec's hard constraint (§5g `prefers-reduced-motion` and §5c mobile-on
|
|
|
256
256
|
|
|
257
257
|
This is intentional. Most visual regressions Fawzi has documented in `/insights` (hero videos cropped wrong on mobile, touch targets < 44px on mobile, navigation collapse misbehaving) only show up below 768. Scoring on desktop alone is how we got "looks great in dev" → "looks broken on the user's phone."
|
|
258
258
|
|
|
259
|
-
## What the loop does NOT do
|
|
259
|
+
## What the loop does NOT do
|
|
260
260
|
|
|
261
|
-
- Cross-browser rendering checks (Firefox / WebKit) — Chromium-only, per `qualia-polish` Stage 4 precedent
|
|
262
|
-
- Accessibility audits beyond what the rubric scores — use `/qualia-polish` Stage 3 (Lighthouse + axe) for that
|
|
263
|
-
- Performance regressions — use `/qualia-polish --loop` only after Lighthouse score passes
|
|
264
|
-
- Reference-image-only mode (compare to a target screenshot without a brief) —
|
|
265
|
-
-
|
|
261
|
+
- Cross-browser rendering checks (Firefox / WebKit) — Chromium-only, per `qualia-polish` Stage 4 precedent.
|
|
262
|
+
- Accessibility audits beyond what the rubric scores — use `/qualia-polish` Stage 3 (Lighthouse + axe) for that.
|
|
263
|
+
- Performance regressions — use `/qualia-polish --loop` only after Lighthouse score passes.
|
|
264
|
+
- Reference-image-only mode (compare to a target screenshot without a brief) — the brief is required; reference is supplemental.
|
|
265
|
+
- Aesthetic pivots — if the issue is "the whole vibe is wrong", `/qualia-vibe` swaps the aesthetic in minutes instead of grinding the loop against a vibe that doesn't fit.
|
|
266
|
+
|
|
267
|
+
Implemented as of v5.2: `--routes a,b,c` for multi-route sweeps, `--reduced-motion` for `prefers-reduced-motion: reduce` capture.
|
|
@@ -36,7 +36,7 @@ Other flags: `--register=brand|product` overrides register inference. Loop-speci
|
|
|
36
36
|
|
|
37
37
|
When `--loop` is the first flag, the polish run is fully autonomous: screenshot a live URL at three viewports, score 8 design dimensions of `qualia-design/design-rubric.md` against the brief using vision, fix top issues in the codebase, re-screenshot, repeat until every dimension scores ≥ 3 or the kill-switch fires (regression, budget cap, max iterations).
|
|
38
38
|
|
|
39
|
-
|
|
39
|
+
Scripts ship at `skills/qualia-polish/scripts/{loop,playwright-capture,score}.mjs`; the vision evaluator is `agents/visual-evaluator.md`; the full loop spec lives in this skill's `REFERENCE.md`.
|
|
40
40
|
|
|
41
41
|
When `--loop` is detected on entry, route to the loop process documented in `REFERENCE.md` and stop executing the standard stages below. The two paths share Stage 0 substrate gates and the rubric, but diverge from Stage 1 onward.
|
|
42
42
|
|
|
@@ -72,15 +72,17 @@ Read PRODUCT.md and DESIGN.md. Identify the **register** — Brand (marketing/la
|
|
|
72
72
|
2. `register:` field in PRODUCT.md
|
|
73
73
|
3. `--register` flag override
|
|
74
74
|
|
|
75
|
-
For App / Redesign scope, write the brief BEFORE any code (use `ultrathink`):
|
|
75
|
+
For App / Redesign scope, write the brief BEFORE any code (use `ultrathink`). Per `rules/one-opinion.md` — **propose one direction, do NOT list a menu of aesthetic options to the user.** Infer the one direction from `PRODUCT.md` register + anti-references + scene sentence, then commit to it in writing:
|
|
76
76
|
|
|
77
77
|
```
|
|
78
|
-
Aesthetic direction: {
|
|
79
|
-
Color strategy: {Restrained
|
|
78
|
+
Aesthetic direction: {ONE concrete direction — e.g. "editorial broadsheet, ivory ground, deep navy ink, italic accents"}
|
|
79
|
+
Color strategy: {ONE choice — Restrained / Committed / Full palette / Drenched — with one-line justification}
|
|
80
80
|
Scene sentence: {who uses this, where, ambient light, mood — concrete}
|
|
81
81
|
Differentiation: {what someone remembers 24 hours later}
|
|
82
82
|
```
|
|
83
83
|
|
|
84
|
+
If the user pushes back on the proposed direction, that is a `/qualia-vibe` trigger — switch surfaces, do not start enumerating alternatives in the brief.
|
|
85
|
+
|
|
84
86
|
For Component / Section / Quick scope, the brief is implicit (loaded from DESIGN.md). Skip the ultrathink step but cite the relevant DESIGN.md tokens you'll touch.
|
|
85
87
|
|
|
86
88
|
For Critique scope, no commit needed — you're scoring, not editing.
|
|
@@ -95,7 +97,7 @@ node bin/slop-detect.mjs {target_paths}
|
|
|
95
97
|
npx tsc --noEmit 2>&1 | head -20
|
|
96
98
|
|
|
97
99
|
# Token enforcement (if Stylelint configured)
|
|
98
|
-
npx stylelint "src/**/*.css" 2>&1 | head -20 # optional,
|
|
100
|
+
npx stylelint "src/**/*.css" 2>&1 | head -20 # optional, report if not configured
|
|
99
101
|
```
|
|
100
102
|
|
|
101
103
|
ANY critical-severity slop hit = mandatory fix before proceeding. Don't stage anything until critical findings are zero.
|
|
@@ -148,19 +150,19 @@ npx lhci autorun \
|
|
|
148
150
|
npx @axe-core/cli http://localhost:3000{route} --exit 2>&1 | tail -30
|
|
149
151
|
```
|
|
150
152
|
|
|
151
|
-
If Lighthouse/axe not installed,
|
|
153
|
+
If Lighthouse/axe are not installed, continue but note the missing tooling in the report. Don't fail the polish over optional local tooling, and don't hide the skipped gate.
|
|
152
154
|
|
|
153
155
|
If a11y < 90 OR axe critical/serious violations: **fix programmatically** (these are deterministic — no vision needed). Re-run to confirm.
|
|
154
156
|
|
|
155
157
|
### Stage 4 — Vision loop (Redesign scope only — max 2 iterations)
|
|
156
158
|
|
|
157
|
-
Use
|
|
159
|
+
Use `skills/qualia-polish/scripts/playwright-capture.mjs` (Playwright backend, with Chrome-binary fallback). Capture screenshots at 3 viewports: 375 / 768 / 1440 — these match what `agents/visual-evaluator.md` expects, and what the `--loop` mode captures. Single browser (Chromium) is fine in 2026 — cross-browser CSS rendering differences are vanishingly rare.
|
|
158
160
|
|
|
159
161
|
```
|
|
160
162
|
viewports: [
|
|
161
163
|
{ width: 375, height: 812, name: 'mobile' },
|
|
162
164
|
{ width: 768, height: 1024, name: 'tablet' },
|
|
163
|
-
{ width:
|
|
165
|
+
{ width: 1440, height: 900, name: 'desktop' }
|
|
164
166
|
]
|
|
165
167
|
```
|
|
166
168
|
|
|
@@ -261,7 +263,7 @@ node ~/.claude/bin/qualia-ui.js end "POLISHED" "{next command — depends on con
|
|
|
261
263
|
| Symptom | Likely cause | Action |
|
|
262
264
|
|---|---|---|
|
|
263
265
|
| `bin/slop-detect.mjs not found` | Framework not installed in project | Run `npx qualia install` or pull script from framework repo |
|
|
264
|
-
| `PRODUCT.md missing` |
|
|
266
|
+
| `PRODUCT.md missing` | Project predates the PRODUCT.md substrate | Run setup (ask 5 questions, generate). For Component scope, can proceed with nudge. |
|
|
265
267
|
| `Lighthouse not installed` | Optional tool | Skip Stage 3 numeric gates, note in report. Don't fail. |
|
|
266
268
|
| `webapp-testing skill not present` | Optional Anthropic skill | Skip Stage 4 vision loop on Redesign scope. Note in report. Recommend installing. |
|
|
267
269
|
| Vision loop oscillates between iterations | Rubric not anchored properly | Verify rubric prompt instructs "default to 3, only 1-2 = fix". Hard cap at 2 iterations. |
|
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
*/
|
|
30
30
|
|
|
31
31
|
import { readFileSync, writeFileSync, existsSync, mkdirSync } from "node:fs";
|
|
32
|
-
import { dirname } from "node:path";
|
|
32
|
+
import path, { dirname } from "node:path";
|
|
33
33
|
import { argv, exit } from "node:process";
|
|
34
34
|
import { spawnSync } from "node:child_process";
|
|
35
35
|
|
|
@@ -202,10 +202,17 @@ function cmdCommitFix() {
|
|
|
202
202
|
if (!statePath || !file) { console.error("--state and --file required"); exit(2); }
|
|
203
203
|
const state = loadState(statePath);
|
|
204
204
|
|
|
205
|
-
// slop-detect gate — block on critical findings
|
|
205
|
+
// slop-detect gate — block on critical findings. Resolve the script path with
|
|
206
|
+
// a search order so installs that put slop-detect in non-default locations
|
|
207
|
+
// still gate. Silent skip is reserved for genuinely missing installs.
|
|
206
208
|
const slopBin = process.env.SLOP_DETECT_BIN || "node";
|
|
207
|
-
const
|
|
208
|
-
|
|
209
|
+
const slopCandidates = [
|
|
210
|
+
process.env.SLOP_DETECT_SCRIPT,
|
|
211
|
+
`${process.env.HOME}/.claude/bin/slop-detect.mjs`,
|
|
212
|
+
path.join(path.dirname(new URL(import.meta.url).pathname), "..", "..", "..", "bin", "slop-detect.mjs"),
|
|
213
|
+
].filter(Boolean);
|
|
214
|
+
const slopScript = slopCandidates.find((p) => existsSync(p));
|
|
215
|
+
if (slopScript) {
|
|
209
216
|
const r = spawnSync(slopBin, [slopScript, file], { encoding: "utf8" });
|
|
210
217
|
if (r.status === 1) {
|
|
211
218
|
console.log(JSON.stringify({ ok: false, gate: "slop-detect", file, output: r.stdout }, null, 2));
|
|
@@ -213,12 +220,17 @@ function cmdCommitFix() {
|
|
|
213
220
|
}
|
|
214
221
|
}
|
|
215
222
|
|
|
216
|
-
// Stage + commit
|
|
223
|
+
// Stage + commit. Set a bot identity inline so the commit works on fresh
|
|
224
|
+
// clones where git user.name / user.email aren't configured yet.
|
|
217
225
|
const safeSlug = String(slug).toLowerCase().replace(/[^a-z0-9-]+/g, "-").slice(0, 48);
|
|
218
226
|
const msg = `qpl-${state.iteration}: ${safeSlug}`;
|
|
219
227
|
const add = spawnSync("git", ["add", file], { encoding: "utf8" });
|
|
220
228
|
if (add.status !== 0) { console.error(add.stderr); exit(2); }
|
|
221
|
-
const commit = spawnSync("git", [
|
|
229
|
+
const commit = spawnSync("git", [
|
|
230
|
+
"-c", "user.name=Qualia Polish Loop",
|
|
231
|
+
"-c", "user.email=polish-loop@qualia.solutions",
|
|
232
|
+
"commit", "-m", msg,
|
|
233
|
+
], { encoding: "utf8" });
|
|
222
234
|
if (commit.status !== 0) {
|
|
223
235
|
// empty diff → nothing to commit; not fatal
|
|
224
236
|
if (/nothing to commit/i.test(commit.stdout + commit.stderr)) {
|
|
@@ -95,7 +95,7 @@ matches the failure. Use this lookup:
|
|
|
95
95
|
| Wave 2 task ran before wave 1 committed | `agents/planner.md` (dependency graph) |
|
|
96
96
|
| Build passed locally, broke in CI | `rules/deployment.md` or a missing pre-deploy-gate scan |
|
|
97
97
|
| RLS missing on new table | `rules/security.md` + `agents/builder.md` (security persona handling) |
|
|
98
|
-
| Design regression — fonts off, contrast fail | `qualia-design/frontend.md` + `skills/qualia-
|
|
98
|
+
| Design regression — fonts off, contrast fail | `qualia-design/frontend.md` + `qualia-design/design-laws.md` + `skills/qualia-polish/SKILL.md` |
|
|
99
99
|
| Migration unsafe (DROP without IF EXISTS, etc.) | `hooks/migration-guard.js` |
|
|
100
100
|
| Verifier missed it | `agents/verifier.md` — most embarrassing case, address with extra care |
|
|
101
101
|
|
|
@@ -126,7 +126,7 @@ fi
|
|
|
126
126
|
### Step 6 — Upload to ERP
|
|
127
127
|
|
|
128
128
|
The full payload-builder + 3-attempt-retry logic lives unchanged from v4 — see the **ERP Upload** section below for the canonical implementation. Behavior summary:
|
|
129
|
-
- ERP disabled in config → skip
|
|
129
|
+
- ERP disabled in config → skip upload with an info line, note local commit
|
|
130
130
|
- API key missing → warn with self-service fix instructions, skip upload
|
|
131
131
|
- 401/422 → permanent failure, no retry, tell employee to ask Fawzi
|
|
132
132
|
- Transient (timeout/5xx) → 3 attempts with 1s/3s/9s backoff
|
|
@@ -149,7 +149,7 @@ node ~/.claude/bin/qualia-ui.js info "Shift report submitted. You can clock out
|
|
|
149
149
|
| Symptom | Likely cause | Self-service fix |
|
|
150
150
|
|---|---|---|
|
|
151
151
|
| "Could not allocate report ID" | tracking.json missing/corrupt | `cat .planning/tracking.json` to inspect, or restore from `git checkout HEAD -- .planning/tracking.json` |
|
|
152
|
-
| "ERP API key missing" | `~/.claude/.erp-api-key` empty | `qualia-framework set-erp-key
|
|
152
|
+
| "ERP API key missing" | `~/.claude/.erp-api-key` empty | `printf '%s' "$QUALIA_ERP_KEY" \| qualia-framework set-erp-key` (ask Fawzi for the key) |
|
|
153
153
|
| "ERP auth failed (401)" | Key revoked or wrong | Ask Fawzi for a fresh key |
|
|
154
154
|
| "ERP upload failed after 3 attempts" | ERP down or network issue | Local commit is safe. Re-run `/qualia-report` later. |
|
|
155
155
|
| "git push failed" | Auth or network or upstream issue | `git push` manually, see the error, fix, re-run |
|
|
@@ -181,52 +181,16 @@ IDEMPOTENCY_KEY=$(node -e "
|
|
|
181
181
|
|
|
182
182
|
# Guard: API key required for upload (otherwise curl posts an empty bearer)
|
|
183
183
|
if [ "$ERP_ENABLED" = "true" ] && [ -z "$API_KEY" ] && [ "$DRY_RUN" != "true" ]; then
|
|
184
|
-
node ~/.claude/bin/qualia-ui.js warn "ERP API key missing (~/.claude/.erp-api-key). Run: qualia-framework set-erp-key
|
|
184
|
+
node ~/.claude/bin/qualia-ui.js warn "ERP API key missing (~/.claude/.erp-api-key). Run: printf '%s' \"\$QUALIA_ERP_KEY\" | qualia-framework set-erp-key"
|
|
185
185
|
ERP_ENABLED="false"
|
|
186
186
|
fi
|
|
187
187
|
|
|
188
|
-
# Build payload (env-var-passed user values to dodge shell escaping)
|
|
188
|
+
# Build payload (env-var-passed user values to dodge shell escaping).
|
|
189
|
+
# `report-payload.js` is the canonical, tested Framework -> ERP payload builder.
|
|
189
190
|
PAYLOAD=$(
|
|
190
191
|
SUBMITTED_BY="$SUBMITTED_BY" SUBMITTED_AT="$SUBMITTED_AT" \
|
|
191
192
|
CLIENT_REPORT_ID="$CLIENT_REPORT_ID" REPORT_FILE="$REPORT_FILE" \
|
|
192
|
-
node -
|
|
193
|
-
const fs=require('fs'),path=require('path'),os=require('os');
|
|
194
|
-
const {spawnSync}=require('child_process');
|
|
195
|
-
const git=(a)=>{const r=spawnSync('git',a,{encoding:'utf8',timeout:3000});return r.status===0?r.stdout.trim():'';};
|
|
196
|
-
const repoSlug=(r)=>(r||'').replace(/^git@github\\.com:/,'github.com/').replace(/^https?:\\/\\//,'').replace(/\\.git$/,'').split('/').filter(Boolean).pop();
|
|
197
|
-
let config={};try{config=JSON.parse(fs.readFileSync(path.join(os.homedir(),'.claude/.qualia-config.json'),'utf8'));}catch{}
|
|
198
|
-
const t=JSON.parse(fs.readFileSync('.planning/tracking.json','utf8'));
|
|
199
|
-
const notes=fs.readFileSync(process.env.REPORT_FILE,'utf8').substring(0,60000);
|
|
200
|
-
const commits=[];try{const r=spawnSync('git',['log','--oneline','--since=8 hours ago','--format=%h'],{encoding:'utf8',timeout:3000});if(r.stdout)commits.push(...r.stdout.trim().split('\n').filter(Boolean));}catch{}
|
|
201
|
-
const gitRemote=t.git_remote||git(['config','--get','remote.origin.url']);
|
|
202
|
-
const projectKey=t.project_id||repoSlug(gitRemote)||require('path').basename(process.cwd());
|
|
203
|
-
// Session duration: minutes from session_started_at to submitted_at. The ERP's
|
|
204
|
-
// example payload (docs/erp-contract.md:93) includes this; without it the ERP
|
|
205
|
-
// can't compute shift-length analytics without parsing notes.
|
|
206
|
-
let sessionDurationMinutes=0;
|
|
207
|
-
if(t.session_started_at){
|
|
208
|
-
const startMs=Date.parse(t.session_started_at);
|
|
209
|
-
const endMs=Date.parse(process.env.SUBMITTED_AT)||Date.now();
|
|
210
|
-
if(!Number.isNaN(startMs)&&endMs>startMs){
|
|
211
|
-
sessionDurationMinutes=Math.round((endMs-startMs)/60000);
|
|
212
|
-
}
|
|
213
|
-
}
|
|
214
|
-
console.log(JSON.stringify({
|
|
215
|
-
project:t.project||require('path').basename(process.cwd()),
|
|
216
|
-
project_id:projectKey,team_id:t.team_id||'qualia-solutions',git_remote:gitRemote,
|
|
217
|
-
client:t.client||'',client_report_id:process.env.CLIENT_REPORT_ID,
|
|
218
|
-
framework_version:config.version||'',milestone:t.milestone||1,
|
|
219
|
-
milestone_name:t.milestone_name||'',milestones:Array.isArray(t.milestones)?t.milestones:[],
|
|
220
|
-
phase:t.phase,phase_name:t.phase_name,total_phases:t.total_phases,status:t.status,
|
|
221
|
-
tasks_done:t.tasks_done||0,tasks_total:t.tasks_total||0,verification:t.verification||'pending',
|
|
222
|
-
gap_cycles:(t.gap_cycles||{})[String(t.phase)]||0,build_count:t.build_count||0,
|
|
223
|
-
deploy_count:t.deploy_count||0,deployed_url:t.deployed_url||'',
|
|
224
|
-
session_started_at:t.session_started_at||'',last_pushed_at:t.last_pushed_at||'',
|
|
225
|
-
session_duration_minutes:sessionDurationMinutes,
|
|
226
|
-
lifetime:t.lifetime||{},commits:commits,notes:notes,
|
|
227
|
-
submitted_by:process.env.SUBMITTED_BY||'unknown',submitted_at:process.env.SUBMITTED_AT
|
|
228
|
-
}));
|
|
229
|
-
"
|
|
193
|
+
node ~/.claude/bin/report-payload.js
|
|
230
194
|
)
|
|
231
195
|
|
|
232
196
|
# --dry-run: print and stop
|
|
@@ -32,7 +32,7 @@ Final milestone = Handoff:
|
|
|
32
32
|
Done.
|
|
33
33
|
```
|
|
34
34
|
|
|
35
|
-
## Design as a thread
|
|
35
|
+
## Design as a thread
|
|
36
36
|
Every road agent loads `PRODUCT.md + DESIGN.md + design-laws.md` substrate. Builders run `slop-detect` on every frontend commit. Verifiers score 8 design dimensions per phase.
|
|
37
37
|
|
|
38
38
|
## /qualia-polish is scope-adaptive
|
|
@@ -45,7 +45,19 @@ Every road agent loads `PRODUCT.md + DESIGN.md + design-laws.md` substrate. Buil
|
|
|
45
45
|
/qualia-polish --quick ~1m gates only
|
|
46
46
|
```
|
|
47
47
|
|
|
48
|
-
##
|
|
48
|
+
## Design pivots — /qualia-vibe (v6.1+)
|
|
49
|
+
```
|
|
50
|
+
/qualia-vibe fast aesthetic pivot: ONE proposed direction, swap tokens, keep layout (~3 min)
|
|
51
|
+
/qualia-vibe brutalist explicit pivot to named direction
|
|
52
|
+
/qualia-vibe --variants 3 opt-in menu (uses AskUserQuestion; default flow is one-opinion)
|
|
53
|
+
/qualia-vibe --extract https://stripe.com reverse-engineer DESIGN.md from a reference URL
|
|
54
|
+
/qualia-vibe --extract ./inspo.png same, from a local screenshot
|
|
55
|
+
/qualia-vibe --sync show drift between code (CSS vars, Tailwind config) and DESIGN.md
|
|
56
|
+
/qualia-vibe --sync --write patch DESIGN.md to match code, commit
|
|
57
|
+
```
|
|
58
|
+
`/qualia-vibe` is for the WHOLE-SITE aesthetic. For surgical component-level fixes use `/qualia-polish` (component or section scope). For ground-up structural redesign use `/qualia-polish --redesign`.
|
|
59
|
+
|
|
60
|
+
## /qualia-polish --loop — autonomous visual QA
|
|
49
61
|
```
|
|
50
62
|
/qualia-polish --loop http://localhost:3000 screenshot + eval + fix loop
|
|
51
63
|
/qualia-polish --loop {url} --max 4 cap iterations
|
|
@@ -55,14 +67,14 @@ Every road agent loads `PRODUCT.md + DESIGN.md + design-laws.md` substrate. Buil
|
|
|
55
67
|
```
|
|
56
68
|
Screenshots at 3 viewports (375/768/1440), scores 8 design dimensions using vision, fixes issues, re-screenshots, loops until all dims >= 3 or kill-switch triggers. Per-iteration git commits for clean revert.
|
|
57
69
|
|
|
58
|
-
##
|
|
70
|
+
## Deterministic-enforcement skills
|
|
59
71
|
```
|
|
60
72
|
/qualia-hook-gen convert a CLAUDE.md/rules instruction into a deterministic pre-tool-use hook
|
|
61
73
|
/qualia-optimize --deepen spawns 3 parallel interface-design variants per candidate (Step 5b)
|
|
62
74
|
```
|
|
63
75
|
`/qualia-hook-gen` reduces lifetime token cost (each migrated rule frees ~50-200 tokens per request). `/qualia-optimize --deepen` produces dramatically better refactor RFCs because 3 radically-different interfaces are surfaced and the human picks/hybridizes.
|
|
64
76
|
|
|
65
|
-
## Alignment substrate
|
|
77
|
+
## Alignment substrate
|
|
66
78
|
Before high-stakes phases, run alignment skills against `.planning/CONTEXT.md` (domain glossary) and `.planning/decisions/` (ADRs):
|
|
67
79
|
|
|
68
80
|
```
|
|
@@ -105,7 +117,7 @@ No accumulated garbage. No context rot.
|
|
|
105
117
|
- **Intent verification** — Confirm before modifying 3+ files (OWNER role: just do it)
|
|
106
118
|
|
|
107
119
|
## Tracking
|
|
108
|
-
`.planning/tracking.json` is updated on every push.
|
|
120
|
+
`.planning/tracking.json` is updated locally on every push. It feeds statusline, stop-session-log, and `/qualia-report`; the ERP receives explicit report uploads and does not read this file from git.
|
|
109
121
|
Never edit tracking.json manually — hooks update it from STATE.md.
|
|
110
122
|
|
|
111
123
|
## Compaction — ALWAYS preserve
|
|
@@ -19,7 +19,7 @@ Spawn verifier to check phase goal. Does NOT trust build summaries; greps codeba
|
|
|
19
19
|
`/qualia-verify` — verify current built phase
|
|
20
20
|
`/qualia-verify {N}` — verify specific phase
|
|
21
21
|
`/qualia-verify {N} --auto` — verify + auto-chain: PASS → next phase/milestone; FAIL → gap closure; gap limit → halt
|
|
22
|
-
`/qualia-verify {N} --adversarial` — second verifier in fresh context with adversarial prompt. Union findings. Recommended for high-stakes phases (Handoff, payment/auth/migration).
|
|
22
|
+
`/qualia-verify {N} --adversarial` — second verifier in fresh context with adversarial prompt. Union findings. Recommended for high-stakes phases (Handoff, payment/auth/migration).
|
|
23
23
|
|
|
24
24
|
## Process
|
|
25
25
|
|
|
@@ -106,7 +106,7 @@ Findings merge into main report. Union PASS/FAIL: either pass found CRITICAL/HIG
|
|
|
106
106
|
|
|
107
107
|
### 2d. INSUFFICIENT EVIDENCE downgrade (mandatory)
|
|
108
108
|
|
|
109
|
-
The verifier marks criteria it could not check (budget exhaustion, missing context) as `INSUFFICIENT EVIDENCE`. The orchestrator
|
|
109
|
+
The verifier marks criteria it could not check (budget exhaustion, missing context) as `INSUFFICIENT EVIDENCE`. The orchestrator must treat those as FAIL before declaring PASS. Grep the verification file and downgrade immediately:
|
|
110
110
|
|
|
111
111
|
```bash
|
|
112
112
|
IE_COUNT=$(grep -c "INSUFFICIENT EVIDENCE" .planning/phase-{N}-verification.md 2>/dev/null || echo 0)
|
|
@@ -142,7 +142,7 @@ Per gap:
|
|
|
142
142
|
node ~/.claude/bin/qualia-ui.js fail "{gap description}"
|
|
143
143
|
```
|
|
144
144
|
|
|
145
|
-
**Self-healing
|
|
145
|
+
**Self-healing:** before re-planning gaps, run postmortem so the framework learns from the miss. Writes `.planning/phase-{N}-postmortem.md`. Does NOT auto-apply deltas unless user runs `/qualia-postmortem --apply`.
|
|
146
146
|
|
|
147
147
|
```
|
|
148
148
|
/qualia-postmortem --phase {N}
|