qualia-framework 3.6.0 → 4.0.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/README.md +96 -51
- package/agents/builder.md +25 -14
- package/agents/plan-checker.md +29 -16
- package/agents/planner.md +33 -24
- package/agents/research-synthesizer.md +25 -12
- package/agents/roadmapper.md +89 -84
- package/agents/verifier.md +11 -2
- package/bin/qualia-ui.js +267 -1
- package/bin/state.js +90 -5
- package/guide.md +84 -21
- package/package.json +1 -1
- package/skills/qualia/SKILL.md +3 -1
- package/skills/qualia-build/SKILL.md +39 -4
- package/skills/qualia-handoff/SKILL.md +87 -12
- package/skills/qualia-idk/SKILL.md +160 -0
- package/skills/qualia-milestone/SKILL.md +122 -79
- package/skills/qualia-new/SKILL.md +151 -230
- package/skills/qualia-plan/SKILL.md +14 -9
- package/skills/qualia-report/SKILL.md +12 -0
- package/skills/qualia-verify/SKILL.md +57 -3
- package/templates/journey.md +113 -0
- package/templates/plan.md +56 -11
- package/templates/requirements.md +82 -22
- package/templates/roadmap.md +41 -14
- package/templates/tracking.json +2 -0
- package/tests/runner.js +169 -4
package/bin/state.js
CHANGED
|
@@ -140,6 +140,8 @@ function writeTracking(t) {
|
|
|
140
140
|
function ensureLifetime(t) {
|
|
141
141
|
if (!t) return t;
|
|
142
142
|
if (typeof t.milestone !== "number") t.milestone = 1;
|
|
143
|
+
if (typeof t.milestone_name !== "string") t.milestone_name = "";
|
|
144
|
+
if (!Array.isArray(t.milestones)) t.milestones = [];
|
|
143
145
|
if (!t.lifetime || typeof t.lifetime !== "object") {
|
|
144
146
|
t.lifetime = {
|
|
145
147
|
tasks_completed: 0,
|
|
@@ -345,9 +347,13 @@ function checkPreconditions(current, target, opts) {
|
|
|
345
347
|
const taskHeaders = planContent.match(/^## Task \d+/gm);
|
|
346
348
|
if (!taskHeaders || taskHeaders.length === 0)
|
|
347
349
|
return fail("INVALID_PLAN", "Plan file has no task headers (expected '## Task N')");
|
|
350
|
+
// Accept either legacy "**Done when:**" or story-file "**Acceptance Criteria:**"
|
|
351
|
+
// so old in-flight plans don't break on upgrade.
|
|
348
352
|
const doneWhenCount = (planContent.match(/\*\*Done when:\*\*/g) || []).length;
|
|
349
|
-
|
|
350
|
-
|
|
353
|
+
const acCount = (planContent.match(/\*\*Acceptance Criteria:\*\*/g) || []).length;
|
|
354
|
+
const anchors = doneWhenCount + acCount;
|
|
355
|
+
if (anchors < taskHeaders.length)
|
|
356
|
+
return fail("INVALID_PLAN", `${taskHeaders.length} tasks but only ${anchors} 'Done when:' or 'Acceptance Criteria:' anchors`);
|
|
351
357
|
}
|
|
352
358
|
|
|
353
359
|
if (target === "verified") {
|
|
@@ -436,6 +442,8 @@ function cmdCheck(opts) {
|
|
|
436
442
|
status: s.status,
|
|
437
443
|
assigned_to: s.assigned_to,
|
|
438
444
|
milestone: t.milestone || 1,
|
|
445
|
+
milestone_name: t.milestone_name || "",
|
|
446
|
+
milestones: t.milestones || [],
|
|
439
447
|
lifetime: t.lifetime,
|
|
440
448
|
verification: t.verification || "pending",
|
|
441
449
|
gap_cycles: (t.gap_cycles || {})[String(s.phase)] || 0,
|
|
@@ -550,6 +558,7 @@ function cmdTransition(opts) {
|
|
|
550
558
|
t.tasks_done = parseInt(opts.tasks_done) || 0;
|
|
551
559
|
t.tasks_total = parseInt(opts.tasks_total) || 0;
|
|
552
560
|
t.wave = parseInt(opts.wave) || 0;
|
|
561
|
+
t.build_count = (parseInt(t.build_count) || 0) + 1;
|
|
553
562
|
s.last_activity = `Phase ${phase} built (${t.tasks_done}/${t.tasks_total} tasks)`;
|
|
554
563
|
if (s.phases[phase - 1]) s.phases[phase - 1].status = "built";
|
|
555
564
|
}
|
|
@@ -601,6 +610,7 @@ function cmdTransition(opts) {
|
|
|
601
610
|
|
|
602
611
|
if (target === "shipped") {
|
|
603
612
|
t.deployed_url = opts.deployed_url || "";
|
|
613
|
+
t.deploy_count = (parseInt(t.deploy_count) || 0) + 1;
|
|
604
614
|
}
|
|
605
615
|
|
|
606
616
|
// Write both files
|
|
@@ -712,6 +722,9 @@ function cmdInit(opts) {
|
|
|
712
722
|
? { ...defaultLifetime, ...(prevLife.lifetime || {}) }
|
|
713
723
|
: { ...defaultLifetime };
|
|
714
724
|
|
|
725
|
+
// Preserve milestones array across re-init (v4: milestone summaries for ERP tree).
|
|
726
|
+
const prevMilestones = (prevLife && Array.isArray(prevLife.milestones)) ? prevLife.milestones : [];
|
|
727
|
+
|
|
715
728
|
// Build tracking — current-phase fields reset, lifetime + identity preserved
|
|
716
729
|
const t = {
|
|
717
730
|
project: opts.project,
|
|
@@ -722,6 +735,8 @@ function cmdInit(opts) {
|
|
|
722
735
|
project_id: opts.project_id || (prevLife ? prevLife.project_id || "" : ""),
|
|
723
736
|
git_remote: opts.git_remote || (prevLife ? prevLife.git_remote || "" : ""),
|
|
724
737
|
milestone: prevLife ? prevLife.milestone : 1,
|
|
738
|
+
milestone_name: opts.milestone_name || (prevLife ? prevLife.milestone_name || "" : ""),
|
|
739
|
+
milestones: prevMilestones,
|
|
725
740
|
phase: 1,
|
|
726
741
|
phase_name: phases[0].name,
|
|
727
742
|
total_phases: totalPhases,
|
|
@@ -854,12 +869,15 @@ function cmdValidatePlan(opts) {
|
|
|
854
869
|
errors.push("No task headers found (expected '## Task N — title')");
|
|
855
870
|
}
|
|
856
871
|
|
|
857
|
-
// Check "Done when" exists for each task
|
|
872
|
+
// Check "Done when" OR "Acceptance Criteria" anchor exists for each task
|
|
873
|
+
// (story-file format uses Acceptance Criteria; legacy format uses Done when)
|
|
858
874
|
const taskCount = taskHeaders ? taskHeaders.length : 0;
|
|
859
875
|
const doneWhenCount = (content.match(/\*\*Done when:\*\*/g) || []).length;
|
|
860
|
-
|
|
876
|
+
const acCount = (content.match(/\*\*Acceptance Criteria:\*\*/g) || []).length;
|
|
877
|
+
const anchors = doneWhenCount + acCount;
|
|
878
|
+
if (anchors < taskCount) {
|
|
861
879
|
errors.push(
|
|
862
|
-
`${taskCount} tasks but only ${
|
|
880
|
+
`${taskCount} tasks but only ${anchors} 'Done when:' or 'Acceptance Criteria:' anchors`
|
|
863
881
|
);
|
|
864
882
|
}
|
|
865
883
|
|
|
@@ -958,6 +976,7 @@ function cmdValidatePlan(opts) {
|
|
|
958
976
|
phase,
|
|
959
977
|
task_count: taskCount,
|
|
960
978
|
done_when_count: doneWhenCount,
|
|
979
|
+
ac_count: acCount,
|
|
961
980
|
contract_count: contractCount,
|
|
962
981
|
warnings: warnings.length > 0 ? warnings : undefined,
|
|
963
982
|
});
|
|
@@ -990,10 +1009,76 @@ function cmdCloseMilestone(opts) {
|
|
|
990
1009
|
);
|
|
991
1010
|
}
|
|
992
1011
|
|
|
1012
|
+
// ─── v4 guard rails ─────────────────────────────────────
|
|
1013
|
+
// A milestone is only closable if it actually acted like one:
|
|
1014
|
+
// (a) all its phases are verified/polished/completed, AND
|
|
1015
|
+
// (b) it had ≥ 2 phases (so a 1-phase "milestone" is forced back to being a phase).
|
|
1016
|
+
// Both guards are bypassable with --force for retroactive bookkeeping.
|
|
1017
|
+
if (!opts.force) {
|
|
1018
|
+
const totalPhases = parseInt(t.total_phases) || s.phases.length || 0;
|
|
1019
|
+
if (totalPhases < 2) {
|
|
1020
|
+
return output(
|
|
1021
|
+
fail(
|
|
1022
|
+
"MILESTONE_TOO_SMALL",
|
|
1023
|
+
`Milestone ${closedMilestone} has only ${totalPhases} phase(s). A milestone needs ≥ 2 phases OR must be a shipped release gate. Use --force if this is intentional (e.g. a preview/demo milestone).`
|
|
1024
|
+
)
|
|
1025
|
+
);
|
|
1026
|
+
}
|
|
1027
|
+
const unfinished = s.phases.filter((p) => {
|
|
1028
|
+
const st = (p.status || "").toLowerCase();
|
|
1029
|
+
return !(st === "verified" || st === "polished" || st === "completed" || st === "complete");
|
|
1030
|
+
});
|
|
1031
|
+
if (unfinished.length > 0) {
|
|
1032
|
+
return output(
|
|
1033
|
+
fail(
|
|
1034
|
+
"MILESTONE_NOT_READY",
|
|
1035
|
+
`Milestone ${closedMilestone} has ${unfinished.length} unfinished phase(s): ${unfinished.map((p) => `${p.num}:${p.name}`).join(", ")}. Verify them first, or use --force.`
|
|
1036
|
+
)
|
|
1037
|
+
);
|
|
1038
|
+
}
|
|
1039
|
+
}
|
|
1040
|
+
|
|
1041
|
+
// ─── Append a summary to milestones[] so the ERP can render the tree ──
|
|
1042
|
+
// This is the minimal metadata needed to reconstruct "milestone N of the
|
|
1043
|
+
// project contained these phases" without replaying git history.
|
|
1044
|
+
const phasesCompleted = s.phases.filter((p) => {
|
|
1045
|
+
const st = (p.status || "").toLowerCase();
|
|
1046
|
+
return st === "verified" || st === "polished" || st === "completed" || st === "complete";
|
|
1047
|
+
}).length;
|
|
1048
|
+
// tasks_completed for THIS milestone = lifetime.tasks_completed minus the
|
|
1049
|
+
// sum of tasks already counted in prior milestones[] entries. This gives
|
|
1050
|
+
// the correct per-milestone count even though `t.tasks_done` only reflects
|
|
1051
|
+
// the current phase, not the cumulative milestone total.
|
|
1052
|
+
const priorMilestoneTasks = Array.isArray(t.milestones)
|
|
1053
|
+
? t.milestones.reduce((sum, m) => sum + (parseInt(m && m.tasks_completed) || 0), 0)
|
|
1054
|
+
: 0;
|
|
1055
|
+
const tasksCompletedThisMilestone = Math.max(
|
|
1056
|
+
0,
|
|
1057
|
+
(parseInt(t.lifetime && t.lifetime.tasks_completed) || 0) - priorMilestoneTasks
|
|
1058
|
+
);
|
|
1059
|
+
const summary = {
|
|
1060
|
+
num: closedMilestone,
|
|
1061
|
+
name: t.milestone_name || `Milestone ${closedMilestone}`,
|
|
1062
|
+
total_phases: parseInt(t.total_phases) || s.phases.length || 0,
|
|
1063
|
+
phases_completed: phasesCompleted,
|
|
1064
|
+
tasks_completed: tasksCompletedThisMilestone,
|
|
1065
|
+
shipped_url: t.deployed_url || "",
|
|
1066
|
+
closed_at: new Date().toISOString(),
|
|
1067
|
+
};
|
|
1068
|
+
t.milestones = Array.isArray(t.milestones) ? t.milestones : [];
|
|
1069
|
+
// Idempotency: don't duplicate if the same milestone number is already logged.
|
|
1070
|
+
const existing = t.milestones.findIndex((m) => m && m.num === closedMilestone);
|
|
1071
|
+
if (existing >= 0) {
|
|
1072
|
+
t.milestones[existing] = summary;
|
|
1073
|
+
} else {
|
|
1074
|
+
t.milestones.push(summary);
|
|
1075
|
+
}
|
|
1076
|
+
|
|
993
1077
|
t.lifetime.milestones_completed += 1;
|
|
994
1078
|
t.lifetime.total_phases += (parseInt(t.total_phases) || 0);
|
|
995
1079
|
t.lifetime.last_closed_milestone = closedMilestone;
|
|
996
1080
|
t.milestone = closedMilestone + 1;
|
|
1081
|
+
t.milestone_name = ""; // cleared; /qualia-milestone reads next one from JOURNEY.md
|
|
997
1082
|
t.last_updated = new Date().toISOString();
|
|
998
1083
|
|
|
999
1084
|
writeTracking(t);
|
package/guide.md
CHANGED
|
@@ -1,63 +1,126 @@
|
|
|
1
|
-
# Qualia Developer Guide
|
|
1
|
+
# Qualia Developer Guide (v4)
|
|
2
2
|
|
|
3
3
|
> Follow the road. Type the commands. The framework handles the rest.
|
|
4
|
+
> v4 adds a `--auto` flag that chains the whole road end-to-end with only two human checkpoints per project.
|
|
4
5
|
|
|
5
6
|
## The Road
|
|
6
7
|
|
|
7
8
|
```
|
|
8
|
-
/qualia-new
|
|
9
|
+
/qualia-new ← Set up project (once). Produces JOURNEY.md — all milestones to handoff.
|
|
9
10
|
↓
|
|
10
|
-
For each phase:
|
|
11
|
-
/qualia-plan
|
|
12
|
-
/qualia-build
|
|
13
|
-
/qualia-verify
|
|
11
|
+
For each phase of the current milestone:
|
|
12
|
+
/qualia-plan ← Plan it (planner + plan-checker, story-file format)
|
|
13
|
+
/qualia-build ← Build it (builder subagents with pre-inlined context)
|
|
14
|
+
/qualia-verify ← Check it actually works (goal-backward + per-task AC)
|
|
14
15
|
↓
|
|
15
|
-
/qualia-
|
|
16
|
-
|
|
17
|
-
|
|
16
|
+
/qualia-milestone ← Close milestone, open next from JOURNEY.md
|
|
17
|
+
↓
|
|
18
|
+
...repeat per milestone until the Handoff milestone...
|
|
19
|
+
↓
|
|
20
|
+
/qualia-polish ← Design pass (part of Handoff milestone)
|
|
21
|
+
/qualia-ship ← Deploy to production
|
|
22
|
+
/qualia-handoff ← Enforce the 4 handoff deliverables
|
|
18
23
|
↓
|
|
19
24
|
Done.
|
|
20
25
|
```
|
|
21
26
|
|
|
27
|
+
## Auto Mode (v4)
|
|
28
|
+
|
|
29
|
+
Append `--auto` to `/qualia-new` and the framework chains every step:
|
|
30
|
+
|
|
31
|
+
```
|
|
32
|
+
/qualia-new --auto
|
|
33
|
+
→ research runs → JOURNEY.md written → approve the whole journey ONCE
|
|
34
|
+
→ auto: plan 1 → build 1 → verify 1 → plan 2 → build 2 → verify 2 → ...
|
|
35
|
+
→ pause at each milestone boundary: "Continue to M{N+1}?"
|
|
36
|
+
→ resume: plan 1 → build 1 → ... of new milestone
|
|
37
|
+
→ eventually reaches Handoff milestone's last phase → ship → handoff → report → done
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
**Human gates in auto mode (total: 2 per project):**
|
|
41
|
+
1. Journey approval after `/qualia-new` research
|
|
42
|
+
2. Each milestone boundary
|
|
43
|
+
|
|
44
|
+
**Plus one halt case:** if a phase fails verification beyond the gap-cycle limit (default 2), the chain stops and asks for human intervention.
|
|
45
|
+
|
|
22
46
|
## The 10 Commands
|
|
23
47
|
|
|
24
48
|
| When | Command | What it does |
|
|
25
49
|
|------|---------|-------------|
|
|
26
|
-
| Starting | `/qualia-new` | Set up project
|
|
50
|
+
| Starting | `/qualia-new` | Set up project with full journey (all milestones → Handoff) |
|
|
51
|
+
| Starting (auto) | `/qualia-new --auto` | Same + chain through building automatically |
|
|
27
52
|
| Building | `/qualia-plan` | Plan the current phase |
|
|
28
53
|
| | `/qualia-build` | Build it (parallel tasks) |
|
|
29
54
|
| | `/qualia-verify` | Check it actually works |
|
|
55
|
+
| Milestone | `/qualia-milestone` | Close current, open next from JOURNEY.md |
|
|
30
56
|
| Quick fix | `/qualia-quick` | Skip planning, just do it |
|
|
31
57
|
| Finishing | `/qualia-polish` | Design and UX pass |
|
|
32
58
|
| | `/qualia-ship` | Deploy to production |
|
|
33
|
-
| | `/qualia-handoff` | Deliver to client |
|
|
34
|
-
| Reporting | `/qualia-report` | Log what you did (mandatory) |
|
|
35
|
-
|
|
|
59
|
+
| | `/qualia-handoff` | Deliver to client (4 mandatory deliverables) |
|
|
60
|
+
| Reporting | `/qualia-report` | Log what you did (mandatory before clock-out) |
|
|
61
|
+
| Lost? | `/qualia` | Mechanical next-command router |
|
|
62
|
+
| Confused? | `/qualia-idk` | Diagnostic — scans planning + code, explains what's going on |
|
|
63
|
+
|
|
64
|
+
## Full Journey Hierarchy (v4)
|
|
65
|
+
|
|
66
|
+
```
|
|
67
|
+
Project
|
|
68
|
+
└─ Journey (the whole arc — mapped upfront by /qualia-new, lives in .planning/JOURNEY.md)
|
|
69
|
+
└─ Milestone (a release — 2-5 total, Handoff is always last)
|
|
70
|
+
└─ Phase (a feature-sized deliverable, 2-5 tasks)
|
|
71
|
+
└─ Task (atomic unit, one commit, one verification contract)
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
Hard rules (enforced by `state.js` and the roadmapper):
|
|
75
|
+
- **Milestone count: 2 to 5.** Final milestone is always literally named "Handoff".
|
|
76
|
+
- **≥ 2 phases per non-Handoff milestone** (single-phase "milestones" are phases, not milestones).
|
|
77
|
+
- **Milestone numbering is contiguous** — no skipped numbers.
|
|
78
|
+
- **Handoff milestone has fixed 4 phases:** Polish, Content + SEO, Final QA, Handoff (credentials + walkthrough + archive + ERP report).
|
|
36
79
|
|
|
37
80
|
## Rules
|
|
38
81
|
|
|
39
82
|
1. **Feature branches only** — never push to main
|
|
40
83
|
2. **Read before write** — don't edit files you haven't read
|
|
41
84
|
3. **MVP first** — build what's asked, nothing extra
|
|
42
|
-
4.
|
|
85
|
+
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
|
|
86
|
+
5. **`/qualia` is your friend** — lost? type it
|
|
87
|
+
6. **`/qualia-idk` is your deeper friend** — not lost on "what command", but confused about the *situation*? Type `idk`.
|
|
43
88
|
|
|
44
89
|
## When You're Stuck
|
|
45
90
|
|
|
46
91
|
```
|
|
47
|
-
/qualia ← "what
|
|
92
|
+
/qualia ← "what command should I run next?" (state-driven, instant)
|
|
93
|
+
/qualia-idk ← "what's actually going on here?" (diagnostic, scans planning + code, ~30s)
|
|
48
94
|
```
|
|
49
95
|
|
|
50
|
-
If
|
|
96
|
+
If neither helps, paste the error and ask Claude directly. If Claude can't fix it, tell Fawzi.
|
|
51
97
|
|
|
52
98
|
## Session Start / End
|
|
53
99
|
|
|
54
|
-
**Start:** Claude loads your project context automatically.
|
|
55
|
-
**End:** Run `/qualia-report` — this is mandatory before clock-out.
|
|
100
|
+
**Start:** Claude loads your project context automatically. The router banner shows your journey position ("M2 of 4 · P2 of 3").
|
|
101
|
+
**End:** Run `/qualia-report` — this is mandatory before clock-out. The report is committed to git and (if ERP is enabled) uploaded to https://portal.qualiasolutions.net.
|
|
56
102
|
|
|
57
103
|
## How It Works (you don't need to know this, but if curious)
|
|
58
104
|
|
|
105
|
+
- **Journey-first planning:** `/qualia-new` produces JOURNEY.md listing every milestone from kickoff to Handoff with exit criteria and phase sketches. The whole team sees the path on day 1.
|
|
59
106
|
- **Context isolation:** Each task runs in a fresh AI brain. Task 50 gets the same quality as Task 1.
|
|
60
|
-
- **
|
|
61
|
-
- **
|
|
107
|
+
- **Pre-inlined context at dispatch:** The builder starts with PROJECT.md, DESIGN.md, and all Context @files already loaded — no wasted orientation reads.
|
|
108
|
+
- **Goal-backward verification:** The verifier doesn't trust "I built it." It greps the code to check if things actually work AND walks every task's Acceptance Criteria.
|
|
109
|
+
- **Story-file plans:** Every task has Why / Acceptance Criteria / Depends on / Validation inline — the plan IS the brief.
|
|
62
110
|
- **Wave execution:** Independent tasks run in parallel. Dependent tasks wait.
|
|
63
|
-
- **
|
|
111
|
+
- **Milestone-boundary pauses:** In `--auto` mode, the framework pauses only at real decision points. Everything else runs on rails.
|
|
112
|
+
- **tracking.json:** Updated on every push. The ERP reads it automatically. v4 adds `milestone_name` + `milestones[]` so the ERP renders a proper tree instead of a flat list.
|
|
113
|
+
|
|
114
|
+
## Quick Reference
|
|
115
|
+
|
|
116
|
+
| Situation | Run |
|
|
117
|
+
|---|---|
|
|
118
|
+
| Starting a new client project | `/qualia-new` (or `/qualia-new --auto` to roll end-to-end) |
|
|
119
|
+
| Starting a quick throwaway | `/qualia-new --quick` |
|
|
120
|
+
| Brownfield project | `/qualia-map` first, then `/qualia-new` |
|
|
121
|
+
| Stuck picking next command | `/qualia` |
|
|
122
|
+
| Confused about the situation | `/qualia-idk` |
|
|
123
|
+
| Finished the last phase of a milestone | `/qualia-milestone` |
|
|
124
|
+
| About to ship | `/qualia-ship` |
|
|
125
|
+
| Client is ready to take over | `/qualia-handoff` |
|
|
126
|
+
| End of workday | `/qualia-report` (mandatory) |
|
package/package.json
CHANGED
package/skills/qualia/SKILL.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: qualia
|
|
3
|
-
description: "Smart router — reads project state, classifies
|
|
3
|
+
description: "Smart router — reads project state (state.js), classifies the situation mechanically, returns the exact next command. Use whenever you type /qualia, 'what next', 'next', 'what now', 'what should I do next', 'what command now'. For deeper 'I don't understand what's going on' / 'something feels off' situations, use /qualia-idk instead — that one actually scans the planning folder and codebase to diagnose the confusion."
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# /qualia — What's Next?
|
|
@@ -56,6 +56,8 @@ Use the state.js JSON output plus gathered context:
|
|
|
56
56
|
**Clear next step** (use the UI helper — it reads state.js itself):
|
|
57
57
|
```bash
|
|
58
58
|
node ~/.claude/bin/qualia-ui.js banner router
|
|
59
|
+
# If a project is loaded, show the journey position first (one-glance orientation)
|
|
60
|
+
test -f .planning/JOURNEY.md && node ~/.claude/bin/qualia-ui.js journey-tree .planning/JOURNEY.md
|
|
59
61
|
node ~/.claude/bin/qualia-ui.js next "{next_command from state.js}"
|
|
60
62
|
```
|
|
61
63
|
|
|
@@ -10,6 +10,7 @@ Execute the phase plan. Each task runs in a fresh subagent context. Independent
|
|
|
10
10
|
## Usage
|
|
11
11
|
`/qualia-build` — build the current planned phase
|
|
12
12
|
`/qualia-build {N}` — build specific phase
|
|
13
|
+
`/qualia-build {N} --auto` — build + chain into `/qualia-verify {N} --auto` when done (no human gate between build and verify)
|
|
13
14
|
|
|
14
15
|
## Process
|
|
15
16
|
|
|
@@ -57,22 +58,44 @@ node ~/.claude/bin/qualia-ui.js wave {W} {total_waves} {tasks_in_wave}
|
|
|
57
58
|
node ~/.claude/bin/qualia-ui.js task {task_num} "{task title}"
|
|
58
59
|
```
|
|
59
60
|
|
|
61
|
+
**Pre-inline context before spawning** (saves 3-5 Read calls inside each builder subagent — GSD-style dispatch):
|
|
62
|
+
|
|
63
|
+
1. Parse the task's `Context:` field to get `@file` references
|
|
64
|
+
2. Read PROJECT.md
|
|
65
|
+
3. Read DESIGN.md if any file in the task is `.tsx`, `.jsx`, `.css`, `.scss`
|
|
66
|
+
4. Read each `@file` referenced in Context
|
|
67
|
+
5. Inline all of the above into the agent prompt under `<pre-loaded-context>` so the builder starts with full context
|
|
68
|
+
|
|
60
69
|
Spawn a fresh builder subagent:
|
|
61
70
|
|
|
62
71
|
```
|
|
63
72
|
Agent(prompt="
|
|
64
73
|
Read your role: @~/.claude/agents/builder.md
|
|
65
74
|
|
|
66
|
-
|
|
67
|
-
|
|
75
|
+
<pre-loaded-context>
|
|
76
|
+
# PROJECT.md
|
|
77
|
+
{inlined contents of .planning/PROJECT.md}
|
|
78
|
+
|
|
79
|
+
# DESIGN.md (if frontend task)
|
|
80
|
+
{inlined contents of .planning/DESIGN.md}
|
|
81
|
+
|
|
82
|
+
# {each @file from task.Context}
|
|
83
|
+
{inlined contents}
|
|
84
|
+
</pre-loaded-context>
|
|
68
85
|
|
|
69
86
|
YOUR TASK:
|
|
70
|
-
{paste the single task block from the plan — title, files,
|
|
87
|
+
{paste the single task block from the plan — title, wave, persona, files, depends-on, why, acceptance-criteria, action, validation, context}
|
|
71
88
|
|
|
72
|
-
|
|
89
|
+
All files in <pre-loaded-context> are already in your working memory — do NOT
|
|
90
|
+
re-Read them. Only Read files NOT in the pre-loaded context (e.g. existing
|
|
91
|
+
project code you need to modify).
|
|
92
|
+
|
|
93
|
+
Execute the task. Commit when done.
|
|
73
94
|
", subagent_type="qualia-builder", description="Task {N}: {title}")
|
|
74
95
|
```
|
|
75
96
|
|
|
97
|
+
**Why pre-inline:** without it, the builder's first actions are 3-5 Read tool calls to orient itself (PROJECT.md, DESIGN.md, context files). With pre-inline, the builder starts already oriented and spends its context budget on the actual task.
|
|
98
|
+
|
|
76
99
|
**After each task completes:**
|
|
77
100
|
- Verify the commit exists: `git log --oneline -1`
|
|
78
101
|
- Show result:
|
|
@@ -110,6 +133,18 @@ node ~/.claude/bin/state.js transition --to built --phase {N} --tasks-done {done
|
|
|
110
133
|
If state.js returns an error, show it to the employee and stop.
|
|
111
134
|
Do NOT manually edit STATE.md or tracking.json — state.js handles both.
|
|
112
135
|
|
|
136
|
+
### 6. Route (auto-chain aware)
|
|
137
|
+
|
|
138
|
+
**If invoked with `--auto`:** immediately invoke `/qualia-verify {N} --auto` inline. No pause, no permission ask. Verify will either chain into the next phase (if PASS), into gap closure (if FAIL and gap cycles remain), or halt with clear escalation (if gap limit reached).
|
|
139
|
+
|
|
140
|
+
```bash
|
|
141
|
+
node ~/.claude/bin/qualia-ui.js info "Auto mode — chaining into /qualia-verify {N}"
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
Then invoke the `qualia-verify` skill inline with the same `--auto` flag.
|
|
145
|
+
|
|
146
|
+
**Otherwise (default guided mode):** stop and show the next step:
|
|
147
|
+
|
|
113
148
|
```bash
|
|
114
149
|
node ~/.claude/bin/qualia-ui.js end "PHASE {N} BUILT" "/qualia-verify {N}"
|
|
115
150
|
```
|
|
@@ -1,11 +1,26 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: qualia-handoff
|
|
3
|
-
description: "Client delivery —
|
|
3
|
+
description: "Client delivery — produces the 4 mandatory Handoff deliverables (production URL, documentation, client assets archive, ERP finalization). Triggered at the end of the Handoff milestone."
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# /qualia-handoff — Client Delivery
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
Finishes a project by producing the 4 mandatory Handoff deliverables defined in `JOURNEY.md`'s Handoff milestone. Every Qualia client project ends with this skill.
|
|
9
|
+
|
|
10
|
+
## When to Use
|
|
11
|
+
|
|
12
|
+
- After `/qualia-ship` on the final phase of the Handoff milestone
|
|
13
|
+
- Invoked automatically at the end of `/qualia-new --auto` chain
|
|
14
|
+
- Can also be run manually if the project deviated from auto mode
|
|
15
|
+
|
|
16
|
+
## The 4 Deliverables
|
|
17
|
+
|
|
18
|
+
Every Handoff milestone must produce these. They are checked against in `REQUIREMENTS.md` as `HAND-10..HAND-15`.
|
|
19
|
+
|
|
20
|
+
1. **Production URL verified** — HTTP 200, auth flow, latency under 500ms
|
|
21
|
+
2. **Documentation** — README with architecture, setup, API docs
|
|
22
|
+
3. **Client Assets** — `.planning/archive/` contains every milestone's verification reports + credentials doc + recorded walkthrough
|
|
23
|
+
4. **ERP Finalization** — final `/qualia-report` with `lifetime.milestones_completed` incremented
|
|
9
24
|
|
|
10
25
|
## Process
|
|
11
26
|
|
|
@@ -13,7 +28,35 @@ Prepare and deliver the finished project to the client.
|
|
|
13
28
|
node ~/.claude/bin/qualia-ui.js banner handoff
|
|
14
29
|
```
|
|
15
30
|
|
|
16
|
-
### 1.
|
|
31
|
+
### 1. Verify Production URL (Deliverable 1)
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
URL=$(node -e "const t=JSON.parse(require('fs').readFileSync('.planning/tracking.json','utf8'));console.log(t.deployed_url||'')")
|
|
35
|
+
if [ -z "$URL" ]; then
|
|
36
|
+
node ~/.claude/bin/qualia-ui.js fail "No deployed_url — run /qualia-ship first"
|
|
37
|
+
exit 1
|
|
38
|
+
fi
|
|
39
|
+
HTTP=$(curl -s -o /dev/null -w "%{http_code}" "$URL")
|
|
40
|
+
LATENCY=$(curl -s -o /dev/null -w "%{time_total}" "$URL")
|
|
41
|
+
AUTH=$(curl -s -o /dev/null -w "%{http_code}" "$URL/api/auth/callback" 2>/dev/null || echo "N/A")
|
|
42
|
+
node ~/.claude/bin/qualia-ui.js ok "URL: $URL (HTTP $HTTP, ${LATENCY}s, auth:$AUTH)"
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
If HTTP is not 2xx or latency > 1.0s → halt; deliverable fails.
|
|
46
|
+
|
|
47
|
+
### 2. Update Documentation (Deliverable 2)
|
|
48
|
+
|
|
49
|
+
Ensure the repo's `README.md` has:
|
|
50
|
+
- **Overview** — what the project does
|
|
51
|
+
- **Architecture** — stack summary, key services (Supabase / Vercel / third-party)
|
|
52
|
+
- **Setup** — how to run locally (clone, env, `npm install`, `npm run dev`)
|
|
53
|
+
- **Env vars** — list from `.env.local.example` (mask values)
|
|
54
|
+
- **Deploy** — "Production deploys via `vercel --prod`. GitHub auto-deploy is DISABLED."
|
|
55
|
+
- **Support** — contact: Fawzi Goussous, fawzi@qualiasolutions.net
|
|
56
|
+
|
|
57
|
+
If README is stale or missing sections, update it and commit.
|
|
58
|
+
|
|
59
|
+
### 3. Generate Handover Doc + Archive (Deliverable 3)
|
|
17
60
|
|
|
18
61
|
Create `.planning/HANDOFF.md`:
|
|
19
62
|
|
|
@@ -21,46 +64,78 @@ Create `.planning/HANDOFF.md`:
|
|
|
21
64
|
# {Project Name} — Handover
|
|
22
65
|
|
|
23
66
|
## What Was Built
|
|
24
|
-
{3-5 bullet summary of delivered features}
|
|
67
|
+
{3-5 bullet summary of delivered features, pulled from JOURNEY.md milestone exit criteria}
|
|
25
68
|
|
|
26
69
|
## Access
|
|
27
70
|
- **URL:** {production URL}
|
|
28
|
-
- **Admin login:** {credentials
|
|
71
|
+
- **Admin login:** {credentials doc location — typically `.planning/credentials.md` (git-ignored)}
|
|
29
72
|
- **Supabase:** {project ref}
|
|
30
73
|
- **GitHub:** {repo URL}
|
|
31
74
|
- **Vercel:** {project URL}
|
|
75
|
+
- **Walkthrough:** {Loom or video link — recorded demo of primary flows}
|
|
32
76
|
|
|
33
77
|
## How to Use
|
|
34
78
|
{Brief walkthrough of the main user flows}
|
|
35
79
|
|
|
36
80
|
## Known Limitations
|
|
37
|
-
{Anything not in scope or deferred}
|
|
81
|
+
{Anything not in scope or deferred, copied from REQUIREMENTS.md Out of Scope + Post-Handoff v2}
|
|
38
82
|
|
|
39
83
|
## Maintenance
|
|
40
|
-
- Hosting: Vercel (
|
|
84
|
+
- Hosting: Vercel (MANUAL deploys via `vercel --prod`)
|
|
41
85
|
- Database: Supabase ({region})
|
|
42
86
|
- Domain: {domain provider if applicable}
|
|
87
|
+
- Monitoring: UptimeRobot status page https://stats.uptimerobot.com/bKudHy1pLs
|
|
88
|
+
|
|
89
|
+
## Milestones Shipped
|
|
90
|
+
{Summary pulled from tracking.json milestones[] — one line per closed milestone with date and phase count}
|
|
43
91
|
|
|
44
92
|
## Support
|
|
45
93
|
Contact: Fawzi Goussous — fawzi@qualiasolutions.net
|
|
94
|
+
Standard support window: 30 days post-handoff.
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
Also ensure `.planning/archive/` contains every milestone's phase verification reports (qualia-milestone moves them there on close — verify they're present).
|
|
98
|
+
|
|
99
|
+
```bash
|
|
100
|
+
ls -la .planning/archive/ 2>/dev/null
|
|
46
101
|
```
|
|
47
102
|
|
|
48
|
-
|
|
103
|
+
If `.planning/archive/` is empty, something went wrong — milestones should have been archived on close. Investigate and recover from git history if needed.
|
|
104
|
+
|
|
105
|
+
### 4. Commit + Push
|
|
49
106
|
|
|
50
107
|
```bash
|
|
51
|
-
git add .planning/HANDOFF.md
|
|
52
|
-
git commit -m "docs: client handoff
|
|
108
|
+
git add .planning/HANDOFF.md README.md
|
|
109
|
+
git commit -m "docs: client handoff — {project name}"
|
|
53
110
|
git push
|
|
54
111
|
```
|
|
55
112
|
|
|
56
|
-
###
|
|
113
|
+
### 5. Update State
|
|
57
114
|
|
|
58
115
|
```bash
|
|
59
116
|
node ~/.claude/bin/state.js transition --to handed_off
|
|
60
117
|
```
|
|
118
|
+
|
|
61
119
|
Do NOT manually edit STATE.md or tracking.json — state.js handles both.
|
|
62
120
|
|
|
121
|
+
### 6. ERP Finalization (Deliverable 4)
|
|
122
|
+
|
|
123
|
+
Trigger the final `/qualia-report`. This uploads the closing state to the ERP with `lifetime.milestones_completed` incremented by the Handoff close that just happened.
|
|
124
|
+
|
|
125
|
+
In `--auto` mode, inline-invoke `/qualia-report` now. In guided mode, show the next step:
|
|
126
|
+
|
|
63
127
|
```bash
|
|
64
|
-
node ~/.claude/bin/qualia-ui.js ok "
|
|
128
|
+
node ~/.claude/bin/qualia-ui.js ok "Production URL verified"
|
|
129
|
+
node ~/.claude/bin/qualia-ui.js ok "Documentation updated"
|
|
130
|
+
node ~/.claude/bin/qualia-ui.js ok "Client assets archived + handoff doc written"
|
|
131
|
+
node ~/.claude/bin/qualia-ui.js ok "Ready for final ERP report"
|
|
65
132
|
node ~/.claude/bin/qualia-ui.js end "DELIVERED" "/qualia-report"
|
|
66
133
|
```
|
|
134
|
+
|
|
135
|
+
## Rules
|
|
136
|
+
|
|
137
|
+
1. **No handoff without verified production URL.** Step 1 halts if URL is down or latency > 1s.
|
|
138
|
+
2. **Archive is mandatory.** `.planning/archive/` must contain every closed milestone's phase artifacts. If empty, the project was handled outside the framework — recover from git history.
|
|
139
|
+
3. **README is the public face.** If it's stale, fix it before handoff. Client reads it first.
|
|
140
|
+
4. **Credentials never in the repo.** `.planning/credentials.md` is git-ignored. Deliver credentials via secure channel (1Password shared vault, encrypted email).
|
|
141
|
+
5. **Support clause is 30 days by default.** If the client contract says otherwise, override it in HANDOFF.md.
|