@haposoft/cafekit 0.15.3 → 0.16.0-rc.1

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 (90) hide show
  1. package/README.md +4 -2
  2. package/bin/__tests__/codex-hooks.test.js +140 -0
  3. package/bin/__tests__/codex-native.test.js +2 -2
  4. package/bin/__tests__/develop-contract.test.js +1120 -0
  5. package/bin/__tests__/installer-safety.test.js +510 -2
  6. package/bin/__tests__/package-inventory.test.js +258 -0
  7. package/bin/__tests__/secret-scanner.test.js +157 -0
  8. package/bin/__tests__/validator-grounding.test.js +713 -0
  9. package/bin/install.js +5 -1
  10. package/bin/lib/codex-install.js +21 -6
  11. package/bin/lib/context.js +17 -6
  12. package/bin/lib/copy-utils.js +31 -0
  13. package/bin/lib/instruction-blocks.js +85 -0
  14. package/bin/lib/managed-writer.js +4 -1
  15. package/bin/lib/opencode-install.js +75 -30
  16. package/bin/phases/claude-runtime.js +103 -4
  17. package/bin/phases/codex-runtime.js +9 -5
  18. package/bin/phases/post-install.js +29 -22
  19. package/bin/phases/root-config.js +89 -10
  20. package/package.json +14 -4
  21. package/src/claude/CLAUDE.md +6 -122
  22. package/src/claude/agents/code-auditor.md +21 -22
  23. package/src/claude/agents/debugger.md +3 -3
  24. package/src/claude/agents/deployer.md +1 -1
  25. package/src/claude/agents/{god-developer.md → implementer.md} +2 -2
  26. package/src/claude/agents/project-manager.md +1 -1
  27. package/src/claude/agents/spec-maker.md +2 -2
  28. package/src/claude/hooks/__tests__/spec-gate.test.js +356 -5
  29. package/src/claude/hooks/agent.cjs +7 -14
  30. package/src/claude/hooks/rules.cjs +33 -53
  31. package/src/claude/hooks/spec-gate.cjs +66 -21
  32. package/src/claude/hooks/spec-state.cjs +5 -0
  33. package/src/claude/migration-manifest.json +9 -2
  34. package/src/claude/runtime.json +0 -3
  35. package/src/claude/scripts/generate-skill-catalog.cjs +1 -1
  36. package/src/claude/scripts/scan-staged-secrets.cjs +170 -0
  37. package/src/claude/scripts/spec-ground.cjs +189 -83
  38. package/src/claude/scripts/validate-spec-output.cjs +294 -30
  39. package/src/claude/scripts/workflow-policy.cjs +609 -0
  40. package/src/claude/skills/ai-multimodal/SKILL.md +2 -2
  41. package/src/claude/skills/ai-multimodal/references/audio-processing.md +6 -6
  42. package/src/claude/skills/ai-multimodal/references/video-analysis.md +1 -1
  43. package/src/claude/skills/backend-development/SKILL.md +4 -4
  44. package/src/claude/skills/backend-development/references/backend-architecture.md +1 -1
  45. package/src/claude/skills/backend-development/references/backend-devops.md +2 -2
  46. package/src/claude/skills/backend-development/references/backend-mindset.md +3 -3
  47. package/src/claude/skills/backend-development/references/backend-performance.md +5 -5
  48. package/src/claude/skills/backend-development/references/backend-security.md +3 -3
  49. package/src/claude/skills/backend-development/references/backend-technologies.md +5 -5
  50. package/src/claude/skills/backend-development/references/backend-testing.md +2 -2
  51. package/src/claude/skills/brainstorm/SKILL.md +2 -3
  52. package/src/claude/skills/code-review/SKILL.md +12 -8
  53. package/src/claude/skills/code-review/references/verification-gate.md +4 -4
  54. package/src/claude/skills/debug/SKILL.md +2 -0
  55. package/src/claude/skills/develop/SKILL.md +100 -52
  56. package/src/claude/skills/develop/references/parallel-waves.md +105 -26
  57. package/src/claude/skills/develop/references/quality-gate.md +58 -38
  58. package/src/claude/skills/develop/references/subagent-patterns.md +2 -2
  59. package/src/claude/skills/git/SKILL.md +44 -50
  60. package/src/claude/skills/hotfix/SKILL.md +10 -8
  61. package/src/claude/skills/hotfix/references/parallel-patterns.md +2 -2
  62. package/src/claude/skills/hotfix/references/review-cycle.md +26 -21
  63. package/src/claude/skills/inspect/SKILL.md +12 -30
  64. package/src/claude/skills/mobile-development/SKILL.md +12 -12
  65. package/src/claude/skills/mobile-development/references/mobile-android.md +7 -7
  66. package/src/claude/skills/mobile-development/references/mobile-best-practices.md +22 -23
  67. package/src/claude/skills/mobile-development/references/mobile-frameworks.md +13 -13
  68. package/src/claude/skills/mobile-development/references/mobile-ios.md +1 -1
  69. package/src/claude/skills/mobile-development/references/mobile-mindset.md +17 -19
  70. package/src/claude/skills/question/SKILL.md +13 -13
  71. package/src/claude/skills/research/SKILL.md +2 -2
  72. package/src/claude/skills/specs/SKILL.md +32 -15
  73. package/src/claude/skills/specs/references/review.md +3 -3
  74. package/src/claude/skills/specs/rules/tasks-generation.md +1 -1
  75. package/src/claude/skills/specs/templates/spec-state.json +7 -3
  76. package/src/claude/skills/sync/SKILL.md +26 -1
  77. package/src/claude/skills/sync/references/sync-protocols.md +3 -3
  78. package/src/claude/skills/test/SKILL.md +12 -4
  79. package/src/claude/skills/test/references/failure-triage.md +17 -17
  80. package/src/claude/skills/test/references/test-memory.md +2 -2
  81. package/src/codex/AGENTS.md +16 -24
  82. package/src/codex/hooks/lib/spec-receipt.cjs +57 -4
  83. package/src/codex/hooks/rules.cjs +27 -26
  84. package/src/codex/hooks/spec-gate.cjs +19 -8
  85. package/src/codex/hooks/spec-state.cjs +10 -1
  86. package/src/common/AGENTS.md +43 -0
  87. package/src/opencode/AGENTS.md +21 -121
  88. package/src/opencode/plugins/rules.ts +26 -34
  89. package/src/opencode/plugins/spec-gate.ts +283 -0
  90. package/src/claude/skills/inspect/references/external-gemini-inspection.md +0 -169
