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.
Files changed (81) hide show
  1. package/AGENTS.md +2 -1
  2. package/CLAUDE.md +2 -1
  3. package/README.md +45 -29
  4. package/agents/builder.md +1 -5
  5. package/agents/plan-checker.md +1 -1
  6. package/agents/planner.md +2 -6
  7. package/agents/qa-browser.md +3 -3
  8. package/agents/roadmapper.md +2 -2
  9. package/agents/verifier.md +7 -9
  10. package/agents/visual-evaluator.md +1 -3
  11. package/bin/cli.js +370 -205
  12. package/bin/erp-retry.js +11 -3
  13. package/bin/install.js +383 -55
  14. package/bin/knowledge-flush.js +25 -13
  15. package/bin/knowledge.js +11 -1
  16. package/bin/project-snapshot.js +293 -0
  17. package/bin/qualia-ui.js +13 -2
  18. package/bin/report-payload.js +137 -0
  19. package/bin/slop-detect.mjs +81 -9
  20. package/bin/state.js +8 -1
  21. package/bin/statusline.js +14 -2
  22. package/docs/archive/CHANGELOG-pre-v4.md +855 -0
  23. package/docs/changelog-v6.html +864 -0
  24. package/docs/ecosystem-operating-model.md +121 -0
  25. package/docs/erp-contract.md +74 -21
  26. package/docs/onboarding.html +2 -2
  27. package/docs/release.md +44 -0
  28. package/docs/reviews/v6.2.1-revival-audit.md +53 -0
  29. package/docs/reviews/v6.2.2-memory-erp-audit.md +41 -0
  30. package/docs/reviews/v6.2.3-erp-id-guard.md +15 -0
  31. package/guide.md +28 -3
  32. package/hooks/auto-update.js +20 -10
  33. package/hooks/branch-guard.js +10 -2
  34. package/hooks/env-empty-guard.js +15 -5
  35. package/hooks/git-guardrails.js +10 -1
  36. package/hooks/migration-guard.js +4 -1
  37. package/hooks/pre-deploy-gate.js +11 -1
  38. package/hooks/pre-push.js +43 -106
  39. package/hooks/session-start.js +22 -14
  40. package/hooks/stop-session-log.js +11 -3
  41. package/hooks/supabase-destructive-guard.js +11 -1
  42. package/hooks/vercel-account-guard.js +12 -3
  43. package/package.json +4 -3
  44. package/qualia-design/design-reference.md +2 -1
  45. package/qualia-design/frontend.md +4 -4
  46. package/rules/one-opinion.md +59 -0
  47. package/rules/trust-boundary.md +35 -0
  48. package/skills/qualia-feature/SKILL.md +5 -5
  49. package/skills/qualia-flush/SKILL.md +5 -7
  50. package/skills/qualia-hook-gen/SKILL.md +1 -1
  51. package/skills/qualia-learn/SKILL.md +1 -0
  52. package/skills/qualia-map/SKILL.md +2 -1
  53. package/skills/qualia-milestone/SKILL.md +2 -2
  54. package/skills/qualia-new/SKILL.md +6 -6
  55. package/skills/qualia-optimize/SKILL.md +1 -1
  56. package/skills/qualia-plan/SKILL.md +1 -1
  57. package/skills/qualia-polish/REFERENCE.md +8 -6
  58. package/skills/qualia-polish/SKILL.md +11 -9
  59. package/skills/qualia-polish/scripts/loop.mjs +18 -6
  60. package/skills/qualia-postmortem/SKILL.md +1 -1
  61. package/skills/qualia-report/SKILL.md +6 -42
  62. package/skills/qualia-road/SKILL.md +17 -5
  63. package/skills/qualia-verify/SKILL.md +3 -3
  64. package/skills/qualia-vibe/SKILL.md +226 -0
  65. package/skills/qualia-vibe/scripts/extract.mjs +141 -0
  66. package/skills/qualia-vibe/scripts/tokens.mjs +342 -0
  67. package/templates/help.html +10 -3
  68. package/templates/knowledge/agents.md +3 -3
  69. package/templates/knowledge/index.md +1 -1
  70. package/templates/tracking.json +3 -0
  71. package/templates/work-packet.md +46 -0
  72. package/tests/bin.test.sh +423 -25
  73. package/tests/hooks.test.sh +1 -8
  74. package/tests/install-smoke.test.sh +137 -0
  75. package/tests/published-install-smoke.test.sh +126 -0
  76. package/tests/refs.test.sh +43 -1
  77. package/tests/run-all.sh +49 -0
  78. package/tests/runner.js +19 -33
  79. package/tests/slop-detect.test.sh +11 -5
  80. package/tests/state.test.sh +4 -1
  81. package/hooks/pre-compact.js +0 -125
@@ -0,0 +1,121 @@
1
+ # Qualia Ecosystem Operating Model
2
+
3
+ The three systems have different jobs:
4
+
5
+ | Layer | System | Owns |
6
+ |---|---|---|
7
+ | Execution | Qualia Framework | Planning, building, verifying, shipping, handoff, and reporting inside a project repo. |
8
+ | Knowledge | Qualia Memory | Lessons, client preferences, recurring mistakes, durable research, and reusable patterns. |
9
+ | Operations | Qualia ERP | Live clients, projects, assignments, milestones, reports, invoices, payments, schedules, dashboards, and client portal state. |
10
+
11
+ Short version: **Framework builds. Memory remembers. ERP operates.**
12
+
13
+ ## Boundaries
14
+
15
+ - Framework `.planning/` is execution state for agents and local reporting.
16
+ - ERP is the operational source of truth for admin and employee visibility.
17
+ - Memory stores durable knowledge, not live operational status.
18
+ - Read.ai and meeting tools are inputs, not a fourth source of truth.
19
+
20
+ ## Safe Flows
21
+
22
+ ### ERP to Framework
23
+
24
+ ERP can provide a work packet before a session starts:
25
+
26
+ ```text
27
+ ERP project context
28
+ -> templates/work-packet.md
29
+ -> Claude/Codex session
30
+ -> Framework command
31
+ -> plan/build/verify/report
32
+ ```
33
+
34
+ The work packet should include project/client IDs, current milestone, open blockers, latest report, assigned employee, approved work, and guardrails. It should not silently change Framework state; the agent still uses `state.js` and `.planning/` for execution.
35
+
36
+ ### Framework to ERP
37
+
38
+ Framework reports through `/qualia-report`:
39
+
40
+ ```text
41
+ Framework session
42
+ -> .planning/reports/report-YYYY-MM-DD.md
43
+ -> POST /api/v1/reports
44
+ -> ERP session report and admin dashboard
45
+ ```
46
+
47
+ This is the primary sync. It is explicit, idempotent, and employee-visible.
48
+
49
+ Framework can also export a project-level snapshot for admin visibility:
50
+
51
+ ```text
52
+ qualia-framework project-snapshot --write
53
+ -> .planning/snapshots/project-snapshot-*.json
54
+ -> ERP imports current 0-to-100 progress as a draft/project telemetry record
55
+ ```
56
+
57
+ Or, when ERP credentials are configured:
58
+
59
+ ```text
60
+ qualia-framework project-snapshot --upload
61
+ -> POST /api/v1/project-snapshots
62
+ -> ERP updates the canonical project's latest Framework progress metadata
63
+ ```
64
+
65
+ The snapshot is not a replacement for `/qualia-report`; it is the project-level rollup. It carries shared IDs, current milestone/phase, closed milestones, lifetime counters, deployment counters, and a progress percentage so ERP/admin views can show where a project stands without guessing from names or scraping local files.
66
+
67
+ ### Framework Planning Snapshots to ERP
68
+
69
+ If ERP wants `.planning/JOURNEY.md`, `ROADMAP.md`, `STATE.md`, or `tracking.json`, use an explicit import/snapshot workflow. Do not depend on passive git scraping or hook-created bot commits.
70
+
71
+ Acceptable future contract:
72
+
73
+ ```text
74
+ Framework creates a planning snapshot
75
+ -> .planning/snapshots/project-snapshot-*.json
76
+ -> or POST /api/v1/project-snapshots
77
+ -> GitHub or API upload
78
+ -> ERP imports phases/items as draft operational records
79
+ -> human or approved automation confirms client-visible changes
80
+ ```
81
+
82
+ Framework tasks remain internal execution units. ERP assignments, deadlines, and client-visible statuses remain ERP-owned.
83
+
84
+ ### Framework to Memory
85
+
86
+ Framework promotes durable lessons through `/qualia-learn`, `/qualia-postmortem`, or the knowledge flush:
87
+
88
+ ```text
89
+ session report / postmortem / lesson
90
+ -> Memory raw note
91
+ -> wiki concept, client preference, or project lesson
92
+ -> future recall before planning
93
+ ```
94
+
95
+ ### Memory to Framework and ERP
96
+
97
+ Memory can provide context and draft suggestions. It must not directly override ERP operational state.
98
+
99
+ ```text
100
+ Memory context
101
+ -> draft or planning context
102
+ -> human/approved automation confirms
103
+ -> ERP update or Framework execution
104
+ ```
105
+
106
+ ## Shared Identifiers
107
+
108
+ Use these wherever available:
109
+
110
+ | Identifier | Meaning |
111
+ |---|---|
112
+ | `project_id` | Stable Framework/project key, safe across folder renames. |
113
+ | `erp_project_id` | ERP canonical project UUID. |
114
+ | `client_id` | ERP/client canonical UUID. |
115
+ | `team_id` | Qualia/team identity. |
116
+ | `workspace_id` | Tenant/workspace UUID. |
117
+ | `git_remote` | Repository correlation key. |
118
+ | `framework_version` | Framework version that produced a report. |
119
+ | `client_report_id` | Per-project report sequence such as `QS-REPORT-03`. |
120
+
121
+ The less these systems guess from names, the cleaner admin tracking becomes.
@@ -15,7 +15,7 @@ Phase and task counters remain framework telemetry. They help agents plan/build/
15
15
 
16
16
  ## Configuration
17
17
 
18
- Stored in `~/.claude/.qualia-config.json`:
18
+ Stored in the active install home, either `~/.claude/.qualia-config.json` or `~/.codex/.qualia-config.json`:
19
19
 
20
20
  ```json
21
21
  {
@@ -27,7 +27,7 @@ Stored in `~/.claude/.qualia-config.json`:
27
27
  }
28
28
  ```
29
29
 