@@ -88,6 +88,22 @@ Forbidden generated artifacts:
88
88
  - Concise, prefer bullet lists; no fluff
89
89
  - Unresolved questions → list at the end of each document
90
90
 
91
+ ## Lane selection before spec gate
92
+
93
+ Classify task risk at the runtime boundary before starting spec state or approval flow. Use the executable policy, not keyword count or prose alone:
94
+
95
+ ```bash
96
+ node .claude/scripts/workflow-policy.cjs --classify-lane --task-json '<task JSON>' --json
97
+ # Downgrade from Critical requires explicit user authorization — model-supplied lane cannot bypass risk signals
98
+ node .claude/scripts/workflow-policy.cjs --classify-lane --task-json '{"riskSignals":{"auth":true},"override":"Direct","userAuthorized":true}' --json
99
+ ```
100
+
101
+ - **Direct** — clear, isolated, reversible, low-risk work. May skip spec files, registry/state, and subagents. Still run targeted verification, diff self-check, and evidence proportional to blast radius. No spec/state/registry ceremony required.
102
+ - **Standard** — default lane. Create one bounded spec artifact (`requirements.md` + `design.md` in the current layout), keep one canonical receipt, and run exactly one combined `code-auditor` review at feature ship point (not per-task).
103
+ - **Critical** — destructive/irreversible, auth/payment/privacy/data, schema/migration, public contract, cross-runtime coupling, outcome-changing ambiguity, or difficult rollback. Require strict spec/state/evidence; delegation is risk-driven (inspector/test-runner/code-auditor enabled only when risk lens requires), not a fixed four-agent chain.
104
+
105
+ Explicit `override` is allowed in either direction but is enforced at the runtime boundary. A model-supplied lane or downgrade must not bypass risk signals. Downgrading from Critical requires explicit user-originated authorization (`userAuthorized:true` or `origin:user`) and must surface the trade-off (reduced review/evidence coverage). Agent validation or --auto never fabricates `user_approved`; `generated`, `agent_validated`, and `user_approved` are independent booleans per `schema_version: "2.0"`.
106
+
91
107
  ## Default Behavior
92
108
 
93
109
  > **This section is the entry/dispatch layer ONLY.** It decides *which part of the pipeline to run and where to stop*. It does NOT change any pipeline step, the validator, templates, or rules.
@@ -112,15 +128,15 @@ Forbidden generated artifacts:
112
128
 
113
129
  ### Creation Mode Gate
114
130
 
115
- Shown once on the no-flag create path. Selects the **stop point only**.
131
+ Shown once on the no-flag create path. Selects the **stop point only**. Approval schema is versioned (`schema_version: "2.0"`): each phase has `generated`, `agent_validated`, `user_approved` as independent booleans. `ready` requires all three true. Legacy `approved` field is rejected — `--auto` or agent validation never fabricates `user_approved`.
116
132
 
117
- | Option | Runs | Stops after | Approvals |
133
+ | Option | Runs | Stops after | Approvals (v2) |
118
134
  |---|---|---|---|
119
- | **Auto (→ Tasks)** | Step 1→10 end-to-end | full (ready gate) | each phase `generated=true` + `approved=true` |
120
- | **Stop after Design** | Step 1→6 | `design` (before Step 7) | requirements + design `approved=true`; `ready_for_implementation=false` |
121
- | **Step by step** | one phase at a time | after each phase | per phase `generated=true`, `approved=false` until user approves |
135
+ | **Auto (→ Tasks)** | Step 1→10 end-to-end | full (ready gate) | each phase `generated=true` + `agent_validated=true`; `user_approved` stays false until explicit user approval (`--auto` does NOT auto-set `user_approved`). Ready requires `generated && agent_validated && user_approved`. |
136
+ | **Stop after Design** | Step 1→6 | `design` (before Step 7) | requirements + design `generated=true` + `agent_validated=true`; `user_approved=true` only after explicit user approval; later phases ungenerated; `ready_for_implementation=false` |
137
+ | **Step by step** | one phase at a time | after each phase | per phase `generated=true`, `agent_validated` per agent check, `user_approved=false` until user explicitly approves |
122
138
 
123
- `--auto` = Auto without the gate. Early stops leave `ready_for_implementation=false` and emit Step 9b. Resume via `/hapo:specs` Interactive State Discovery.
139
+ `--auto` = Auto without the gate. Early stops leave `ready_for_implementation=false` and emit Step 9b. Resume via `/hapo:specs` Interactive State Discovery. If legacy `approved` field is present, fail closed with migration guidance: replace `approved` with `agent_validated` + `user_approved` per `spec-state.json` template.
124
140
 
125
141
  ### Translation Mirror (optional reference copy)
126
142
 