30
- The API key is read from `~/.claude/.erp-api-key` (file mode 0600).
30
+ The API key is read from `.erp-api-key` in the same install home (file mode 0600).
31
31
 
32
32
  ## Endpoints
33
33
 
@@ -54,7 +54,10 @@ below).
54
54
  {
55
55
  "project": "client-project-name",
56
56
  "project_id": "qs-acme-portal",
57
+ "erp_project_id": "7b5d3b4e-2b8a-4de4-91a1-9b2f3182f5ef",
58
+ "client_id": "5f5a8d8e-8c58-4c30-9b76-13a08f0d0d8a",
57
59
  "team_id": "qualia-solutions",
60
+ "workspace_id": "2af02a2d-6f1f-4d43-a6cb-6a1e7e09ac43",
58
61
  "git_remote": "github.com/QualiasolutionsCY/acme-portal",
59
62
  "client": "Client Name",
60
63
  "client_report_id": "QS-REPORT-03",
@@ -97,8 +100,7 @@ below).
97
100
  }
98
101
  ```
99
102
 
100
- **`gap_cycles` polymorphism (v3.5+):** in `tracking.json` (the file the ERP
101
- reads from git for passive monitoring) `gap_cycles` is an OBJECT keyed by
103
+ **`gap_cycles` polymorphism (v3.5+):** in local `tracking.json`, `gap_cycles` is an OBJECT keyed by
102
104
  phase number — `{"1": 0, "2": 1}`. In the POST `/api/v1/reports` body,
103
105
  `/qualia-report` flattens to a NUMBER for the current phase. Receivers must
104
106
  accept both shapes: if object, use `gap_cycles[String(phase)] || 0`.
@@ -171,42 +173,90 @@ Authorization: Bearer <api-key>
171
173
  }
172
174
  ```
173
175
 
174
- ### GET /api/v1/tracking/:project
176
+ ## Project Snapshot Export
175
177
 
176
- Retrieve current tracking state (same shape as tracking.json).
178
+ `qualia-framework project-snapshot --write` creates a local project-level rollup at:
177
179
 
178
- **Headers:**
180
+ ```text
181
+ .planning/snapshots/project-snapshot-YYYY-MM-DDTHH-MM-SS-sssZ.json
179
182
  ```
183
+
184
+ This is the explicit Framework -> ERP import artifact for admin/project dashboards. It is separate from `/qualia-report`: reports describe one work session; snapshots describe where the project stands from kickoff to handoff.
185
+
186
+ `qualia-framework project-snapshot --upload` sends the same JSON to ERP:
187
+
188
+ ```http
189
+ POST /api/v1/project-snapshots
180
190
  Authorization: Bearer <api-key>
191
+ Content-Type: application/json
181
192
  ```
182
193
 
183
- **Response (200 OK):**
194
+ ERP resolves `identifiers.erp_project_id` first, then falls back to repo/name matching. A successful import stores the latest snapshot and `framework_progress_percent` on the canonical ERP project's metadata so project dashboards can show current Framework progress.
195
+
196
+ Snapshot shape:
197
+
184
198
  ```json
185
199
  {
186
- "ok": true,
187
- "tracking": {
188
- "project": "client-project-name",
200
+ "snapshot_version": 1,
201
+ "generated_at": "2026-05-21T00:00:00.000Z",
202
+ "source": "qualia-framework",
203
+ "framework_version": "6.2.6",
204
+ "identifiers": {
205
+ "project_id": "qs-acme-portal",
206
+ "team_id": "qualia-solutions",
207
+ "git_remote": "github.com/QualiasolutionsCY/acme-portal",
208
+ "erp_project_id": "7b5d3b4e-2b8a-4de4-91a1-9b2f3182f5ef",
209
+ "client_id": "5f5a8d8e-8c58-4c30-9b76-13a08f0d0d8a"
210
+ },
211
+ "project": {
212
+ "name": "acme-portal",
213
+ "client": "Acme",
214
+ "status": "built",
215
+ "deployed_url": "https://client.vercel.app",
216
+ "progress_percent": 42
217
+ },
218
+ "current": {
189
219
  "milestone": 2,
220
+ "milestone_name": "Product",
190
221
  "phase": 2,
222
+ "phase_name": "Dashboard",
191
223
  "total_phases": 4,
192
- "status": "built",
193
- "last_updated": "2026-04-12T14:30:00Z",
194
- "lifetime": {
195
- "tasks_completed": 23,
196
- "phases_completed": 8,
197
- "milestones_completed": 1,
198
- "total_phases": 8
199
- }
224
+ "tasks_done": 3,
225
+ "tasks_total": 5,
226
+ "verification": "pending",
227
+ "gap_cycles": 1
228
+ },
229
+ "journey": {
230
+ "total_milestones": 3,
231
+ "milestones": [
232
+ { "num": 1, "name": "Foundation", "status": "closed" },
233
+ { "num": 2, "name": "Product", "status": "active" },
234
+ { "num": 3, "name": "Handoff", "status": "pending" }
235
+ ],
236
+ "closed_milestones": []
237
+ },
238
+ "lifetime": {
239
+ "tasks_completed": 12,
240
+ "phases_completed": 4,
241
+ "milestones_completed": 1,
242
+ "total_phases": 4,
243
+ "last_closed_milestone": 1,
244
+ "build_count": 4,
245
+ "deploy_count": 1
200
246
  }
201
247
  }
202
248
  ```