@@ -210,16 +226,16 @@ Load: `references/scope-inquiry.md` (+ `references/ask-user-question-gates.md` f
210
226
  - Smell: >8 files / >2 new classes / >12 tasks → challenge; **>15 tasks → sibling specs**
211
227
  - User: Expand / Hold / Reduce. Skip if trivial (< 20 words, 1 file, "just do it")
212
228
 
213
- #### Execution Tier (auto-scale — after 5-Dimension assessment)
214
- Record in `spec.json.design_context.execution_tier`.
229
+ #### Execution Tier (auto-scale — after 5-Dimension assessment) — legacy metadata
230
+ Record in `spec.json.design_context.execution_tier` for backward compatibility. Tier is metadata only; **lane controls ceremony and delegation** (Direct/Standard/Critical). Light/Standard/Deep mappings are preserved for compatibility but lane policy is authoritative.
215
231
 
216
- | Tier | Trigger | Research | Discovery | Red-Team | Always runs |
232
+ | Tier (legacy) | Trigger | Research | Discovery | Red-Team | Always runs |
217
233
  |---|---|---|---|---|---|
218
234
  | **Light** | Clear + Isolated + ≤2 tasks | skip (rationale) | minimal | Validate-only | scope_lock, EARS, **Layer 1+2** |
219
235
  | **Standard** | default / 3-4 tasks | targeted | light | per Step 8 | all of the above |
220
236
  | **Deep** | Complex/Critical / security-migration / 5+ tasks | full | full | Red-Team → Validate | all of the above |
221
237
 
222
- Grounding + validator + scope_lock never skip. Auth/payment/migration/schema/privacy force Deep. Tier never changes Hard Output Contract or DoCT.
238
+ Grounding + validator + scope_lock never skip. Auth/payment/migration/schema/privacy force Deep (legacy) and Critical (lane). Tier remains backward-compatible execution metadata; lane controls ceremony and delegation.
223
239
 
224
240
  ### Step 4: Init
225
241
  - Check duplicate slugs; create `specs/<feature-name>/`
@@ -355,17 +371,18 @@ Early stop (**Stop after Design** / **Step by step**): no completion block, no v
355
371
 
356
372
  | Field | Rule |
357
373
  |---|---|
374
+ | `schema_version` | Must be `"2.0"`; approvals use `generated` + `agent_validated` + `user_approved` per phase. Legacy `approved` field is rejected — fail closed with migration guidance. |
358
375
  | Status | `in_progress` / `blocked` / `done` / `archived` only (never emit `in-progress`) |
359
376
  | Timestamps | Each `timestamps.*_done` = actual ISO 8601 time at that phase; never reuse init |
360
- | Approvals (Auto / full pipeline) | `generated=true` + `approved=true` per completed phase |
361
- | Approvals (Stop after Design) | phases that ran: both true; later phases ungenerated; `ready_for_implementation=false` |
362
- | Approvals (Step by step) | `generated=true`, `approved=false` until user approves |
377
+ | Approvals (Auto / full pipeline) | `generated=true` + `agent_validated=true`; `user_approved` stays false until explicit user approval (`--auto` never fabricates `user_approved`). Ready requires all three true per phase. |
378
+ | Approvals (Stop after Design) | phases that ran: `generated=true` + `agent_validated=true`; `user_approved=true` only after explicit user approval; later phases ungenerated; `ready_for_implementation=false` |
379
+ | Approvals (Step by step) | `generated=true`, `agent_validated` per agent check, `user_approved=false` until user explicitly approves |
363
380
  | `task_files` / `task_registry` | Exact match to disk after Step 7; registry keys = relative paths with full registry fields |
364
381
  | `validation_recommended` | `true` for auth/privacy/delete/migration/schema/extension/provider or 5+ tasks |
365
382
  | `translation` | optional mirror metadata; never affects ready gate |
366
- | `ready_for_implementation` | `true` only when requirements+design+tasks approved, `progress.tasks=done`, inventories match disk, and validation completed when recommended |
383
+ | `ready_for_implementation` | `true` only when requirements+design+tasks each have `generated && agent_validated && user_approved`, `progress.tasks=done`, inventories match disk, and validation completed when recommended |
367
384
 
368
- If any approval is `false`, keep `ready_for_implementation = false`. Specs with 5+ tasks stay not-ready until `--validate` writes `validation.status = "completed"`.
385
+ If any approval (`generated`, `agent_validated`, or `user_approved`) is `false`, keep `ready_for_implementation = false`. Specs with 5+ tasks stay not-ready until `--validate` writes `validation.status = "completed"`. Legacy `approved` fails closed — do not infer `user_approved` from `generated` or `agent_validated`.
369
386
 
370
387
  ## Subcommands
371
388
 
@@ -99,7 +99,7 @@ These rules override any self-reasoning or optimization the system may attempt:
99
99
  Each reviewer receives:
100
100
  - Their specific lens and persona
101
101
  - Spec file paths to read directly
102
- - Instructions: find 5-10 flaws, findings only, NO praise
102
+ - Instructions: report findings only when backed by concrete citations
103
103
 
104
104
  **Reviewer instructions:**
105
105
  ```
@@ -111,8 +111,8 @@ Rules:
111
111
  - Be concrete: describe failure scenario, not just "could be a problem"
112
112
  - Rate severity: Critical (blocks success) | High (significant risk) | Medium (notable concern)
113
113
  - Skip trivial observations (style, naming, formatting)
114
- - No praise. No "overall looks good". Only findings.
115
- - 5-10 findings. Quality over quantity.
114
+ - No praise. No "overall looks good". Only evidence-backed findings.
115
+ - Quality over quantity; do not pad to a count.
116
116
  ```
117
117
 
118
118
  #### Step 5: Collect → Deduplicate → Cap
@@ -32,7 +32,7 @@ Detail bullets must include:
32
32
  - API payloads, routes, and JSON contracts.
33
33
  - Edge cases, error handling, and exact validation thresholds (e.g., `Return 403 if invalid`).
34
34
 
35
- **Rationale**: Humans review tasks to verify business requirements are met; AI Coders (like god-developer or ck) read tasks to write explicit code. If you only write business jargon, the AI hallucinates. If you only write code names, the human reviewer cannot verify the business value. You MUST provide both.
35
+ **Rationale**: Humans review tasks to verify business requirements are met; AI Coders (like implementer or ck) read tasks to write explicit code. If you only write business jargon, the AI hallucinates. If you only write code names, the human reviewer cannot verify the business value. You MUST provide both.
36
36
 
37
37
  ### 2. Task Integration & Progression
38
38
 
@@ -1,4 +1,5 @@
1
1
  {
2
+ "schema_version": "2.0",
2
3
  "feature_name": "{{FEATURE_NAME}}",
3
4
  "created_at": "{{TIMESTAMP}}",
4
5
  "updated_at": "{{TIMESTAMP}}",
@@ -12,15 +13,18 @@
12
13
  "approvals": {
13
14
  "requirements": {
14
15
  "generated": false,
15
- "approved": false
16
+ "agent_validated": false,
17
+ "user_approved": false
16
18
  },
17
19
  "design": {
18
20
  "generated": false,
19
- "approved": false
21
+ "agent_validated": false,
22
+ "user_approved": false
20
23
  },
21
24
  "tasks": {
22
25
  "generated": false,
23
- "approved": false
26
+ "agent_validated": false,
27
+ "user_approved": false
24
28
  }
25
29
  },
26
30
  "scope_lock": {
@@ -14,8 +14,21 @@ metadata:
14
14
 
15
15
  This skill safely bridges the gap between active development state and physical documentation files (`spec.json` + `task_registry` + `tasks/task-R*.md`). Instead of relying on risky raw AI edits, this skill executes precise contextual replacements.
16
16
 
17
- ## Supported Commands
17
+ ## Lane-aware synchronization
18
+
19
+ Read lane policy before mutating state:
20
+
21
+ ```bash
22
+ node .claude/scripts/workflow-policy.cjs --classify-lane --task-json '<task JSON>' --json
23
+ ```
18
24
 
25
+ - Direct may have no spec/state/registry; sync only concrete targeted evidence and never invents approval state.
26
+ - Standard stores one bounded spec and one canonical feature receipt; one combined `code-auditor` review gates feature closeout.
27
+ - Critical requires strict durable evidence and `inspector → implementer → test-runner → code-auditor` delegation by default.
28
+ - `generated`, `agent_validated`, and `user_approved` are independent. Missing `user_approved` stays false; sync never auto-approves user-owned state.
29
+ - Explicit lane overrides must preserve automatic classification and warning in receipt/state output, especially Critical downgrades.
30
+
31
+ ## Supported Commands
19
32
  ### 1. Task Synchronization
20
33
  Update a specific task's status and automatically check its relevant sub-checkboxes.
21
34
 
@@ -44,5 +57,17 @@ Scans the `spec.json` against all physical `task-R*.md` files to detect mismatch
44
57
  5. **Task Docs Hook:** Every time `hapo:sync` marks a task as `done`, it must flag that a task-level docs checkpoint is now due for that verified task.
45
58
  6. **Phase Prompt Rule:** When `hapo:sync` marks the final pending task in the whole feature as `done`, it should automatically prompt the user if they'd like to advance the phase, but only after the docs checkpoint for that last completed task has been considered.
46
59
 
60
+ ### 4. Explicit Flash Finalization
61
+
62
+ **Usage:** `/hapo:sync <feature_name> <task_id|task-file> sync-finalize`
63
+
64
+ This is the only operation allowed to turn a flash-promoted task (`Verification: PASS`, `status: in_progress`, `readyForSync: true`) into `done` and unblock dependencies. A normal `done` request cannot bypass flash promotion or stale `FLASH_UNVERIFIED` state.
65
+
66
+ ### Flash implementation state
67
+
68
+ Executable policy source: `.claude/scripts/workflow-policy.cjs` (source: `src/claude/scripts/workflow-policy.cjs`). Use `promoteFlashTask` only after exact task Evidence and reachability return PASS; FAIL, BLOCKED, and NO_TESTS remain blocked in progress.
69
+
70
+ `FLASH_UNVERIFIED` is storage for implemented-but-unverified work, not a completion status. Store it as `status: "in_progress"` with blocker `awaiting /hapo:test <feature>`; do not unblock dependencies. `/hapo:test` may promote one task only after its exact Evidence and reachability PASS, replacing the receipt with proof, clearing blocker, and setting `readyForSync: true` while dependencies remain blocked. Only explicit `/hapo:sync ... sync-finalize` may set `done` and unblock. FAIL, BLOCKED, and NO_TESTS remain `in_progress`.
71
+
47
72
  ## References
48
73
  Read `references/sync-protocols.md` for exact Search/Replace regex patterns and JSON schema expectations before acting on the files.
@@ -2,11 +2,11 @@
2
2
 
3
3
  The following guidelines dictate exactly how `hapo:sync` should interact with files to prevent data corruption.
4
4
 
5
- **Canonical task status vocabulary:** `pending`, `in_progress`, `blocked`, `done`
5
+ **Flash implementation state:** `FLASH_UNVERIFIED` MUST remain `status: "in_progress"` with blocker `awaiting /hapo:test <feature>`. It never unblocks dependencies. A task-scoped `/hapo:test` PASS replaces receipt with real `Verification: PASS`, clears blocker, and sets `readyForSync: true` while dependency blocking remains. Only explicit `/hapo:sync ... sync-finalize` may set `done` and unblock; FAIL, BLOCKED, and NO_TESTS stay `in_progress`.
6
6
 
7
- ## 1. Updating `spec.json`
7
+ **Lane state rule:** classify Direct/Standard/Critical before sync. Direct may omit spec/state/registry for clear, reversible low-risk work; Standard uses one bounded spec and one feature receipt; Critical requires strict durable evidence. Explicit overrides must retain automatic lane, risk signals, and warning. `generated`, `agent_validated`, and `user_approved` are independent booleans; never infer or write `user_approved: true` from agent fields.
8
8
 
9
- When requested to update a phase or change task configuration, `spec.json` must maintain its strict schema (defined in `hapo:specs/templates/spec-state.json`).
9
+ ## 1. Updating `spec.json`
10
10
 
11
11
  * **JSON Modification Rule:** Do not output whole files. Instead, load the JSON structure, apply the update to `status`, `current_phase`, `blocker` (if any), `task_files`, and the relevant `task_registry` entry, then overwrite the file cleanly.
12
12
  * **Task Registry Rule:** Resolve the incoming task reference to a single relative path in `task_registry`. Accept either:
@@ -43,9 +43,17 @@ When a feature name or `specs/<feature>` path is supplied, testing is spec-aware
43
43
  Load `spec.json`, `requirements.md`, `design.md`, active/recent task files, and task `Evidence` / test-plan proof.
44
44
  The verdict MUST compare executed/reachable behavior against `scope_lock`, requirements, design contracts, task Completion Criteria, and runtime reachability obligations.
45
45
  Build/typecheck success without scoped runtime proof is not PASS.
46
- </SCOPE-GATE>
46
+ ## Flash promotion contract
47
+
48
+ Executable policy source: `.claude/scripts/workflow-policy.cjs` (source: `src/claude/scripts/workflow-policy.cjs`). Its `consumeReviewVerdict` and `promoteFlashTask` functions are sole source for PASS/FAIL/BLOCKED handling and task-scoped promotion.
49
+
50
+ When `/hapo:test <feature>` finds a task with `status: "in_progress"` and receipt `FLASH_UNVERIFIED`, evaluate that task's exact Evidence and runtime reachability only:
51
+
52
+ - PASS → replace receipt with concrete proof while keeping `status: "in_progress"`, `dependencyBlocked: true`, `unblocks: false`, and `readyForSync: true`; only explicit `/hapo:sync ... sync-finalize` may set `done` and unblock dependents.
53
+ - FAIL, BLOCKED, or NO_TESTS → keep `status: "in_progress"`, keep or update blocker, and do not promote any other flash task.
54
+ - Never blanket-promote every flash task in a feature because one task passed.
55
+
47
56
 
48
- ## 4-Phase Execution
49
57
 
50
58
  ```mermaid
51
59
  flowchart TD
@@ -153,7 +161,7 @@ Return a **structured verdict** (required format — not free-form prose):
153
161
 
154
162
  ### Action
155
163
  - PASS → Proceed. Hand off to hapo:code-review.
156
- - FAIL → [list specific fixes needed] → Return to god-developer. (If REGRESSION: label "Test Regression — tests were deleted or weakened to produce green result")
164
+ - FAIL → [list specific fixes needed] → Return to implementer. (If REGRESSION: label "Test Regression — tests were deleted or weakened to produce green result")
157
165
  - PARTIAL → [list uncovered areas] → Consider adding tests.
158
166
  - NO_TESTS → No test runner detected. User must configure tests first.
159
167
 
@@ -176,7 +184,7 @@ It merges the JSON data into `.hapo/test-memory.json` per `references/test-memor
176
184
  | `hapo:code-review` | runs in parallel | Both run at Quality Gate Step 4 |
177
185
  | `hapo:develop` | orchestrates | Spawns hapo:test at Step 4 |
178
186
  | `inspector` agent | hapo:test → | Scout test file locations when structure is unfamiliar |
179
- | `god-developer` agent | hapo:test → | FAIL verdicts route back here for fixing |
187
+ | `implementer` agent | hapo:test → | FAIL verdicts route back here for fixing |
180
188
  | `test-runner` agent | hapo:test → | Primary executor, spawned via the `Agent` tool |
181
189
  | chrome-devtools scripts | test-runner → | UI verification (navigate, screenshot, console, network, performance, aria-snapshot, inject-auth) |
182
190
 
@@ -35,21 +35,21 @@ Failure detected
35
35
  ├─ Compile Error (#1)
36
36
  │ → STOP immediately. Do NOT run further tests.
37
37
  │ → Report: file, line, error message.
38
- │ → Action: return to god-developer. Fix compile errors first.
38
+ │ → Action: return to implementer. Fix compile errors first.
39
39
  │
40
40
  ├─ Logic Error (#2)
41
41
  │ → Report: test name, file:line, expected value, actual value.
42
- │ → Action: return to god-developer with precise location.
42
+ │ → Action: return to implementer with precise location.
43
43
  │ → Do NOT modify test to make it pass.
44
44
  │
45
45
  ├─ Environment Error (#3)
46
46
  │ → Report: which service/env var is missing.
47
- │ → Action: escalate to USER (not god-developer).
47
+ │ → Action: escalate to USER (not implementer).
48
48
  │ "Environment issue: [DB/service] not reachable. Please start it."
49
49
  │
50
50
  ├─ Flaky Test (#4)
51
51
  │ → Report: test name + "intermittent failure observed".
52
- │ → Action: flag for god-developer review.
52
+ │ → Action: flag for implementer review.
53
53
  │ Likely cause: shared state, async timing, or test ordering.
54
54
  │
55
55
  ├─ Coverage Gap (#5)
@@ -59,17 +59,17 @@ Failure detected
59
59
  │
60
60
  ├─ Build Error (#6)
61
61
  │ → Report: build command, error output (last 20 lines).
62
- │ → Action: return to god-developer.
62
+ │ → Action: return to implementer.
63
63
  │
64
64
  ├─ UI Console Error (#7)
65
65
  │ → Report: error message, source file, line number.
66
- │ → Action: return to god-developer if JS error.
66
+ │ → Action: return to implementer if JS error.
67
67
  │ If external script error: flag as warning only.
68
68
  │
69
69
  ├─ UI Network Error (#8)
70
70
  │ → Report: endpoint URL, status code, response body excerpt.
71
- │ → Action: 404 → god-developer (missing route/resource).
72
- │ 500 → god-developer (server error). 401/403 → auth issue (user).
71
+ │ → Action: 404 → implementer (missing route/resource).
72
+ │ 500 → implementer (server error). 401/403 → auth issue (user).
73
73
  │
74
74
  ├─ UI Performance (#9)
75
75
  │ → Report: specific metric name + actual value + threshold.
@@ -77,27 +77,27 @@ Failure detected
77
77
  │
78
78
  ├─ Accessibility Error (#10)
79
79
  │ → Report: element role + missing attribute.
80
- │ → Action: return to god-developer. Add aria-label / alt / for attributes.
80
+ │ → Action: return to implementer. Add aria-label / alt / for attributes.
81
81
  │
82
82
  ├─ User Flow Error (#11)
83
83
  │ → Report: step failed (e.g., login submit), expected vs actual URL/state.
84
- │ → Action: return to god-developer to fix E2E UI flow.
84
+ │ → Action: return to implementer to fix E2E UI flow.
85
85
  │
86
86
  ├─ SEO Error (#12)
87
87
  │ → Report: missing tag or invalid setup (e.g., no H1, bad canonical).
88
- │ → Action: return to god-developer. Add missing HTML meta tags.
88
+ │ → Action: return to implementer. Add missing HTML meta tags.
89
89
  │
90
90
  ├─ Security Warning (#13)
91
91
  │ → Report: missing header names or exposed secret pattern.
92
- │ → Action: return to god-developer. Add helmet/headers or remove secrets.
92
+ │ → Action: return to implementer. Add helmet/headers or remove secrets.
93
93
  │
94
94
  ├─ Broken Links (#14)
95
95
  │ → Report: crawler source URL → broken target URL (404).
96
- │ → Action: return to god-developer to fix href paths.
96
+ │ → Action: return to implementer to fix href paths.
97
97
  │
98
98
  └─ UI Visual Error (#15)
99
99
  → Report: AI parsed visual issue (e.g., button overlapping text).
100
- → Action: return to god-developer to fix CSS/layout issues.
100
+ → Action: return to implementer to fix CSS/layout issues.
101
101
  ```
102
102
 
103
103
  ---
@@ -107,11 +107,11 @@ Failure detected
107
107
  | Failure count | Verdict | Action |
108
108
  |---|---|---|
109
109
  | 0 failures | **PASS** | Proceed to hapo:code-review |
110
- | 1–2 failures | **FAIL** | Return to god-developer with targeted fix list |
111
- | 3–10 failures | **FAIL** | Return to god-developer, flag as "significant failures" |
110
+ | 1–2 failures | **FAIL** | Return to implementer with targeted fix list |
111
+ | 3–10 failures | **FAIL** | Return to implementer, flag as "significant failures" |
112
112
  | > 10 failures OR 0 tests pass | **COLLAPSE** | Call `AskUserQuestion`: "Test suite critically broken. User intervention required." |
113
113
  | Only coverage gaps | **PARTIAL** | Proceed to hapo:code-review, attach coverage gap list |
114
- | Environment errors only | **BLOCKED** | Escalate to user (not god-developer) |
114
+ | Environment errors only | **BLOCKED** | Escalate to user (not implementer) |
115
115
 
116
116
  ---
117
117
 
@@ -19,7 +19,7 @@ If the file does not exist, the `hapo:test` skill (or the orchestrator) MUST cre
19
19
  The `test-runner` agent is Read-Only. At Phase 1, it must read `.hapo/test-memory.json` (if it exists) to factor into its testing process:
20
20
  - **`env_setup_commands`**: Commands that must be run before tests (e.g. `docker compose up -d redis`). If listed, flag missing dependencies instead of immediate failure.
21
21
  - **`flaky_tests`**: Array of test file paths. If a failure occurs in one of these files, the verdict should explicitly note `(Known Flaky Test)`.
22
- - **`known_issues`**: Issues that god-developer or user marked as ignored.
22
+ - **`known_issues`**: Issues that implementer or user marked as ignored.
23
23
 
24
24
  ## Writing to Memory
25
25
 
@@ -28,7 +28,7 @@ Because `test-runner` is restricted from editing files, it cannot update the mem
28
28
  Example:
29
29
  ```markdown
30
30
  ### Action
31
- → [FAIL] Return to god-developer: Fix CSS layout offset.
31
+ → [FAIL] Return to implementer: Fix CSS layout offset.
32
32
 
33
33
  <lessons_learned>
34
34
  {
@@ -1,30 +1,22 @@
1
- # CafeKit for Codex CLI
1
+ ## Codex runtime
2
2
 
3
- ## Native runtime mapping
3
+ - Repository instructions live in `AGENTS.md`.
4
+ - CafeKit skills live in `.agents/skills/`; invoke them as `$hapo-<name>` or browse with `/skills`. Edit skills in the project, not in a global skills directory.
5
+ - Run Python skill scripts with the project venv:
6
+ - macOS/Linux: `.agents/skills/.venv/bin/python3 scripts/<script>.py`
7
+ - Windows: `.agents\\skills\\.venv\\Scripts\\python.exe scripts\\<script>.py`
8
+ - CafeKit agents live in `.codex/agents/*.toml` and are auto-discovered after the repository is trusted.
9
+ - Runtime support lives in `.codex/rules/`, `.codex/scripts/`, `.codex/references/`, and `.codex/runtime.json`.
10
+ - Project hooks live in `.codex/hooks.json`; review trusted hooks with `/hooks`.
4
11
 
5
- - Repository instructions: `AGENTS.md`.
6
- - CafeKit skills: `.agents/skills/`; invoke explicitly as `$hapo-<name>` or browse with `/skills`.
7
- - CafeKit agents: native auto-discovered definitions in `.codex/agents/*.toml`.
8
- - Runtime support: `.codex/rules/`, `.codex/scripts/`, `.codex/references/`, and `.codex/runtime.json`.
9
- - Lifecycle enforcement: `.codex/hooks.json`. Project hooks run only after the repository and hook definitions are trusted; review them with `/hooks`.
10
- - Do not create deprecated custom prompts or assume Claude/OpenCode command wrappers exist.
12
+ ## Codex caveats
11
13
 
12
- ## Operating contract
14
+ - Custom agents use snake_case names and `fork_turns: "none"` for explicit delegation.
15
+ - Use Codex-native subagent delegation and task-state tools; do not rely on Claude-only tool labels.
16
+ - Do not edit global trust configuration. Hooks are not a complete security boundary; hosted tools and untrusted project hooks can bypass the local hook path.
13
17
 
14
- - Read `README.md` and relevant project instructions before non-trivial work.
15
- - Choose the matching CafeKit skill before improvising a workflow.
16
- - Read `.codex/rules/workflow.md`, `.codex/rules/ai-dev-rules.md`, and
17
- `.codex/rules/skill-workflow-routing.md` for non-trivial work. Load the other
18
- `.codex/rules/*.md` files when their topic applies.
19
- - Keep scope surgical; prefer YAGNI, KISS, then DRY.
20
- - Do not claim completion without fresh build, test, runtime, or artifact evidence.
21
- - For spec tasks, keep `spec.json`, task status, `Completion Criteria`, and `Evidence` synchronized only after verification.
22
- - Privacy approvals are one request, one session, one retry. Only the user may submit the exact approval phrase emitted by the privacy hook.
18
+ ## Combined-install boundary
23
19
 
24
- ## Runtime caveats
20
+ Codex's native project instruction surface is root `AGENTS.md`. Combined installs keep this Codex block there because no separate Codex project entrypoint is configured by CafeKit. Other runtimes may read the same root file; this shared-root trade-off is intentional and must not be treated as filesystem isolation.
25
21
 
26
- - Codex custom agents use snake_case names.
27
- - When selecting a CafeKit custom role explicitly, call `spawn_agent` with `agent_type`, a unique snake_case `task_name`, `message`, and `fork_turns: "none"`. A full-history fork cannot change agent type.
28
- - Use Codex-native subagent delegation and task-state tools; do not rely on Claude-only tool labels.
29
- - The project `.codex/` layer—agents, config, rules, and hooks—loads only after the repository is trusted. Never edit the user's global trust configuration on their behalf.
30
- - Hooks are guardrails, not a complete security boundary. Hosted tools and untrusted project hooks may not enter the local hook path.
22
+ **Ownership / ignore contract (fail-safe):** This Codex block is owned by Codex CLI only. If you are Claude Code, OpenCode, or any other runtime, ignore this entire Codex block and consume only CORE plus your native block. If you cannot determine which block is yours, treat the file as CORE-only. Do not treat another runtime's block as instructions.
@@ -39,9 +39,32 @@ function evidenceBody(text) {
39
39
  function safeTaskFile(featureDir, taskPath) {
40
40
  const target = path.resolve(featureDir, taskPath);
41
41
  const relative = path.relative(featureDir, target);
42
- return !relative.startsWith('..') && !path.isAbsolute(relative)
43
- ? target
44
- : null;
42
+ if (relative === '..' || relative.startsWith(`..${path.sep}`) || path.isAbsolute(relative)) return null;
43
+ return target;
44
+ }
45
+
46
+ function validateCanonicalReceipt(body) {
47
+ const failures = [];
48
+ if (!/^\s*Verification:\s*PASS\s*$/m.test(body)) {
49
+ failures.push('verification_state');
50
+ }
51
+ if (!/^\s*Command(?:\(s\))?\s*:/m.test(body)) {
52
+ failures.push('command');
53
+ }
54
+ if (!/^\s*Exit\s*:|exit\s+code\s*[:=]|\bResult\s*:\s*PASS\b/im.test(body)) {
55
+ failures.push('exit_result');
56
+ }
57
+ const hasBase = /^\s*Base[ \t]*:[ \t]*\S/im.test(body);
58
+ const hasHead = /^\s*Head[ \t]*:[ \t]*\S/im.test(body);
59
+ const hasBaseSha = /\bbase_sha[ \t]*:[ \t]*\S/im.test(body);
60
+ const hasHeadSha = /\bhead_sha[ \t]*:[ \t]*\S/im.test(body);
61
+ if (!((hasBase && hasHead) || (hasBaseSha && hasHeadSha))) {
62
+ failures.push('provenance');
63
+ }
64
+ if (/\bartifact\b/i.test(body) && !/sha256:/i.test(body)) {
65
+ failures.push('artifact_hash');
66
+ }
67
+ return failures;
45
68
  }
46
69
 
47
70
  function checkReceipt(featureDir, taskPath, task) {
@@ -64,6 +87,36 @@ function checkReceipt(featureDir, taskPath, task) {
64
87
  || !(PASS_MARKER.test(body) || LEGACY_SUCCESS.test(body))
65
88
  ) {
66
89
  failures.push('c');
90
+ } else {
91
+ // Canonical receipt requirements: command, exit/result, provenance, unambiguous PASS
92
+ // For done tasks, require canonical fields. If missing, add e/f/g.
93
+ const canonical = validateCanonicalReceipt(body);
94
+ // Map canonical failures to letters e,f,g,h for backward compat checks
95
+ // Use detailed names but also add letters for gate reporting
96
+ const map = {
97
+ verification_state: 'c', // already covers but keep distinct
98
+ command: 'e',
99
+ exit_result: 'f',
100
+ provenance: 'g',
101
+ artifact_hash: 'h',
102
+ };
103
+ for (const fail of canonical) {
104
+ const letter = map[fail];
105
+ // Avoid duplicating c if already failed, but add specific
106
+ if (fail === 'verification_state' && failures.includes('c')) continue;
107
+ if (fail === 'verification_state') {
108
+ // This should have been caught by c, but if PASS present via legacy, still need strict PASS
109
+ if (!PASS_MARKER.test(body)) failures.push('c');
110
+ continue;
111
+ }
112
+ if (letter && !failures.includes(letter)) failures.push(letter);
113
+ }
114
+ // Additional strict check: legacy success alone is not sufficient for canonical
115
+ // If body contains only legacy PASS but not canonical Verification: PASS, c already would have caught if no PASS_MARKER?
116
+ // But we allow legacy for backward compat in c, but canonical requires PASS_MARKER, so we must enforce.
117
+ if (!PASS_MARKER.test(body)) {
118
+ if (!failures.includes('c')) failures.push('c');
119
+ }
67
120
  }
68
121
 
69
122
  const completedAt = task?.completed_at;
@@ -75,4 +128,4 @@ function checkReceipt(featureDir, taskPath, task) {
75
128
  return failures;
76
129
  }
77
130
 
78
- module.exports = { checkReceipt };
131
+ module.exports = { checkReceipt, evidenceBody, safeTaskFile, validateCanonicalReceipt };
@@ -1,20 +1,16 @@
1
- #!/usr/bin/env node
2
1
  'use strict';
3
2
 
4
3
  const crypto = require('crypto');
5
4
  const fs = require('fs');
6
5
  const path = require('path');
7
6
  const {
8
- atomicWrite,
9
7
  getHookContext,
10
8
  logCrash,
11
9
  readPayload,
12
10
  resolveProjectPath
13
11
  } = require('./lib/hook-context.cjs');
14
12
 
15
- const COOLDOWN_MS = 5 * 60 * 1000;
16
-
17
- function cooldownFile(projectRoot, sessionId) {
13
+ function reservationFile(projectRoot, sessionId) {
18
14
  const key = crypto.createHash('sha256')
19
15
  .update(String(sessionId || 'unknown'))
20
16
  .digest('hex')
@@ -22,21 +18,39 @@ function cooldownFile(projectRoot, sessionId) {
22
18
  return path.join(projectRoot, '.codex', 'hooks', '.logs', `rules-${key}.json`);
23
19
  }
24
20
 
25
- function recentlyInjected(file) {
21
+ /** Reserve one injection slot per session. Returns null on reservation errors. */
22
+ function reserveSession(projectRoot, sessionId) {
23
+ if (!sessionId) return null;
24
+ try {
25
+ const file = reservationFile(projectRoot, sessionId);
26
+ fs.mkdirSync(path.dirname(file), { recursive: true });
27
+ fs.writeFileSync(file, JSON.stringify({ sessionId: String(sessionId) }), {
28
+ encoding: 'utf8',
29
+ flag: 'wx',
30
+ mode: 0o600
31
+ });
32
+ return true;
33
+ } catch (error) {
34
+ return error.code === 'EEXIST' ? false : null;
35
+ }
36
+ }
37
+
38
+ function readRuntime(projectRoot) {
26
39
  try {
27
- const state = JSON.parse(fs.readFileSync(file, 'utf8'));
28
- return Date.now() - Number(state.ts || 0) < COOLDOWN_MS;
40
+ const file = path.join(projectRoot, '.codex', 'runtime.json');
41
+ return fs.existsSync(file) ? JSON.parse(fs.readFileSync(file, 'utf8')) : null;
29
42
  } catch {
30
- return false;
43
+ return null;
31
44
  }
32
45
  }
33
46
 
34
47
  try {
35
48
  const payload = readPayload();
36
49
  if (!payload) process.exit(0);
37
- const { projectRoot, runtime } = getHookContext(payload);
38
- const cache = cooldownFile(projectRoot, payload.session_id);
39
- if (recentlyInjected(cache)) process.exit(0);
50
+ const { projectRoot } = getHookContext(payload);
51
+ if (reserveSession(projectRoot, payload.session_id) !== true) process.exit(0);
52
+ const runtime = readRuntime(projectRoot);
53
+ if (runtime === null) process.exit(0);
40
54
 
41
55
  const respondLang = runtime.locale?.responseLanguage || '';
42
56
  const thinkLang = runtime.locale?.thinkingLanguage || (respondLang ? 'en' : '');
@@ -57,23 +71,10 @@ try {
57
71
  '## Rules',
58
72
  `- Markdown: Plans → "${plansPath}/" | Docs → "${docsPath}/"`,
59
73
  '- Do not create markdown outside those directories unless explicitly asked.',
60
- `- docs.maxLoc: ${runtime.docs?.maxLoc || 800} lines per doc file`,
61
- '- Follow YAGNI · KISS · DRY.',
62
- '- Reports: concise; unresolved questions last.',
63
- '',
64
- '## Skill Routing',
65
- '- Choose skills using `.codex/rules/skill-workflow-routing.md` and `.codex/rules/skill-domain-routing.md`.',
66
- '- Inspect installed skills with `node .codex/scripts/generate-skill-catalog.cjs --skills` when needed.',
67
- '- Explicit user requests override routing suggestions.',
68
- '',
69
- '## Modularization',
70
- '- Consider splitting code files over 200 lines at real concern boundaries.',
71
- '- Check existing modules first; use descriptive names and comments.',
72
- '- Skip modularization for markdown, plain text, shell, config, and env files.'
74
+ `- docs.maxLoc: ${runtime.docs?.maxLoc || 800} lines per doc file`
73
75
  );
74
76
 
75
77
  process.stdout.write(`${lines.join('\n')}\n`);
76
- atomicWrite(cache, `${JSON.stringify({ ts: Date.now() })}\n`);
77
78
  } catch (error) {
78
79
  logCrash('rules', error);
79
80
  }
@@ -11,6 +11,10 @@ const {
11
11
  } = require('./lib/hook-context.cjs');
12
12
  const { checkReceipt } = require('./lib/spec-receipt.cjs');
13
13
  const { findActiveSpec, taskStatusMap } = require('./lib/spec-utils.cjs');
14
+ const policyPath = path.join(__dirname, '..', 'scripts', 'workflow-policy.cjs');
15
+ const POLICY = require(fs.existsSync(policyPath)
16
+ ? policyPath
17
+ : path.join(__dirname, '../../claude/scripts/workflow-policy.cjs'));
14
18
 
15
19
  try {
16
20
  const payload = readPayload();
@@ -35,18 +39,25 @@ try {
35
39
  try { cache = JSON.parse(fs.readFileSync(cacheFile, 'utf8')); } catch { cache = {}; }
36
40
  }
37
41
 
38
- if (!cacheExists) {
39
- cache[active.featureName] = currentStatuses;
40
- atomicWrite(cacheFile, `${JSON.stringify(cache)}\n`);
42
+ // Cache hardening: revalidate every done task on every Stop so a
43
+ // cached PASS cannot hide later receipt/provenance mutations.
44
+ // Cache is optimization only - validate every done task even on first run.
45
+ const previous = cacheExists ? (cache[active.featureName] || {}) : {};
46
+ const staleFlashTasks = Object.entries(registry)
47
+ .filter(([, task]) => POLICY.isStaleFlashDone(task))
48
+ .map(([taskPath]) => taskPath);
49
+ if (staleFlashTasks.length > 0) {
50
+ process.stdout.write(`${JSON.stringify({
51
+ decision: 'block',
52
+ reason: `Completion gate: ${staleFlashTasks.length} task(s) marked done with FLASH_UNVERIFIED (${staleFlashTasks.join(', ')}). Run /hapo:test, then use explicit sync-finalize.`
53
+ })}\n`);
41
54
  process.exit(0);
42
55
  }
43
-
44
- const previous = cache[active.featureName] || {};
45
- const newlyDone = Object.keys(registry).filter((taskPath) => (
46
- currentStatuses[taskPath] === 'done' && previous[taskPath] !== 'done'
56
+ const allDoneTasks = Object.keys(registry).filter((taskPath) => (
57
+ currentStatuses[taskPath] === 'done'
47
58
  ));
48
59
  const featureDir = path.join(active.specsDir, active.featureName);
49
- const failures = newlyDone
60
+ const failures = allDoneTasks
50
61
  .map((taskPath) => ({
51
62
  taskPath,
52
63
  failures: checkReceipt(featureDir, taskPath, registry[taskPath])