203
249
 
204
250
  ## Behavior
205
251
 
206
- - When `erp.enabled` is `false`, `/qualia-report` skips the upload silently.
252
+ - When `erp.enabled` is `false`, `/qualia-report` skips the upload and prints an info line so the employee knows the report stayed local.
207
253
  - When the API key file is missing or empty, the upload is skipped with a warning.
208
254
  - Network failures are non-blocking — the report is saved locally regardless.
209
- - The ERP reads `tracking.json` directly from git for real-time status (no API call needed for passive monitoring).
255
+ - `tracking.json` is **local-only** telemetry as of v6.2 (2026-05-20). Pre-v6.2
256
+ the pre-push hook bot-committed it on every push so the ERP could read it
257
+ from GitHub. That consumer was documented here but never actually implemented
258
+ on the ERP side; the bot commits were pollution. The ERP gets all state from
259
+ `/qualia-report` POSTs to `/api/v1/reports` — which is sufficient.
210
260
  - Reports are append-only — no PUT/PATCH/DELETE endpoints exist for
211
261
  external callers. Internal idempotent UPSERT on `(project_id,
212
262
  client_report_id)` retries is the one exception (see "Idempotent UPSERT
@@ -239,6 +289,9 @@ Authorization: Bearer <api-key>
239
289
  | lifetime | object | recommended | Cumulative counters — tasks_completed, phases_completed, milestones_completed, total_phases, last_closed_milestone |
240
290
  | project_id | string | recommended (v3.6+) | Stable per-project identifier — preferred dedupe key over `project` slug. Survives directory renames. |
241
291
  | team_id | string | recommended (v3.6+) | Installation's team identifier. Composite `(team_id, project_id)` is the canonical project key. |
292
+ | erp_project_id | UUID string | optional | ERP's canonical project UUID when known. Strongest direct link for admin dashboards; `/qualia-report` only sends UUID-shaped values. |
293
+ | client_id | UUID string | optional | ERP/client canonical UUID when known. Lets reports attach to the client without guessing from a display name; slug-like values are omitted to avoid ERP validation failures. |
294
+ | workspace_id | UUID string | optional | Workspace/tenant scope for multi-company or multi-team installs; only UUID-shaped values are sent. |
242
295
  | git_remote | string | optional (v3.6+) | e.g. `github.com/QualiasolutionsCY/foo`. Lets the ERP correlate tracking with the source repo. |
243
296
  | session_started_at | string | optional (v3.6+) | ISO 8601 — when the current Claude Code session began. |
244
297
  | last_pushed_at | string | optional (v3.6+) | ISO 8601 — distinct from `last_updated` (which fires on local writes too). |
@@ -295,7 +295,7 @@
295
295
 
296
296
  <header class="marque">
297
297
  <span class="mark">Qualia Framework</span>
298
- <span class="meta">For Moayad &amp; new hires · v5.5</span>
298
+ <span class="meta">For Moayad &amp; new hires · v6.0</span>
299
299
  </header>
300
300
 
301
301
  <section class="hero">
@@ -612,7 +612,7 @@
612
612
  </section>
613
613
 
614
614
  <footer>
615
- <span>Qualia Framework v5.5.0 · Plan, build, verify, ship.</span>
615
+ <span>Qualia Framework v6.2.7 · Plan, build, verify, ship.</span>
616
616
  <span><a href="https://github.com/Qualiasolutions/qualia-framework">github.com/Qualiasolutions/qualia-framework</a></span>
617
617
  </footer>
618
618
 
@@ -0,0 +1,44 @@
1
+ # Release Verification
2
+
3
+ Use this when the repo is ready but `npx qualia-framework@latest install` still needs proof.
4
+
5
+ ## Pre-Publish
6
+
7
+ Run from the release branch before merging:
8
+
9
+ ```bash
10
+ npm test
11
+ npm pack --dry-run
12
+ ```
13
+
14
+ `npm test` proves the source tree and packaged tarball install path. `npm pack --dry-run` proves the files that will be shipped.
15
+
16
+ ## Publish
17
+
18
+ Publish only from the versioned main commit:
19
+
20
+ ```bash
21
+ npm whoami
22
+ npm publish --access public
23
+ npm view qualia-framework version
24
+ ```
25
+
26
+ The final command must print the same version as `package.json`.
27
+
28
+ ## Post-Publish
29
+
30
+ After npm `latest` matches the repo, run:
31
+
32
+ ```bash
33
+ npm run test:published-install
34
+ ```
35
+
36
+ This smoke uses an isolated `HOME` and npm cache, runs `npx --yes qualia-framework@latest install`, selects target `Both`, and verifies:
37
+
38
+ - Claude `CLAUDE.md` is installed with the OWNER role.
39
+ - Codex `AGENTS.md`, `hooks.json`, `agents/*.toml`, `bin/`, `skills/`, `rules/`, templates, and knowledge files are installed with the OWNER role.
40
+ - Role placeholders are gone.
41
+ - The installed hook set is the current 11-hook set with no `pre-compact.js`.
42
+ - The installed `.qualia-config.json` version matches `package.json`.
43
+
44
+ If this fails because npm latest is behind, the framework is not publicly revived yet even if local tests pass.
@@ -0,0 +1,53 @@
1
+ # Qualia Framework Revival Audit - 2026-05-21
2
+
3
+ Scope: current `qualia-framework` worktree moving from `package.json` version `6.2.0` to `6.2.1`, with emphasis on silent failures, dead references, ERP/report truth, Codex and Claude Code compatibility, token discipline, and the "0 to hero" project road.
4
+
5
+ ## Evidence Collected
6
+
7
+ - `npm test` passed all 9 suites after the package-install smoke test was added.
8
+ - `bash tests/refs.test.sh` passed after adding stale-surface guards: 25 checks, 0 failed.
9
+ - `bash tests/skills.test.sh` passed: 168 checks, 0 failed.
10
+ - `bash tests/install-smoke.test.sh` passed: 7 checks, 0 failed.
11
+ - `npm pack --dry-run` succeeded after the version bump and showed `qualia-framework@6.2.1`, 144 package files, 466.7 kB package size, 1.5 MB unpacked.
12
+ - `npm view qualia-framework version` returned `6.1.0`; local package is now `6.2.1`. This means `npx qualia-framework@latest install` does not yet install the local v6.2 contract.
13
+
14
+ ## External 2026 Check
15
+
16
+ - Claude Code skills are live-discovered from `~/.claude/skills/`, project `.claude/skills/`, and parent directories; supporting files should be referenced from `SKILL.md` and loaded on demand. Current framework structure matches this pattern.
17
+ - Claude Code hooks remain event-based and include `PreCompact`, but hooks are arbitrary commands and must be reviewed/tested. Removing Qualia's `pre-compact.js` bot commit is compatible because state durability belongs in `state.js`, not git history.
18
+ - Claude Code subagents use separate context windows and should be used when repeated side work would flood the main context. Qualia's dedicated planner, builder, verifier, researcher, roadmapper, and QA agents still match this model.
19
+ - Codex continues to treat `AGENTS.md` as the cross-agent project instruction surface. The framework's root `AGENTS.md` mirror is the right compatibility layer, but installed Codex behavior should be verified with a real `codex` session after publish.
20
+ - MCP's 2026 direction emphasizes production readiness, security boundaries, and controlled user elicitation. Qualia should keep MCP use explicit and avoid tool servers asking for secrets through elicitation.
21
+
22
+ Sources checked:
23
+ - Claude Code skills: https://code.claude.com/docs/en/slash-commands
24
+ - Claude Code hooks: https://code.claude.com/docs/en/hooks
25
+ - Claude Code subagents: https://code.claude.com/docs/en/sub-agents
26
+ - Codex AGENTS.md pointer: https://github.com/openai/codex/blob/main/docs/agents_md.md
27
+ - AGENTS.md format: https://github.com/agentsmd/agents.md
28
+ - MCP 2026 roadmap: https://blog.modelcontextprotocol.io/posts/2026-mcp-roadmap/
29
+ - MCP elicitation: https://modelcontextprotocol.io/specification/2025-11-25/client/elicitation
30
+
31
+ ## Fixed In This Pass
32
+
33
+ - README and onboarding version text now reflect `v6.2.0`, not `v6.0.0`.
34
+ - README and guide now say 33 skills and include `/qualia-vibe`.
35
+ - Active docs no longer claim the ERP passively reads `tracking.json` from git.
36
+ - `/qualia-road`, `/qualia-milestone`, and `agents/roadmapper.md` now frame `tracking.json` as local/report telemetry instead of an ERP tree source.
37
+ - `/qualia-verify` no longer repeats the old "silent PASS unless downgraded" wording for `INSUFFICIENT EVIDENCE`; it now states fail-closed behavior directly.
38
+ - `/qualia-polish` no longer says optional Lighthouse/axe gates are skipped silently.
39
+ - `tests/refs.test.sh` now fails on stale active-surface claims: passive ERP tracking, removed pre-compact guidance, stale skill count, stale README version, old `INSUFFICIENT EVIDENCE` wording, and silent optional gate language.
40
+ - `tests/install-smoke.test.sh` now proves the packaged tarball can install into both Claude and Codex targets from an isolated HOME.
41
+
42
+ ## Current Verdict
43
+
44
+ The core framework is functional and test-backed, but the public install path is not revived yet because npm latest is still `6.1.0` while this repo is `6.2.1`. Until a verified publish happens, employees using `npx qualia-framework@latest install` do not receive the no-bot-commit contract or the refreshed docs.
45
+
46
+ ## Remaining High-Leverage Work
47
+
48
+ 1. **Publish drift is the current release blocker.** After full tests, publish a patched release so `@latest` matches the repo. Evidence target: `npm view qualia-framework version` returns the new version.
49
+ 2. **Codex install verification should become a test.** The installer already writes `~/.codex/AGENTS.md`, but the next pass should add a non-interactive smoke test that verifies Codex-facing install output contains the role-filled root instructions and no `{{ROLE}}` placeholders.
50
+ 3. **Claude hook modernization should be explicit, not opportunistic.** Current Claude Code exposes newer hook events such as `PostToolUseFailure`, `PostToolBatch`, `InstructionsLoaded`, `SessionEnd`, and agent start/stop events. Qualia does not need to wire all of them, but a future phase should decide which are useful for employee/admin experience instead of drifting hook-by-hook.
51
+ 4. **ERP employee/admin experience should stay report-driven.** Framework telemetry should enrich `/qualia-report`; the ERP should not depend on git scraping internal `.planning` files. This keeps framework tasks internal and preserves the ERP as the oversight layer.
52
+ 5. **Skill count should not grow by default.** The 33-skill surface is already large. Prefer merging or tightening skills before adding new ones unless a new skill removes repeated work that cannot be handled by an existing command.
53
+ 6. **Token awareness should be measured in installed surfaces.** The next audit should report installed `CLAUDE.md`/`AGENTS.md` line count, skill description total size, and agent frontmatter count so "lightweight" is a measurable contract, not a claim.
@@ -0,0 +1,41 @@
1
+ # Qualia Framework Memory/ERP Audit - 2026-05-21
2
+
3
+ Source reviewed: `/home/qualia-new/Downloads/qualia-framework-memory-erp-connection.md`.
4
+
5
+ ## Useful Model Adopted
6
+
7
+ The note's core model is correct and now has a framework home:
8
+
9
+ - Framework builds.
10
+ - Memory remembers.
11
+ - ERP operates.
12
+
13
+ This became `docs/ecosystem-operating-model.md` so employees and admins have one clear boundary document instead of scattered assumptions.
14
+
15
+ ## Correction Applied
16
+
17
+ The note says ERP can sync `.planning/` files from GitHub into project phases/items. That is acceptable only as an explicit import/snapshot workflow. It must not revive the old v6.1 passive `tracking.json` git-scrape story or hook-created bot commits.
18
+
19
+ Current contract:
20
+
21
+ - `/qualia-report` remains the primary Framework -> ERP sync.
22
+ - `.planning` snapshots are allowed only through an explicit future import/API workflow.
23
+ - ERP owns client-visible status, deadlines, assignments, payments, and dashboards.
24
+ - Framework owns local execution state.
25
+ - Memory owns durable knowledge, not live operational truth.
26
+
27
+ ## Changes Made
28
+
29
+ - Added `docs/ecosystem-operating-model.md`.
30
+ - Added `templates/work-packet.md` for ERP-approved session context.
31
+ - Added optional `erp_project_id`, `client_id`, and `workspace_id` fields to `templates/tracking.json`.
32
+ - Updated `bin/state.js` so those identifiers survive `state.js init` / re-init.
33
+ - Updated `/qualia-report` payload construction to send those identifiers only when present.
34
+ - Updated `docs/erp-contract.md` with the new optional fields.
35
+ - Updated `/qualia-report` help text to use the safe piped `set-erp-key` command.
36
+
37
+ ## Remaining Work
38
+
39
+ 1. ERP backend should accept and store `erp_project_id`, `client_id`, and `workspace_id` if it does not already.
40
+ 2. ERP can generate `templates/work-packet.md` content or a JSON equivalent for agents.
41
+ 3. If planning snapshots are needed, define a real endpoint or import job with approval semantics. Do not depend on passive GitHub scraping.
@@ -0,0 +1,15 @@
1
+ # Qualia Framework ERP ID Guard - 2026-05-21
2
+
3
+ After the v6.2.2 Framework/Memory/ERP patch, the ERP route was checked directly in `/home/qualia-new/Projects/qualia-erp/app/api/v1/reports/route.ts`.
4
+
5
+ Finding:
6
+
7
+ - ERP `client_id` is validated as a UUID and stored as an FK to `clients`.
8
+ - ERP already has an `erp_project_id` column and admin reporting reads it.
9
+ - The v6.2.2 framework example used a slug-like `client_id` (`"acme"`) and `/qualia-report` would send any non-empty `client_id`.
10
+
11
+ Fix:
12
+
13
+ - `/qualia-report` now includes `erp_project_id`, `client_id`, and `workspace_id` only when values are UUID-shaped.
14
+ - Docs now label those IDs as UUIDs.
15
+ - `project_id` and `team_id` remain the slug/string identifiers for framework-level dedupe and reporting.
package/guide.md CHANGED
@@ -1,9 +1,31 @@
1
- # Qualia Developer Guide (v5.8)
1
+ # Qualia Developer Guide (v6.2.7)
2
2
 
3
3
  > Follow the road. Type the commands. The framework handles the rest.
4
4
  > `--auto` chains the whole road end-to-end with only two human checkpoints per project.
5
5
 
6
- **v5.8 cleans up the command surface:** `/qualia-polish-loop` is now `/qualia-polish --loop` (one flag instead of two skills). `/qualia-quick`, `/qualia-task`, and `/qualia-prd` are removed after their v5.7 deprecation window; use `/qualia-feature` for single-feature work and `/qualia-discuss` in PROJECT MODE for kickoff capture. Skill count goes from 35 to 32.
6
+ **v6.2.7 is the Codex runtime compatibility patch.** Codex installs now get native `~/.codex/hooks.json`, TOML agents, bin scripts, rules, skills, templates, knowledge, guide, and role config in addition to `AGENTS.md`.
7
+
8
+ **v6.2.5 carries forward.** `qualia-framework project-snapshot --write` creates a single `.planning/snapshots/project-snapshot-*.json` artifact with project identifiers, current milestone/phase, closed milestones, lifetime counters, and a project progress percentage for explicit ERP/admin import.
9
+
10
+ **v6.2.4 carries forward.** The Framework -> ERP report payload now comes from the shipped and tested `report-payload.js` builder, so admin-visible report linking fields are covered by executable tests instead of only prompt prose.
11
+
12
+ **v6.2.3 carries forward.** Framework slugs stay in `project_id`/`team_id`; ERP foreign-key identifiers (`erp_project_id`, `client_id`, `workspace_id`) are sent only when UUID-shaped, so reports do not fail validation because a local slug leaked into an ERP UUID field.
13
+
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
+
16
+ **v6.2.1 carries forward.** Active docs match the v6.2 no-bot-commit model, the explicit `/qualia-report` ERP contract, the current 33-skill surface, and fail-closed `INSUFFICIENT EVIDENCE` behavior. `tests/refs.test.sh` guards those claims.
17
+
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
+
20
+ **v6.2.0 removes hook-created bot commits.** `pre-push.js` stamps local `tracking.json` telemetry but no longer commits it. `pre-compact.js` is gone because `state.js` already gives stronger crash safety with atomic writes plus a journal. ERP sync remains explicit through `/qualia-report` POSTs, not passive git scraping.
21
+
22
+ **v5.9.2 carries forward.** `pre-push.js` self-gates against `branch-guard.js` so a blocked push no longer leaves an orphan bot commit. `qualia-report` ERP payload omits empty ISO datetime fields (avoids 422 from the ERP validator).
23
+
24
+ **v5.9.1 carries forward.** `/qualia-new` opens with the Demo/Full/Quick project-shape gate via `AskUserQuestion`, then exactly one free-text pitch question, then a hard hand-off to `/qualia-discuss` for the structured interview (8 questions for demos, 14 for full projects).
25
+
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
+
28
+ **Surface is 33 skills.** Use `/qualia-feature` for 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.
7
29
 
8
30
  ## The Road
9
31
 
@@ -59,6 +81,9 @@ Append `--auto` to `/qualia-new` and the framework chains every step:
59
81
  | Single feature | `/qualia-feature` | Auto-scoped: inline for trivia, fresh spawn for 1-5 files |
60
82
  | Finishing | `/qualia-polish` | Design and UX pass (scope-adaptive: component / route / app / redesign / critique / quick / loop) |
61
83
  | | `/qualia-polish --loop` | Autonomous visual-polish loop: screenshot, vision-eval, fix, repeat |
84
+ | Pivot the vibe | `/qualia-vibe` | Fast aesthetic pivot (~3 min): swap tokens, keep layout. Propose ONE direction. |
85
+ | | `/qualia-vibe --extract <URL>` | Reverse-engineer DESIGN.md from a reference site |
86
+ | | `/qualia-vibe --sync` | Show / patch drift between code (CSS vars + Tailwind) and DESIGN.md |
62
87
  | | `/qualia-ship` | Deploy to production |
63
88
  | | `/qualia-handoff` | Deliver to client (4 mandatory deliverables) |
64
89
  | Reporting | `/qualia-report` | Log what you did (mandatory before clock-out) |
@@ -119,7 +144,7 @@ If neither helps, paste the error and ask Claude directly. If Claude can't fix i
119
144
  - **Story-file plans:** Every task has Why / Acceptance Criteria / Depends on / Validation inline — the plan IS the brief.
120
145
  - **Wave execution:** Independent tasks run in parallel. Dependent tasks wait.
121
146
  - **Milestone-boundary pauses:** In `--auto` mode, the framework pauses only at real decision points. Everything else runs on rails.
122
- - **tracking.json:** Updated on every push. The ERP reads it automatically. Includes `milestone_name` + `milestones[]` so the ERP can show project and milestone progress without exposing framework tasks as the main employee workflow.
147
+ - **tracking.json:** Updated locally on push. It feeds local statusline, stop-session-log, and `/qualia-report`; the ERP receives explicit report uploads and does not passively scrape this file from git.
123
148
 
124
149
  ## Quick Reference
125
150
 
@@ -10,16 +10,23 @@ const { spawnSync } = require("child_process");
10
10
 
11
11
  const _traceStart = Date.now();
12
12
 
13
- const CLAUDE_DIR = path.join(os.homedir(), ".claude");
14
- const CACHE_FILE = path.join(CLAUDE_DIR, ".qualia-last-update-check");
15
- const CONFIG_FILE = path.join(CLAUDE_DIR, ".qualia-config.json");
16
- const LOCK_FILE = path.join(CLAUDE_DIR, ".qualia-updating");
17
- const NOTIF_FILE = path.join(CLAUDE_DIR, ".qualia-update-available.json");
13
+ function qualiaHome() {
14
+ if (process.env.QUALIA_HOME) return process.env.QUALIA_HOME;
15
+ const parent = path.basename(path.dirname(__dirname));
16
+ if (parent === ".codex" || parent === ".claude") return path.dirname(__dirname);
17
+ return path.join(os.homedir(), ".claude");
18
+ }
19
+
20
+ const QUALIA_HOME = qualiaHome();
21
+ const CACHE_FILE = path.join(QUALIA_HOME, ".qualia-last-update-check");
22
+ const CONFIG_FILE = path.join(QUALIA_HOME, ".qualia-config.json");
23
+ const LOCK_FILE = path.join(QUALIA_HOME, ".qualia-updating");
24
+ const NOTIF_FILE = path.join(QUALIA_HOME, ".qualia-update-available.json");
18
25
  const MAX_AGE_MS = 24 * 60 * 60 * 1000;
19
26
 
20
27
  function _trace(hookName, result, extra) {
21
28
  try {
22
- const traceDir = path.join(os.homedir(), ".claude", ".qualia-traces");
29
+ const traceDir = path.join(QUALIA_HOME, ".qualia-traces");
23
30
  if (!fs.existsSync(traceDir)) fs.mkdirSync(traceDir, { recursive: true });
24
31
  const entry = {
25
32
  hook: hookName,
@@ -76,7 +83,9 @@ try {
76
83
  stdio: ["ignore", "pipe", "ignore"],
77
84
  });
78
85
  latest = ((r.stdout || "").trim());
79
- } catch {}
86
+ } catch (e) {
87
+ _trace("auto-update", "npm-error", { error: e && e.message });
88
+ }
80
89
  try { fs.unlinkSync(LOCK_FILE); } catch {}
81
90
 
82
91
  if (!latest) {
@@ -109,7 +118,7 @@ try {
109
118
  // Invalidate the session-start health cache so the next session re-checks
110
119
  // whether new critical files shipped in the latest version are installed.
111
120
  try {
112
- fs.unlinkSync(path.join(CLAUDE_DIR, ".qualia-install-health.json"));
121
+ fs.unlinkSync(path.join(QUALIA_HOME, ".qualia-install-health.json"));
113
122
  } catch {}
114
123
  _trace("auto-update", "allow", { reason: "notification-written", current: cfg.version, latest });
115
124
  } else {
@@ -117,8 +126,9 @@ try {
117
126
  try { fs.unlinkSync(NOTIF_FILE); } catch {}
118
127
  _trace("auto-update", "allow", { reason: "up-to-date", version: cfg.version });
119
128
  }
120
- } catch {
121
- // Silent — never block the tool call
129
+ } catch (e) {
130
+ // Never block the tool call, but leave a trace so failures are debuggable.
131
+ _trace("auto-update", "error", { error: e && e.message });
122
132
  }
123
133
 
124
134
  process.exit(0);
@@ -12,11 +12,19 @@ const { spawnSync } = require("child_process");
12
12
 
13
13
  const _traceStart = Date.now();
14
14
 
15
- const CONFIG = path.join(os.homedir(), ".claude", ".qualia-config.json");
15
+ function qualiaHome() {
16
+ if (process.env.QUALIA_HOME) return process.env.QUALIA_HOME;
17
+ const parent = path.basename(path.dirname(__dirname));
18
+ if (parent === ".codex" || parent === ".claude") return path.dirname(__dirname);
19
+ return path.join(os.homedir(), ".claude");
20
+ }
21
+
22
+ const QUALIA_HOME = qualiaHome();
23
+ const CONFIG = path.join(QUALIA_HOME, ".qualia-config.json");
16
24
 
17
25
  function _trace(hookName, result, extra) {
18
26
  try {
19
- const traceDir = path.join(os.homedir(), ".claude", ".qualia-traces");
27
+ const traceDir = path.join(QUALIA_HOME, ".qualia-traces");
20
28
  if (!fs.existsSync(traceDir)) fs.mkdirSync(traceDir, { recursive: true });
21
29
  const entry = {
22
30
  hook: hookName,
@@ -9,9 +9,18 @@ const os = require("os");
9
9
 
10
10
  const _traceStart = Date.now();
11
11
 
12
+ function qualiaHome() {
13
+ if (process.env.QUALIA_HOME) return process.env.QUALIA_HOME;
14
+ const parent = path.basename(path.dirname(__dirname));
15
+ if (parent === ".codex" || parent === ".claude") return path.dirname(__dirname);
16
+ return path.join(os.homedir(), ".claude");
17
+ }
18
+
19
+ const QUALIA_HOME = qualiaHome();
20
+
12
21
  function _trace(result, extra) {
13
22
  try {
14
- const traceDir = path.join(os.homedir(), ".claude", ".qualia-traces");
23
+ const traceDir = path.join(QUALIA_HOME, ".qualia-traces");
15
24
  if (!fs.existsSync(traceDir)) fs.mkdirSync(traceDir, { recursive: true });
16
25
  const entry = {
17
26
  hook: "env-empty-guard", result,
@@ -30,10 +39,11 @@ try { if (!process.stdin.isTTY) payload = fs.readFileSync(0, "utf8"); } catch {}
30
39
  let command = "";
31
40
  try {
32
41
  if (payload) command = (JSON.parse(payload).tool_input || {}).command || "";
33
- } catch {
34
- console.error("BLOCKED: env-empty-guard could not parse hook payload.");
35
- _trace("block", { reason: "parse-error" });
36
- process.exit(2);
42
+ } catch (e) {
43
+ // Allow on parse error — this hook only cares about `vercel env` commands, and
44
+ // a malformed payload is not by itself a reason to block unrelated tool calls.
45
+ _trace("allow", { reason: "parse-error", error: e && e.message });
46
+ process.exit(0);
37
47
  }
38
48
 
39
49
  // Only act on vercel env commands.