@mrciphersmith/keryx 0.2.98 → 0.2.99

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 (182) hide show
  1. package/dist/cli.js +4057 -2510
  2. package/dist/core.js +39 -1
  3. package/package.json +1 -1
  4. package/src/gdskills/bundled/rules/core/cli-interface-design.mdc +237 -0
  5. package/src/gdskills/bundled/rules/core/definition-of-done.mdc +116 -0
  6. package/src/gdskills/bundled/rules/core/skills-storage-workflow.mdc +101 -11
  7. package/src/gdskills/bundled/rules/core/subagent-status-protocol.md +9 -2
  8. package/src/gdskills/bundled/skills/core/reviewer-skill-creator/SKILL.md +42 -5
  9. package/src/gdskills/bundled/skills/orchestration/code-verifier/SKILL.md +19 -3
  10. package/src/gdskills/bundled/skills/orchestration/context-collector/SKILL.md +20 -4
  11. package/src/gdskills/bundled/skills/orchestration/feature-analyzer/SKILL.md +32 -9
  12. package/src/gdskills/bundled/skills/orchestration/feature-dev/SKILL.md +18 -4
  13. package/src/gdskills/bundled/skills/orchestration/flow-orchestrator/SKILL.md +21 -5
  14. package/src/gdskills/bundled/skills/orchestration/issue-analyzer/SKILL.md +4 -4
  15. package/src/gdskills/bundled/skills/orchestration/issue-analyzer/orchestrator-prompt.md +1 -1
  16. package/src/gdskills/bundled/skills/orchestration/job-documenter/SKILL.md +42 -2
  17. package/src/gdskills/bundled/skills/orchestration/job-orchestrator/SKILL.md +23 -9
  18. package/src/gdskills/bundled/skills/orchestration/task-implementer/SKILL.md +33 -31
  19. package/src/gdskills/bundled/skills/orchestration/task-implementer/output-contract.schema.json +32 -1
  20. package/src/gdskills/bundled/skills/planning/autodoc-analyst/SKILL.md +16 -0
  21. package/src/gdskills/bundled/skills/planning/autodoc-architect/SKILL.md +16 -0
  22. package/src/gdskills/bundled/skills/planning/autodoc-assembler/SKILL.md +16 -0
  23. package/src/gdskills/bundled/skills/planning/autodoc-orchestrator/SKILL.md +17 -0
  24. package/src/gdskills/bundled/skills/planning/autodoc-scanner/SKILL.md +16 -0
  25. package/src/gdskills/bundled/skills/planning/autodoc-writer/SKILL.md +16 -0
  26. package/src/gdskills/bundled/skills/planning/brainstorm/SKILL.md +28 -3
  27. package/src/gdskills/bundled/skills/planning/consistency-checker/SKILL.codex.md +17 -0
  28. package/src/gdskills/bundled/skills/planning/consistency-checker/SKILL.cursor.md +17 -0
  29. package/src/gdskills/bundled/skills/planning/consistency-checker/SKILL.md +17 -0
  30. package/src/gdskills/bundled/skills/planning/docpack-orchestrator/SKILL.md +32 -2
  31. package/src/gdskills/bundled/skills/planning/docpack-review/SKILL.md +14 -2
  32. package/src/gdskills/bundled/skills/planning/interview/SKILL.md +29 -7
  33. package/src/gdskills/bundled/skills/planning/interviewer/SKILL.md +32 -6
  34. package/src/gdskills/bundled/skills/planning/patterns-researcher/SKILL.codex.md +16 -0
  35. package/src/gdskills/bundled/skills/planning/patterns-researcher/SKILL.cursor.md +16 -0
  36. package/src/gdskills/bundled/skills/planning/patterns-researcher/SKILL.md +16 -0
  37. package/src/gdskills/bundled/skills/planning/planner/SKILL.codex.md +17 -0
  38. package/src/gdskills/bundled/skills/planning/planner/SKILL.cursor.md +17 -0
  39. package/src/gdskills/bundled/skills/planning/planner/SKILL.md +17 -0
  40. package/src/gdskills/bundled/skills/planning/prd-creator/SKILL.md +20 -3
  41. package/src/gdskills/bundled/skills/planning/problem-definer/SKILL.codex.md +16 -0
  42. package/src/gdskills/bundled/skills/planning/problem-definer/SKILL.cursor.md +16 -0
  43. package/src/gdskills/bundled/skills/planning/problem-definer/SKILL.md +16 -0
  44. package/src/gdskills/bundled/skills/planning/project-discovery/SKILL.codex.md +16 -0
  45. package/src/gdskills/bundled/skills/planning/project-discovery/SKILL.cursor.md +16 -0
  46. package/src/gdskills/bundled/skills/planning/project-discovery/SKILL.md +16 -0
  47. package/src/gdskills/bundled/skills/planning/spec-writer/SKILL.codex.md +4 -0
  48. package/src/gdskills/bundled/skills/planning/spec-writer/SKILL.cursor.md +4 -0
  49. package/src/gdskills/bundled/skills/planning/spec-writer/SKILL.md +4 -0
  50. package/src/gdskills/bundled/skills/planning/stack-advisor/SKILL.codex.md +4 -0
  51. package/src/gdskills/bundled/skills/planning/stack-advisor/SKILL.cursor.md +4 -0
  52. package/src/gdskills/bundled/skills/planning/stack-advisor/SKILL.md +4 -0
  53. package/src/gdskills/bundled/skills/platform/agent-entrypoint-distiller/SKILL.md +31 -4
  54. package/src/gdskills/bundled/skills/platform/claude-md-management/SKILL.md +26 -2
  55. package/src/gdskills/bundled/skills/platform/hookify/SKILL.md +28 -3
  56. package/src/gdskills/bundled/skills/quality/api-truth/SKILL.md +226 -0
  57. package/src/gdskills/bundled/skills/quality/changelog/SKILL.md +24 -4
  58. package/src/gdskills/bundled/skills/quality/commit/SKILL.md +24 -3
  59. package/src/gdskills/bundled/skills/quality/db-migrate/SKILL.md +24 -3
  60. package/src/gdskills/bundled/skills/quality/dependency-update/SKILL.md +25 -4
  61. package/src/gdskills/bundled/skills/quality/deploy/SKILL.md +26 -3
  62. package/src/gdskills/bundled/skills/quality/deprecation-path/SKILL.md +268 -0
  63. package/src/gdskills/bundled/skills/quality/fresh-eyes/SKILL.md +190 -0
  64. package/src/gdskills/bundled/skills/quality/metaproject-security/SKILL.md +24 -3
  65. package/src/gdskills/bundled/skills/quality/perf-check/SKILL.md +29 -8
  66. package/src/gdskills/bundled/skills/quality/pr/SKILL.md +24 -4
  67. package/src/gdskills/bundled/skills/quality/pr-issue-documenter/SKILL.md +25 -2
  68. package/src/gdskills/bundled/skills/quality/push/SKILL.md +24 -3
  69. package/src/gdskills/bundled/skills/quality/root-cause/SKILL.md +204 -0
  70. package/src/gdskills/bundled/skills/quality/security-audit/SKILL.md +25 -4
  71. package/src/gdskills/bundled/skills/quality/test-gen/SKILL.md +24 -3
  72. package/src/gdskills/bundled/skills/quality/tests-creator/SKILL.md +17 -2
  73. package/src/gdskills/bundled/skills/review/code-ai-review/SKILL.md +40 -5
  74. package/src/gdskills/bundled/skills/review/code-learned-review/SKILL.md +41 -1
  75. package/src/gdskills/bundled/skills/review/code-mobx-store-review/SKILL.md +44 -2
  76. package/src/gdskills/bundled/skills/review/code-style-review/SKILL.md +44 -4
  77. package/src/gdskills/bundled/skills/review/review-architecture/SKILL.md +3 -3
  78. package/src/gdskills/bundled/skills/review/review-backend/SKILL.md +2 -3
  79. package/src/gdskills/bundled/skills/review/review-clean-code/SKILL.md +4 -4
  80. package/src/gdskills/bundled/skills/review/review-core-boundaries/SKILL.md +36 -2
  81. package/src/gdskills/bundled/skills/review/review-flow-graph/SKILL.md +37 -3
  82. package/src/gdskills/bundled/skills/review/review-frontend/SKILL.md +2 -4
  83. package/src/gdskills/bundled/skills/review/review-frontend-conventions/SKILL.md +36 -2
  84. package/src/gdskills/bundled/skills/review/review-highload/SKILL.md +3 -5
  85. package/src/gdskills/bundled/skills/review/review-layout/SKILL.md +23 -2
  86. package/src/gdskills/bundled/skills/review/review-logic/SKILL.md +3 -3
  87. package/src/gdskills/bundled/skills/review/review-orchestrator/SKILL.md +9 -29
  88. package/src/gdskills/bundled/skills/review/review-performance/SKILL.md +9 -9
  89. package/src/gdskills/bundled/skills/review/review-pr-feedback/SKILL.md +3 -2
  90. package/src/gdskills/bundled/skills/review/review-regression/SKILL.md +33 -2
  91. package/src/gdskills/bundled/skills/review/review-security-code/SKILL.md +4 -2
  92. package/src/gdskills/bundled/skills/review/review-style/SKILL.md +2 -2
  93. package/src/gdskills/bundled/skills/review/review-testing-practices/SKILL.md +40 -2
  94. package/src/gdskills/bundled/skills/review/review-verifier/SKILL.md +1 -1
  95. package/src/gdskills/bundled/skills/orchestration/code-verifier/SKILL.codex.md +0 -330
  96. package/src/gdskills/bundled/skills/orchestration/code-verifier/SKILL.cursor.md +0 -330
  97. package/src/gdskills/bundled/skills/orchestration/code-verifier/SKILL.opencode.md +0 -330
  98. package/src/gdskills/bundled/skills/orchestration/code-verifier/SKILL.zed.md +0 -330
  99. package/src/gdskills/bundled/skills/orchestration/context-collector/SKILL.codex.md +0 -655
  100. package/src/gdskills/bundled/skills/orchestration/context-collector/SKILL.cursor.md +0 -655
  101. package/src/gdskills/bundled/skills/orchestration/context-collector/SKILL.opencode.md +0 -655
  102. package/src/gdskills/bundled/skills/orchestration/context-collector/SKILL.zed.md +0 -655
  103. package/src/gdskills/bundled/skills/orchestration/feature-analyzer/SKILL.codex.md +0 -424
  104. package/src/gdskills/bundled/skills/orchestration/feature-analyzer/SKILL.cursor.md +0 -424
  105. package/src/gdskills/bundled/skills/orchestration/feature-analyzer/SKILL.opencode.md +0 -424
  106. package/src/gdskills/bundled/skills/orchestration/feature-analyzer/SKILL.zed.md +0 -424
  107. package/src/gdskills/bundled/skills/orchestration/feature-dev/SKILL.codex.md +0 -163
  108. package/src/gdskills/bundled/skills/orchestration/feature-dev/SKILL.cursor.md +0 -163
  109. package/src/gdskills/bundled/skills/orchestration/issue-analyzer/SKILL.codex.md +0 -373
  110. package/src/gdskills/bundled/skills/orchestration/issue-analyzer/SKILL.cursor.md +0 -373
  111. package/src/gdskills/bundled/skills/orchestration/issue-analyzer/SKILL.opencode.md +0 -373
  112. package/src/gdskills/bundled/skills/orchestration/issue-analyzer/SKILL.zed.md +0 -373
  113. package/src/gdskills/bundled/skills/orchestration/job-documenter/SKILL.codex.md +0 -374
  114. package/src/gdskills/bundled/skills/orchestration/job-documenter/SKILL.cursor.md +0 -374
  115. package/src/gdskills/bundled/skills/orchestration/job-documenter/SKILL.opencode.md +0 -374
  116. package/src/gdskills/bundled/skills/orchestration/job-documenter/SKILL.zed.md +0 -374
  117. package/src/gdskills/bundled/skills/orchestration/job-orchestrator/SKILL.codex.md +0 -2232
  118. package/src/gdskills/bundled/skills/orchestration/job-orchestrator/SKILL.cursor.md +0 -2232
  119. package/src/gdskills/bundled/skills/orchestration/job-orchestrator/SKILL.opencode.md +0 -2232
  120. package/src/gdskills/bundled/skills/orchestration/job-orchestrator/SKILL.zed.md +0 -2232
  121. package/src/gdskills/bundled/skills/orchestration/task-implementer/SKILL.codex.md +0 -668
  122. package/src/gdskills/bundled/skills/orchestration/task-implementer/SKILL.cursor.md +0 -668
  123. package/src/gdskills/bundled/skills/orchestration/task-implementer/SKILL.opencode.md +0 -668
  124. package/src/gdskills/bundled/skills/orchestration/task-implementer/SKILL.zed.md +0 -668
  125. package/src/gdskills/bundled/skills/planning/brainstorm/SKILL.codex.md +0 -90
  126. package/src/gdskills/bundled/skills/planning/brainstorm/SKILL.cursor.md +0 -90
  127. package/src/gdskills/bundled/skills/planning/interview/SKILL.codex.md +0 -187
  128. package/src/gdskills/bundled/skills/planning/interview/SKILL.cursor.md +0 -187
  129. package/src/gdskills/bundled/skills/planning/interviewer/SKILL.codex.md +0 -105
  130. package/src/gdskills/bundled/skills/planning/interviewer/SKILL.cursor.md +0 -105
  131. package/src/gdskills/bundled/skills/planning/prd-creator/SKILL.codex.md +0 -193
  132. package/src/gdskills/bundled/skills/planning/prd-creator/SKILL.cursor.md +0 -193
  133. package/src/gdskills/bundled/skills/planning/prd-creator/SKILL.opencode.md +0 -193
  134. package/src/gdskills/bundled/skills/planning/prd-creator/SKILL.zed.md +0 -193
  135. package/src/gdskills/bundled/skills/platform/claude-md-management/SKILL.codex.md +0 -87
  136. package/src/gdskills/bundled/skills/platform/claude-md-management/SKILL.cursor.md +0 -87
  137. package/src/gdskills/bundled/skills/platform/hookify/SKILL.codex.md +0 -100
  138. package/src/gdskills/bundled/skills/platform/hookify/SKILL.cursor.md +0 -100
  139. package/src/gdskills/bundled/skills/quality/changelog/SKILL.codex.md +0 -84
  140. package/src/gdskills/bundled/skills/quality/changelog/SKILL.cursor.md +0 -84
  141. package/src/gdskills/bundled/skills/quality/commit/SKILL.codex.md +0 -66
  142. package/src/gdskills/bundled/skills/quality/commit/SKILL.cursor.md +0 -66
  143. package/src/gdskills/bundled/skills/quality/db-migrate/SKILL.codex.md +0 -66
  144. package/src/gdskills/bundled/skills/quality/db-migrate/SKILL.cursor.md +0 -66
  145. package/src/gdskills/bundled/skills/quality/dependency-update/SKILL.codex.md +0 -81
  146. package/src/gdskills/bundled/skills/quality/dependency-update/SKILL.cursor.md +0 -81
  147. package/src/gdskills/bundled/skills/quality/deploy/SKILL.codex.md +0 -70
  148. package/src/gdskills/bundled/skills/quality/deploy/SKILL.cursor.md +0 -70
  149. package/src/gdskills/bundled/skills/quality/perf-check/SKILL.codex.md +0 -83
  150. package/src/gdskills/bundled/skills/quality/perf-check/SKILL.cursor.md +0 -83
  151. package/src/gdskills/bundled/skills/quality/pr/SKILL.codex.md +0 -75
  152. package/src/gdskills/bundled/skills/quality/pr/SKILL.cursor.md +0 -75
  153. package/src/gdskills/bundled/skills/quality/pr-issue-documenter/SKILL.codex.md +0 -378
  154. package/src/gdskills/bundled/skills/quality/pr-issue-documenter/SKILL.cursor.md +0 -378
  155. package/src/gdskills/bundled/skills/quality/pr-issue-documenter/SKILL.opencode.md +0 -378
  156. package/src/gdskills/bundled/skills/quality/pr-issue-documenter/SKILL.zed.md +0 -378
  157. package/src/gdskills/bundled/skills/quality/push/SKILL.codex.md +0 -52
  158. package/src/gdskills/bundled/skills/quality/push/SKILL.cursor.md +0 -52
  159. package/src/gdskills/bundled/skills/quality/security-audit/SKILL.codex.md +0 -108
  160. package/src/gdskills/bundled/skills/quality/security-audit/SKILL.cursor.md +0 -108
  161. package/src/gdskills/bundled/skills/quality/test-gen/SKILL.codex.md +0 -80
  162. package/src/gdskills/bundled/skills/quality/test-gen/SKILL.cursor.md +0 -80
  163. package/src/gdskills/bundled/skills/quality/tests-creator/SKILL.codex.md +0 -345
  164. package/src/gdskills/bundled/skills/quality/tests-creator/SKILL.cursor.md +0 -345
  165. package/src/gdskills/bundled/skills/quality/tests-creator/SKILL.opencode.md +0 -345
  166. package/src/gdskills/bundled/skills/quality/tests-creator/SKILL.zed.md +0 -345
  167. package/src/gdskills/bundled/skills/review/code-ai-review/SKILL.codex.md +0 -203
  168. package/src/gdskills/bundled/skills/review/code-ai-review/SKILL.cursor.md +0 -203
  169. package/src/gdskills/bundled/skills/review/code-ai-review/SKILL.opencode.md +0 -203
  170. package/src/gdskills/bundled/skills/review/code-ai-review/SKILL.zed.md +0 -203
  171. package/src/gdskills/bundled/skills/review/code-learned-review/SKILL.codex.md +0 -243
  172. package/src/gdskills/bundled/skills/review/code-learned-review/SKILL.cursor.md +0 -243
  173. package/src/gdskills/bundled/skills/review/code-learned-review/SKILL.opencode.md +0 -243
  174. package/src/gdskills/bundled/skills/review/code-learned-review/SKILL.zed.md +0 -243
  175. package/src/gdskills/bundled/skills/review/code-mobx-store-review/SKILL.codex.md +0 -259
  176. package/src/gdskills/bundled/skills/review/code-mobx-store-review/SKILL.cursor.md +0 -259
  177. package/src/gdskills/bundled/skills/review/code-mobx-store-review/SKILL.opencode.md +0 -259
  178. package/src/gdskills/bundled/skills/review/code-mobx-store-review/SKILL.zed.md +0 -259
  179. package/src/gdskills/bundled/skills/review/code-style-review/SKILL.codex.md +0 -168
  180. package/src/gdskills/bundled/skills/review/code-style-review/SKILL.cursor.md +0 -168
  181. package/src/gdskills/bundled/skills/review/code-style-review/SKILL.opencode.md +0 -168
  182. package/src/gdskills/bundled/skills/review/code-style-review/SKILL.zed.md +0 -168
@@ -1,2232 +0,0 @@
1
- ---
2
- name: job-orchestrator
3
- description: "Use when a GitHub issue or complex intent needs to be analyzed, planned, and implemented end-to-end with sub-agents."
4
- triggers:
5
- - "Implement issue"
6
- - "Issue to PR"
7
- - "Orchestrate"
8
- - "Run pipeline"
9
- - "Analyze and implement"
10
- - "Full implementation"
11
- - "Full review"
12
- - "Полное ревью"
13
- - "Review my code"
14
- - "Analyze branch"
15
- - "Review via orchestrator"
16
- - "Orchestrated review"
17
- - "Auto-implement"
18
- - "Auto-implement issue"
19
- - "Orchestrate issue"
20
- - "Run issue pipeline"
21
- - "Full issue implementation"
22
- metadata:
23
- author: "MrCipherSmith"
24
- version: "3.2.0"
25
- category: "orchestration"
26
- compatible_harnesses: "cursor,codex,zed,opencode,claude"
27
- license: "MIT"
28
- ---
29
-
30
- <SUBAGENT-STOP>
31
- If you were dispatched as a subagent to execute a specific task, skip this skill entirely.
32
- This skill is for orchestrators and interactive session-level routing only.
33
- Proceed directly with your assigned task.
34
- </SUBAGENT-STOP>
35
-
36
- # Job Orchestrator
37
-
38
- ## Purpose
39
-
40
- Dynamic orchestrator that builds execution plans based on user intent. Unlike a fixed pipeline, the orchestrator adapts its workflow to what the user actually needs — from "just analyze this issue" to "implement, review, and create a PR". It dispatches sub-agents (`issue-analyzer`, `context-collector`, `tests-creator`, `task-implementer`, `code-verifier`, `review-orchestrator`) and persists every step, document and retry through `keryx job`, which writes `.metaproject/jobs/<job-name>/`.
41
-
42
- **The package is the state.** `keryx job` is the only writer of `state.json`; it validates every write against the registered contract `job-orchestrator-state` and refuses one that does not conform. Never hand-write `state.json`, and never hold a step's outcome only in this session — a step recorded nowhere is a step that did not happen as far as the next session is concerned.
43
-
44
- **Execution metrics (opt-in):** when a USER runs this orchestrator directly (not as a dispatched subagent), at the start ask "Collect execution statistics for this run? (yes/no)" per `.metaproject/rules/core/execution-metrics.md`. If yes, append the `## Execution Metrics` section at the end and save it under the job dir (`jobs/<job>/metrics/`). Never ask or emit it when dispatched as a subagent.
45
-
46
- **Key design principle** (from Anthropic's "Building Effective Agents"):
47
- > "The key difference from parallelization is its flexibility — subtasks aren't pre-defined, but determined by the orchestrator based on the specific input."
48
-
49
- **Input:** User request (issue URL, analysis request, implementation request, etc.)
50
- **Output:** Executed plan + persistent job documentation in `.metaproject/jobs/<job-name>/` + optional PR
51
-
52
- ## When to Use
53
-
54
- - Implementing a complete GitHub issue from start to finish
55
- - Analyzing an issue and proposing a solution before implementing
56
- - Running any multi-step orchestrated workflow
57
- - Running a comprehensive code review with persistent documentation
58
- - When the AGENTS.md routing rule (Step 1.5) determines the user wants orchestrated execution and the user confirms
59
- - User says "implement issue #N", "analyze issue #N", provides an issue URL, or asks for orchestrated work
60
- - User says "full review", "полное ревью", or any request that implies orchestration
61
-
62
- ## Architecture: 4 Dynamic Phases
63
-
64
- ```
65
- Phase 0: CONTEXT COLLECTION → Gather info, determine intent
66
- Phase 1: PLAN BUILDING → Build dynamic plan, init job docs
67
- Phase 2: EXECUTION → Execute plan steps, document each result
68
- Phase 3: COMPLETION → Final report, optional PR, tell user where docs are
69
- ```
70
-
71
- ---
72
-
73
- ## Phase 0: CONTEXT COLLECTION
74
-
75
- ### 0.0 State Resumption Check
76
-
77
- Before asking any questions, list existing job packages:
78
-
79
- ```bash
80
- keryx job list --json
81
- ```
82
-
83
- Every entry carries `phase`, `stepsDone`/`stepsTotal` and `nextStep`. A job whose
84
- `phase` is not `COMPLETION` is unfinished.
85
-
86
- 1. If an unfinished job exists, ASK the user:
87
- "Found unfinished job '<job-name>' (<stepsDone>/<stepsTotal> steps, next: <nextStep>).
88
- Resume it or start a new orchestrated job?"
89
- 2. If resume → read the package and jump directly to the step it names:
90
-
91
- ```bash
92
- keryx job status <job-name> --json
93
- ```
94
-
95
- `next_step` is the first step that is neither `completed` nor `skipped` — computed
96
- from the file, not recalled. `retries` gives the recorded attempt count per step, so
97
- a resumed session continues from the real number instead of restarting at zero, and
98
- `documents` lists what has already been produced.
99
- 3. If new → proceed to 0.1.
100
-
101
- There is no `paused` status and nothing writes one. A job is unfinished exactly when a
102
- step is still open, and `keryx job status` is what reports that.
103
-
104
- ### 0.1 Determine User Intent
105
-
106
- Parse the user's request to identify the intent:
107
-
108
- | User Says | Intent | Plan Type |
109
- |-----------|--------|-----------|
110
- | "Implement issue #N" / "Issue to PR" | `implement` | Full: analyze → branch → implement → verify → review → fix → PR |
111
- | "Analyze issue #N" / "Study issue" | `analyze` | Analysis only: analyze → report. Then ask if user wants to implement. |
112
- | "Review my code" / "Review branch" | `review` | Review only: review → report |
113
- | "Analyze and implement" | `implement` | Same as implement |
114
- | Custom request | `custom` | Run `interviewer` skill first, then build plan from output |
115
-
116
- **Ambiguity detection:** If the request uses vague words ("improve", "fix", "refactor") with no issue number or specific file — trigger the **Interactive Approach Selection** below.
117
-
118
- ### 0.1.1 Interactive Approach Selection (for ambiguous requests)
119
-
120
- When intent cannot be determined confidently, present options to the user:
121
-
122
- ```
123
- I see several ways to approach this. Which fits best?
124
-
125
- A) 🔍 Analysis only — decompose into tasks, show plan, stop
126
- B) 🛠 Full implementation — analyze → implement → review → PR
127
- C) 📋 Analysis + brainstorm — explore approaches before committing
128
- D) 🔧 Review only — review current branch changes
129
- E) 📝 Custom — describe what you need, I'll build the plan
130
-
131
- > pick a letter or describe your own approach
132
- ```
133
-
134
- **Mapping:**
135
- - A → `analyze` intent
136
- - B → `implement` intent
137
- - C → `analyze` intent + trigger `brainstorm` after analysis
138
- - D → `review` intent
139
- - E → `custom` intent → proceed to 0.1.5 (interviewer gate)
140
-
141
- **Skip this step** when intent is clear (explicit issue number, "implement issue #N", "review my code").
142
-
143
- ### 0.1.5 Interviewer Gate (for `custom` and ambiguous requests)
144
-
145
- For `custom` intent OR any ambiguous request, invoke the `interviewer` skill **before** collecting standard context. This replaces the generic "What do you need?" question with a structured critical interview.
146
-
147
- **Invoke:**
148
- ```
149
- Load skill: skills/gdskills/planning/interviewer/SKILL.md
150
-
151
- INPUT:
152
- topic: <user's original request>
153
- goal: "job-orchestrator — build execution plan"
154
- context:
155
- codebase_summary: <git log --oneline -10 if available>
156
- existing_analysis: <any issue content already known>
157
- ```
158
-
159
- **Map output:**
160
- - `derived_context` → `INTENT_STATE.task_description`
161
- - answers with `confidence: "certain"` → `INTENT_STATE.constraints`
162
- - `blockers` → surface to user (if non-empty, do NOT proceed)
163
-
164
- **Gate rule:**
165
- - `ready_to_proceed: false` → STOP. Tell user what blockers remain.
166
- - `ready_to_proceed: true` → continue to 0.2 with enriched context.
167
-
168
- **Skip** for `implement`/`analyze` with an issue number — requirements are in the issue.
169
-
170
- ### 0.2 Collect Required Context
171
-
172
- The orchestrator MUST collect all required context before proceeding:
173
-
174
- **Always ask (mandatory):**
175
-
176
- 1. **What to do** — for `implement`/`analyze`: from issue. For `custom`: from interviewer output (0.1.5).
177
-
178
- 2. **Project directory** — NEVER assume. Always ask explicitly:
179
- ```
180
- Which project directory should I use?
181
- ○ Type the full absolute path to your project
182
- (No default — always ask, never assume.)
183
- ```
184
-
185
- 3. **Base branch** — auto-detect from repo:
186
- ```bash
187
- # Detect default branch
188
- git -C <project_dir> symbolic-ref refs/remotes/origin/HEAD 2>/dev/null | sed 's@^refs/remotes/origin/@@'
189
- # Fallback: check for main, master, develop
190
- ```
191
- Present detected branch and ask to confirm. No hardcoded default — and
192
- `input-contract.schema.json` declares none either, so the contract cannot
193
- reintroduce one behind the question.
194
-
195
- **Intent-specific questions:**
196
-
197
- | Intent | Additional Questions |
198
- |--------|---------------------|
199
- | `implement` | Create PR? (default: yes). Skip if user already stated. |
200
- | `analyze` | None — always produced. After: ask if user wants to implement. |
201
- | `review` | Which branch to review? (default: current branch) |
202
- | `custom` | None — covered by interviewer in 0.1.5 |
203
-
204
- 4. **Job name** — auto-generate based on context, ask user to confirm:
205
- ```
206
- Job documentation folder:
207
- ○ issue-4141--pipeline-validation (auto-generated, Recommended)
208
- ○ Type your own name
209
- ```
210
-
211
- **Naming patterns:**
212
- - Issue implementation: `issue-<N>--<slug>`
213
- - Issue analysis: `analysis--issue-<N>`
214
- - Code review: `review--<slug>`
215
- - Custom: `task--<slug>`
216
-
217
- ### 0.3 Interview for Implement Intent
218
-
219
- For `implement` intent, dispatch `interview` skill after collecting context to clarify implementation-specific ambiguities (complements 0.1.5 which handles `custom` intent):
220
-
221
- ```
222
- Dispatch interview skill with:
223
- {
224
- "goal": <issue title>,
225
- "context": <collected context + issue body>,
226
- "domain": "implement",
227
- "caller": "job-orchestrator",
228
- "known_facts": [project_dir, base_branch, issue details],
229
- "max_questions": null
230
- }
231
- ```
232
-
233
- **When to run:** `implement` intent only (if `run_interview: true`, default).
234
- **Skip for:** `analyze` (analysis reveals details), `review` (scoped by diff), `custom` (covered by 0.1.5).
235
-
236
- **Output → Phase 1:** `INTERVIEW_RESULT` feeds into plan building — informs task decomposition and architecture.
237
-
238
- **Brainstorm trigger:** If during interview the user answers "not sure" or the interview identifies an unresolved architectural question (high-impact decision with no clear answer), auto-trigger:
239
- ```
240
- Dispatch brainstorm --quick with:
241
- topic: <the specific architectural question>
242
- context: <project stack + interview answers so far>
243
- ```
244
- Present brainstorm result as enriched answer options, then continue interview.
245
-
246
- **Skip if:** user says "just do it" / "skip questions", or `run_interview: false`.
247
-
248
- ### 0.3.1 Dependency Check
249
-
250
- If the issue or interview reveals the task is primarily about updating dependencies:
251
- ```
252
- IF issue title/body contains "update", "upgrade", "bump", "dependency", "CVE":
253
- Suggest: "This looks like a dependency update task. Use /dependency-update instead?"
254
- IF user confirms → delegate to dependency-update skill, skip orchestrator pipeline
255
- ```
256
-
257
- ### 0.4 Summarize and Confirm
258
-
259
- Before proceeding, present a summary:
260
-
261
- ```
262
- Ready to proceed:
263
- Intent: implement
264
- Issue: #4141 — Pipeline validation improvements
265
- Project: /Users/.../<PROJECT>
266
- Base: <detected base branch>
267
- Create PR: yes
268
- Job name: issue-4141--pipeline-validation
269
-
270
- Proceed? (yes / adjust)
271
- ```
272
-
273
- This is the **operator** gate and it is not governed by `skip_confirmation`. That
274
- setting is `{"const": true}` in `input-contract.schema.json` and means exactly one
275
- thing: dispatched sub-agents run without asking the operator to approve each
276
- dispatch. It has never covered this question, and the two are named apart here so
277
- the contract and the prose stop reading as a contradiction. The gate that *can* be
278
- turned off is `plan_approval` in 1.3.
279
-
280
- `job_name` must match `^[a-z0-9-]+$` — the pattern `state.schema.json` declares and
281
- `keryx job init` enforces before it builds a path from the value. `issue-4141--pipeline-validation`
282
- conforms; anything with a slash, a space or an uppercase letter is refused.
283
-
284
- ---
285
-
286
- ## Phase 1: PLAN BUILDING
287
-
288
- ### 1.1 Build Execution Plan
289
-
290
- Based on intent, construct an ordered list of steps:
291
-
292
- **For `implement` intent:**
293
- ```
294
- PLAN:
295
- 1. { id: "analyze", type: "analyze", agent: "issue-analyzer", depends: [] }
296
- 2. { id: "context", type: "context", agent: "context-collector", depends: ["analyze"] }
297
- 3. { id: "prepare", type: "prepare", agent: "orchestrator", depends: ["context"] }
298
- 4. { id: "tests-creator", type: "tests", agent: "tests-creator", depends: ["prepare"] }
299
- 5. { id: "implement", type: "implement", agent: "task-implementer", depends: ["tests-creator"] }
300
- 6. { id: "sanity-check", type: "check", agent: "orchestrator", depends: ["implement"] }
301
- 7. { id: "verify", type: "verify", agent: "code-verifier", depends: ["sanity-check"] }
302
- 8. { id: "review", type: "review", agent: "review-orchestrator", depends: ["verify"] }
303
- 9. { id: "security", type: "security", agent: "security-audit", depends: ["implement"], conditional: true }
304
- 10. { id: "fix", type: "fix", agent: "task-implementer", depends: ["review"], conditional: true }
305
- 11. { id: "verify-post-fix", type: "verify", agent: "code-verifier", depends: ["fix"], conditional: true }
306
- 12. { id: "perf-check", type: "perf", agent: "perf-check", depends: ["verify"], conditional: true }
307
- 13. { id: "report", type: "report", agent: "orchestrator", depends: ["verify"] }
308
- 14. { id: "pr", type: "pr", agent: "orchestrator", depends: ["report"], conditional: true }
309
- 15. { id: "deploy", type: "deploy", agent: "deploy", depends: ["pr"], conditional: true }
310
- ```
311
-
312
- This is the plan `keryx job init --intent implement` writes, step for step. The `agent`
313
- field is the **label recorded in the plan**, not a dispatch target: the `review` step is
314
- executed by `review-orchestrator` (2.6), and `orchestrator` means this skill does the
315
- step itself. Read the recorded plan back at any time with `keryx job status <job-name>`.
316
-
317
- **Conditional step triggers** — one row per step, no step listed twice:
318
-
319
- | Step | Runs when |
320
- |------|-----------|
321
- | `sanity-check` | always — verifies ≥1 commit was made |
322
- | `tests-creator` | always — mandatory TDD step before every task-implementer wave |
323
- | `verify` | always — `code-verifier` is the mandatory quality gate after implementation |
324
- | `security` | diff touches `auth/`, `api/`, migrations, schema files, or `.env` |
325
- | `fix` | review or verify produced a `blocker` or `major` finding |
326
- | `verify-post-fix` | after `fix` ran — confirms the fix resolved the findings |
327
- | `perf-check` | diff contains `*.tsx`, `*.jsx`, `*.css`, `dist/` or `build/` files |
328
- | `pr` | `create_pr: true` |
329
- | `deploy` | user answers "yes" to the post-PR staging deploy prompt |
330
-
331
- Severities are the canonical four — `blocker`, `major`, `minor`, `info` — from
332
- `review-finding.schema.json`. They are the only vocabulary this skill uses, so the
333
- `fix` trigger and the counts in the report are read off the same field.
334
-
335
- Note: `security` runs in parallel with `review` (both depend on `implement` results, no overlap).
336
-
337
- **A conditional step is not exempt from the record.** Every step in the plan is
338
- written into the package by `keryx job init`, and `keryx job complete` refuses while
339
- any step is neither `completed` nor `skipped`. A condition that did not fire is
340
- closed explicitly:
341
-
342
- ```bash
343
- keryx job step <job-name> perf-check --status skipped --reason "no frontend files in diff"
344
- ```
345
-
346
- **For `analyze` intent:**
347
- ```
348
- PLAN:
349
- 1. { id: "analyze", type: "analyze", agent: "issue-analyzer", depends: [] }
350
- 2. { id: "context", type: "context", agent: "context-collector", depends: ["analyze"] }
351
- 3. { id: "report", type: "report", agent: "orchestrator", depends: ["context"] }
352
- 4. { id: "proposal", type: "proposal", agent: "orchestrator", depends: ["report"] }
353
- ```
354
- Step 4 (`proposal`) asks the user: "Want me to implement this? If yes, I'll extend the plan."
355
-
356
- **For `review` intent:**
357
- ```
358
- PLAN:
359
- 1. { id: "context", type: "context", agent: "context-collector", depends: [] }
360
- 2. { id: "review", type: "review", agent: "reviewers", depends: ["context"] }
361
- 3. { id: "report", type: "report", agent: "orchestrator", depends: ["review"] }
362
- ```
363
-
364
- **For `custom` intent:**
365
- Build plan dynamically. Each step must have: id, type, agent, dependencies.
366
-
367
- ### 1.2 Create the Job Package
368
-
369
- Create the package with the CLI. This is one command, run by the orchestrator — not
370
- a sub-agent dispatch:
371
-
372
- ```bash
373
- keryx job init --name <job-name> --intent implement|analyze|review|custom --project <project_dir>
374
- ```
375
-
376
- It creates `.metaproject/jobs/<job-name>/` containing:
377
-
378
- - `state.json` — validated against the registered contract `job-orchestrator-state`
379
- on **every** write. A state that does not conform is refused, not written.
380
- - `journal.md` — append-only, one line per recorded event, written by `keryx job`.
381
- - the plan for the chosen intent, every step `pending`, with `plan.current_step`
382
- already pointing at the first one.
383
-
384
- `--intent` defaults to `implement`. `--project` defaults to the current directory;
385
- pass the path collected in 0.2 explicitly rather than relying on the default.
386
-
387
- **Refusals to expect, and what each means:**
388
-
389
- | Message | Cause |
390
- |---------|-------|
391
- | `Job package already exists: .metaproject/jobs/<name>` | The package is there. Run `keryx job status <name>` and resume it (0.0) instead of re-initialising. |
392
- | `Invalid --name "<name>"` | The name is not `^[a-z0-9-]+$`. |
393
- | `Invalid --intent "<value>"` | Not one of `implement`, `analyze`, `review`, `custom`. |
394
-
395
- Confirm the result before proceeding:
396
-
397
- ```bash
398
- keryx job status <job-name>
399
- ```
400
-
401
- It prints the phase, the step list with statuses, and `next:` — the step execution
402
- starts from.
403
-
404
- ### 1.3 Display Plan + Agent Approval
405
-
406
- Display the plan the package actually holds — do not retype it from memory:
407
-
408
- ```bash
409
- keryx job status <job-name>
410
- ```
411
-
412
- There is **one** plan. Every step listed in 1.1 is in it, including the conditional
413
- ones; a conditional step is one whose trigger may not fire, not one that is absent
414
- until somebody adds it. For the `implement` intent that is fifteen steps:
415
-
416
- ```
417
- Execution plan — 15 steps (◦ = conditional):
418
-
419
- Step 1 analyze issue-analyzer → issue #<N>
420
- Step 2 context context-collector → project context + test framework
421
- Step 3 prepare orchestrator → feature branch worktree
422
- Step 4 tests-creator tests-creator × <tasks> → RED test stubs per task (MANDATORY)
423
- Step 5 implement task-implementer × <tasks> → <N> tasks make tests GREEN (wave-parallel)
424
- Step 6 sanity-check orchestrator → verify commits exist
425
- Step 7 verify code-verifier → lint + type-check + tests + imports (MANDATORY)
426
- Step 8 review review-orchestrator → managed review round
427
- Step 9 ◦ security security-audit → auth/API/DB/env files touched
428
- Step 10◦ fix task-implementer → blocker or major findings
429
- Step 11◦ verify-post-fix code-verifier → after fix
430
- Step 12◦ perf-check perf-check → frontend/bundle files changed
431
- Step 13 report orchestrator → final summary
432
- Step 14◦ pr orchestrator + gh CLI → create_pr=true
433
- Step 15◦ deploy deploy → user asked for a staging deploy
434
-
435
- Proceed? (yes / adjust: "skip fix", "remove pr", etc.)
436
- ```
437
-
438
- **If user adjusts:** record the decision in the package rather than holding it in
439
- this session:
440
-
441
- ```bash
442
- # "skip fix" — close it now, with the reason on the record
443
- keryx job step <job-name> fix --status skipped --reason "operator asked to skip at plan approval"
444
- # "remove pr"
445
- keryx job step <job-name> pr --status skipped --reason "create_pr: false"
446
- ```
447
-
448
- Then re-display with `keryx job status <job-name>` and ask again. A step the operator
449
- removed is `skipped` with a reason, never silently dropped — that is the difference
450
- between a plan somebody changed and a plan that quietly shrank.
451
-
452
- **If `plan_approval: false`** (automation setting) → skip this display and proceed directly.
453
-
454
- ---
455
-
456
- ## Phase 2: EXECUTION
457
-
458
- Execute each step in plan order, documenting results after each step.
459
-
460
- ### 2.1 General Execution Loop
461
-
462
- Every step in the loop is bracketed by two `keryx job` calls. The package, not this
463
- session, is what says a step ran.
464
-
465
- ```
466
- FOR step in PLAN:
467
- IF step.conditional AND condition_not_met:
468
- keryx job step <job-name> <step-id> --status skipped --reason "<why the trigger did not fire>"
469
- CONTINUE
470
-
471
- 2.1.1 Open the step:
472
- keryx job step <job-name> <step-id> --status in-progress
473
- Re-entering a step that was already opened increments `metrics.steps[].retries`
474
- — that counter is the attempt budget, and it survives a session restart.
475
-
476
- 2.1.2 Execute step (see step-specific instructions below)
477
- If the sub-agent returns a malformed result or fails to follow formatting rules, run an explicit retry:
478
- "The previous output was malformed. Fix these errors: [errors] and try again." (Max 2 retries before counting as critical failure).
479
- Re-open the step before each retry so the retry is counted.
480
-
481
- 2.1.3 Collect result
482
-
483
- 2.1.4 Write the document to disk, then record it in the package:
484
- keryx job document <job-name> --type analysis|implementation-report|review|verification-report --file <path>
485
- The file must already exist — `job document` refuses a `--file` it cannot
486
- find with "Write the document first, then record it." It copies the file
487
- into the package and adds it to `documentation.documents_created`.
488
- Re-recording the same type replaces the file and leaves one entry.
489
-
490
- 2.1.5 Confirm what the package now holds:
491
- keryx job status <job-name>
492
- The step list, the retry counts and the recorded documents come from
493
- `state.json`. This is the job index; there is no README to update.
494
-
495
- 2.1.6 Close the step:
496
- keryx job step <job-name> <step-id> --status completed
497
-
498
- IF step failed critically:
499
- keryx job step <job-name> <step-id> --status failed --reason "<what failed>"
500
- Ask user: "Step '<name>' failed. Continue with remaining steps or abort?"
501
- IF abort: skip to Phase 3 (COMPLETION)
502
- ```
503
-
504
- **`failed` is not terminal.** `keryx job complete` refuses while any step is `failed`
505
- or still open, and names them. A job that genuinely ends with a step unfinished is
506
- closed by deciding what happened to that step — `--status skipped --reason "<why>"` —
507
- which leaves the decision on the record instead of leaving the package half-written.
508
-
509
- Only four document types exist: `analysis`, `implementation-report`, `review`,
510
- `verification-report`. Anything else is refused with the valid list.
511
-
512
- ### 2.2 Step: ANALYZE
513
-
514
- Dispatch `issue-analyzer` as a sub-agent.
515
-
516
- **Prepare prompt:** Read `skills/gdskills/orchestration/issue-analyzer/orchestrator-prompt.md`
517
- and fill in:
518
- - Issue URL or repo+number
519
- - Codebase paths with roles
520
- - Automation settings (skip_confirmation: true, search_depth: focused)
521
-
522
- That file ships with the skill. If the read fails, the path is wrong or the skill is
523
- not installed — stop and say so. Do not proceed on an improvised prompt: a missed
524
- template is exactly the failure that hid behind the old "(if it exists)" hedge.
525
-
526
- **Launch:**
527
- ```
528
- Task({
529
- description: "Issue analysis: #<N>",
530
- subagent_type: "general-purpose",
531
- prompt: <constructed prompt>
532
- })
533
- ```
534
-
535
- **Parse result:** Extract JSON analysis object:
536
- ```
537
- ANALYSIS_RESULT:
538
- issue_type: from issue.type
539
- total_tasks: from issue.total_tasks (= tasks.length)
540
- tasks: [{task_id, task_name, task_type, complexity, dependencies,
541
- description, target_files, acceptance_criteria, context,
542
- existing_tests, existing_stories, module_patterns}]
543
- dependency_order: from dependency_order array (already topologically sorted)
544
- ```
545
-
546
- **Validate:** At least 1 task, no circular dependencies, all dependency references valid. Dependency_order array must contain all task_ids exactly once.
547
-
548
- **Document:** write the analysis, then record it:
549
-
550
- ```bash
551
- keryx job document <job-name> --type analysis --file <path/to/analysis.md>
552
- ```
553
-
554
- It lands in the package as `analysis.md` (the source extension is preserved, so a
555
- `.json` analysis lands as `analysis.json`) and appears in `documents` on the next
556
- `keryx job status`.
557
-
558
- **For `analyze` intent:** After documenting, present analysis to user. Ask:
559
- ```
560
- Analysis complete. Found <N> tasks.
561
- Want me to implement this? I'll create a feature branch and run the full pipeline.
562
- ○ Yes, implement
563
- ○ No, analysis is enough
564
- ```
565
- If "Yes" → follow Plan Extension below: create an `implement` package and continue there. Do not rewrite this package's plan.
566
- If "No" → skip to Phase 3 (COMPLETION).
567
-
568
- ### 2.3 Step: CONTEXT
569
-
570
- Dispatch `context-collector` to build the unified context document.
571
-
572
- **Prepare prompt:** Use the template from `skills/gdskills/orchestration/context-collector/SKILL.md`:
573
-
574
- ```
575
- Task({
576
- description: "Collect context: <job-name>",
577
- subagent_type: "general-purpose",
578
- prompt: |
579
- You are the context-collector agent. Your task is to research and build
580
- a context document for the current job.
581
-
582
- Load the skill from: skills/gdskills/orchestration/context-collector/SKILL.md
583
-
584
- ACTION: collect
585
- JOB_NAME: <job-name>
586
- JOBS_ROOT: <JOBS_ROOT>
587
- PROJECT_DIR: <project_dir>
588
-
589
- DATA:
590
- TASK_DESCRIPTION: <from issue or user request>
591
- FOCUS_AREAS: <derived from analysis — affected areas, libraries>
592
- ANALYSIS_RESULT: <output from issue-analyzer, if available>
593
- KNOWN_LIBRARIES: <from package.json scan during analysis>
594
-
595
- Execute all phases and return a CONTEXT_RESULT block.
596
- })
597
- ```
598
-
599
- **Parse result:**
600
- ```
601
- CONTEXT_RESULT:
602
- status: success | error
603
- version: <document version>
604
- summary: <what context was collected>
605
- ```
606
-
607
- **Validate:** status must be `success`. If `error` → log warning, continue (context is helpful but not blocking).
608
-
609
- **After context is collected:** the orchestrator holds the context path and puts it
610
- into every subsequent dispatch prompt:
611
-
612
- ```
613
- CONTEXT_LOCATION: <JOBS_ROOT>/<job-name>/ai/context.md
614
- ```
615
-
616
- **Context versioning:** the file lives at this one fixed path and is overwritten in
617
- place on every update — never written to a new, version-numbered filename. Each
618
- collect/update instead increments the `Version` field in the document's own
619
- "Document Metadata" table and appends a line to its `Update Log` section (see
620
- context-collector SKILL.md §4.1, §4.3); that table on disk is the current version.
621
-
622
- `state.json` does not carry a context pointer and nothing writes one — do not tell a
623
- sub-agent to look for one. The orchestrator passes the path (Constructing Subagent
624
- Context, below); subagents receive, they do not retrieve.
625
-
626
- **Triggering context updates during execution:**
627
-
628
- If during later steps (implement, review) a sub-agent reports missing context or a new library is discovered:
629
-
630
- ```
631
- Task({
632
- description: "Update context: <job-name>",
633
- subagent_type: "general-purpose",
634
- prompt: |
635
- You are the context-collector agent. Update the existing context.
636
-
637
- Load the skill from: skills/gdskills/orchestration/context-collector/SKILL.md
638
-
639
- ACTION: update
640
- JOB_NAME: <job-name>
641
- JOBS_ROOT: <JOBS_ROOT>
642
- PROJECT_DIR: <project_dir>
643
- CONTEXT_VERSION: <current version + 1> ← written into ai/context.md's Version field; file overwritten in place
644
-
645
- DATA:
646
- TASK_DESCRIPTION: <original task description>
647
- UPDATE_REASON: <why context needs updating>
648
- FOCUS_AREAS: <new areas to research>
649
-
650
- Execute update flow and return a CONTEXT_RESULT block.
651
- })
652
- ```
653
-
654
- ### 2.4 Step: PREPARE
655
-
656
- Create git worktree for feature branch.
657
-
658
- > **CRITICAL**: Feature branches MUST be created via `git worktree add`.
659
- > **NEVER** use `git checkout -b` or `git switch -c` — this switches the main working directory.
660
- > The worktree is a **sibling directory** to the project directory.
661
-
662
- **Determine branch name:**
663
- ```
664
- Format: feature/<custom-slug>
665
- Slug: descriptive, lowercase, alphanumeric+hyphens, from issue title/feature
666
- Examples: feature/pipeline-validation, feature/mirror-step-source-column
667
- ```
668
-
669
- **Create worktree:**
670
- ```bash
671
- # Fetch latest base branch
672
- git -C <project_dir> fetch origin <base_branch>
673
-
674
- # Create worktree as SIBLING directory
675
- git -C <project_dir> worktree add ../<branch-slug> -b feature/<branch-slug> origin/<base_branch>
676
-
677
- # Example:
678
- # Project dir: /Users/user/projects/<PROJECT>
679
- # git -C ... worktree add ../pipeline-validation -b feature/pipeline-validation origin/develop-2
680
- # Result worktree: /Users/user/projects/pipeline-validation
681
- # Result branch: feature/pipeline-validation
682
-
683
- # Auto-detect package manager and install dependencies
684
- if [ -f <worktree_path>/bun.lock ] || [ -f <worktree_path>/bun.lockb ]; then
685
- PM="bun"; RUNNER="bun run"; bun install --cwd <worktree_path>
686
- elif [ -f <worktree_path>/pnpm-lock.yaml ]; then
687
- PM="pnpm"; RUNNER="pnpm run"; pnpm install --prefix <worktree_path>
688
- elif [ -f <worktree_path>/yarn.lock ]; then
689
- PM="yarn"; RUNNER="yarn"; yarn --cwd <worktree_path>
690
- elif [ -f <worktree_path>/package-lock.json ]; then
691
- PM="npm"; RUNNER="npm run"; npm install --prefix <worktree_path>
692
- elif [ -f <worktree_path>/requirements.txt ]; then
693
- PM="python"; RUNNER=""; pip install -r <worktree_path>/requirements.txt
694
- elif [ -f <worktree_path>/go.mod ]; then
695
- PM="go"; RUNNER=""; (cd <worktree_path> && go mod download)
696
- fi
697
- ```
698
-
699
- > **IMPORTANT**: After creating the worktree, ALL subsequent operations (implementation, review, lint, test, git) MUST run in the **worktree directory**, NOT in the original project directory.
700
-
701
- > **Concurrency**: every subsequent git command MUST use `git -C <worktree_path>`, never a bare `git`, and MUST NOT `git stash` or `git add -A`/`--all`/`.` — see `rules/core/git-concurrency.mdc`. Pin each dispatch to `<worktree_path>` explicitly; a dispatched agent's first action is `cd <worktree_path> && pwd && git branch --show-current`, re-checked before its first write.
702
-
703
- **Record state:**
704
- ```
705
- BRANCH_STATE:
706
- name: feature/<branch-slug>
707
- base: <base_branch>
708
- worktree_path: <absolute path to worktree>
709
- project_dir: <original project directory — DO NOT modify>
710
- created_from_commit: <commit hash>
711
- package_manager: <PM>
712
- run_command: <RUNNER>
713
- ```
714
-
715
- > **Carry `package_manager` and `run_command` into every subsequent dispatch prompt** — all subsequent steps use these instead of hardcoded `npm`. They are not persisted; the orchestrator holds them for the run and states them explicitly in each dispatch.
716
-
717
- **Record:** close the step and put the branch on the record:
718
-
719
- ```bash
720
- keryx job step <job-name> prepare --status completed --reason "feature/<branch-slug> at <worktree_path>"
721
- ```
722
-
723
- `--reason` is appended to the package's `journal.md` with a timestamp, which is where
724
- "what branch did this job use" is answerable after the session ends.
725
-
726
- ### 2.5 Step: TESTS-CREATOR + IMPLEMENT
727
-
728
- tests-creator runs before task-implementer for every task, with no exceptions.
729
-
730
- There is no `wave-executor` agent. Each wave is two dispatches the orchestrator makes
731
- itself — `tests-creator`, then `task-implementer` — and both are real, installed
732
- skills. Nothing is delegated to an intermediary that does not exist.
733
-
734
- **CONTEXT BUDGET RULE: instruct every dispatched agent to write its full result to a
735
- file and return only a compact summary line.** The orchestrator's context grows with
736
- what agents *return*, not with what they do; a returned result file path costs a line,
737
- an inlined verification log costs thousands. After 3–4 waves of inlined results the
738
- session freezes on context reload, which is the failure this rule exists to avoid.
739
-
740
- ---
741
-
742
- #### Wave ordering
743
-
744
- Waves come from `dependency_order` in `ANALYSIS_RESULT`, which `issue-analyzer` already
745
- returned topologically sorted and which 2.2 validated. Wave 1 is every task with no
746
- unsatisfied dependency; wave N+1 is every task whose dependencies are all in waves 1..N.
747
- Do not re-derive an ordering the analysis already produced.
748
-
749
- #### Execution pattern
750
-
751
- ```
752
- FOR wave_index, wave_tasks in enumerate(WAVES):
753
-
754
- keryx job step <job-name> tests-creator --status in-progress # wave 1 only
755
- # Step A — tests-creator (MANDATORY, run first)
756
- Dispatch one tests-creator per task in this wave, in a SINGLE turn (parallel).
757
- Wait for ALL of them. Collect TEST_SPECS[task_id] from each response.
758
- keryx job step <job-name> tests-creator --status completed # last wave only
759
-
760
- # Parallel safety check, before Step B:
761
- # if two tasks in this wave share a target_file, dispatch them sequentially.
762
-
763
- keryx job step <job-name> implement --status in-progress # wave 1 only
764
- # Step B — task-implementer (after all test stubs are committed)
765
- Dispatch one task-implementer per task in this wave, in a SINGLE turn (parallel),
766
- each carrying test_case_specs: TEST_SPECS[task_id].
767
- Wait for ALL of them.
768
-
769
- Read each result's STATUS line:
770
- DONE / DONE_WITH_CONCERNS → accept it (record every concern)
771
- BLOCKED → do not accept it; read its result file
772
-
773
- # Task boundary commit, for EVERY accepted result, before anything else,
774
- # whatever auto_commit was (see "Task boundary commit" below):
775
- FOR each accepted result: commit its still-changed reported paths, or skip
776
-
777
- any BLOCKED → STOP, resolve or ask the user
778
- otherwise → continue to next wave
779
- ```
780
-
781
- #### tests-creator dispatch (Step A)
782
-
783
- ```
784
- Task({
785
- description: "Wave <N> tests: <task_id>",
786
- subagent_type: "general-purpose",
787
- prompt: |
788
- Load skill: skills/gdskills/quality/tests-creator/SKILL.md
789
-
790
- ## Task
791
- <the single task object>
792
-
793
- ## Workspace
794
- - worktree_path: <absolute path>
795
- - branch: <branch name>
796
- - package_manager: <pm>
797
- - run_command: <runner>
798
- - context_path: <JOBS_ROOT>/<job-name>/ai/context.md
799
-
800
- ## Required response
801
- Begin with STATUS: <STATUS>. Return the test_case_specs for this task and
802
- nothing else inline; write anything longer to
803
- <JOBS_ROOT>/<job-name>/results/<task_id>-tests.json and return the path.
804
- })
805
- ```
806
-
807
- #### task-implementer dispatch (Step B)
808
-
809
- ```
810
- Task({
811
- description: "Wave <N> implement: <task_id>",
812
- subagent_type: "general-purpose",
813
- prompt: |
814
- Load skill: skills/gdskills/orchestration/task-implementer/SKILL.md
815
-
816
- ## Task
817
- <the single task object, WITH test_case_specs: TEST_SPECS[task_id]>
818
-
819
- ## Workspace
820
- - worktree_path: <absolute path>
821
- - branch: <branch name>
822
- - package_manager: <pm>
823
- - run_command: <runner>
824
- - issue_number: <N>
825
- - job_name: <job-name>
826
- - context_path: <JOBS_ROOT>/<job-name>/ai/context.md
827
-
828
- ## Automation (task-implementer input `automation`)
829
- - auto_commit: <implementer_settings.auto_commit> # false: do not commit; report exact paths
830
-
831
- ## Required response format (compact — no inline JSON)
832
- STATUS: DONE
833
- Task: <task_id>
834
- Commits: [abc1234 feat(x): ...] # auto_commit=false: Commits: none (auto_commit=false)
835
- Tests: <N passed, M failed>
836
- Result file: <JOBS_ROOT>/<job-name>/results/<task_id>.json
837
-
838
- Write full detail to the result file. Do NOT inline it.
839
- })
840
- ```
841
-
842
- **Who commits is set by the dispatch, never by a default.** Step B always passes
843
- `auto_commit` explicitly. The worker's own default is `true`, so a dispatch that
844
- leaves it out gets a worker that commits even when `implementer_settings.auto_commit`
845
- is `false`.
846
-
847
- **Task boundary commit, for every accepted result, whatever `auto_commit` was:**
848
- a task is not done until its diff is committed (`rules/core/git-concurrency.mdc`
849
- rule 4, "Reporting Back"). As soon as a result is accepted (`STATUS: DONE` or
850
- `DONE_WITH_CONCERNS`), take its reported `files_modified`/`files_created`/
851
- `files_deleted` from the result file and commit the ones git still shows as
852
- changed, never `-A`/`--all`/`.`:
853
- ```bash
854
- set -- <each files_modified/files_created/files_deleted path, single-quoted: 'src/a.ts' 'docs/b c.md'> # may be none; an unquoted path with a space splits and is skipped
855
- PENDING=()
856
- for p in "$@"; do
857
- [ -n "$(git -C <worktree_path> status --porcelain -- "$p")" ] && PENDING+=("$p")
858
- done
859
- if [ ${#PENDING[@]} -eq 0 ]; then
860
- echo "boundary commit: nothing left to commit, skipped"
861
- else
862
- git -C <worktree_path> add -- "${PENDING[@]}"
863
- git -C <worktree_path> commit -m "<type>(<scope>): <task description>
864
-
865
- task: <task_id>" -- "${PENDING[@]}"
866
- fi
867
- ```
868
- With `auto_commit=false` this commits exactly the worker's paths. With
869
- `auto_commit=true` the worker already committed, so nothing is left and the step
870
- skips. That is the expected outcome, not an error. If paths remain after an
871
- `auto_commit=true` worker, it left part of its diff uncommitted: the step
872
- commits it, and you record that as a concern. Each path is checked on its own
873
- because `git status --porcelain --` with no path lists the whole tree, `git add`
874
- fails on a path that is neither on disk nor tracked, and `git commit` with
875
- nothing staged exits 1. The trailing `-- "${PENDING[@]}"` commits only these
876
- paths, so a file another lane staged is not swept into this commit.
877
-
878
- **Each wave runs in ONE worktree.** The worktree created in 2.4 is the whole job's
879
- workspace — waves are ordered, not isolated from each other, and a later wave sees
880
- what an earlier one committed. That is what makes the dependency order mean anything.
881
-
882
- **After all waves, document:** write the implementation report, then record it:
883
-
884
- ```bash
885
- keryx job document <job-name> --type implementation-report --file <path/to/implementation-report.md>
886
- keryx job step <job-name> implement --status completed
887
- ```
888
-
889
- The report summarises every wave: commits, files, test totals, and each task's final
890
- STATUS.
891
-
892
- ### 2.5.1 Post-Implementation Checkpoint
893
-
894
- After all waves complete, check if tests were created. If not, offer `test-gen`:
895
-
896
- ```
897
- # Derive all modified files from the per-task result files
898
- ALL_FILES = collect from <JOBS_ROOT>/<job-name>/results/*.json
899
-
900
- IF no test files in ALL_FILES:
901
- Auto-trigger test-gen for new/modified source files
902
- (skip test files, config files, types-only files)
903
- ```
904
-
905
- Then present the implementation summary to user:
906
-
907
- ```
908
- Implementation complete:
909
- - <N>/<M> tasks ✅
910
- - <X> files modified, <Y> files created
911
- - Tests: <created by implementer | auto-generated by test-gen | none>
912
-
913
- What's next?
914
- A) 🔍 Review → fix → PR (standard pipeline)
915
- B) 👀 Show me the diff first — I'll review manually
916
- C) 🚀 Skip review, go straight to PR
917
- D) ⏹ Stop here — I'll continue manually
918
- ```
919
-
920
- **Mapping:**
921
- - A → continue to the REVIEW step (2.6)
922
- - B → run `git diff <merge_base>..HEAD --stat` and `git diff <merge_base>..HEAD`, then re-ask
923
- - C → skip REVIEW and FIX, go to VERIFY (2.8) → PR. Record both:
924
- `keryx job step <job-name> review --status skipped --reason "operator chose to skip review"`
925
- - D → close the open steps with a reason and go to Phase 3:
926
- `keryx job step <job-name> <step-id> --status skipped --reason "operator stopped here to continue manually"`
927
-
928
- **Wait for the answer.** There is no default and no timer: this skill runs as a model
929
- in a turn-based session, and nothing here can observe wall-clock time passing while a
930
- user does not reply. A "default after N seconds" could never fire, so it is not
931
- offered.
932
-
933
- ### 2.5.2 Step: IMPLEMENT SANITY CHECK
934
-
935
- Lightweight verification after all waves complete, **before** launching review.
936
- This catches the case where a task-implementer reports `STATUS: DONE` but made no
937
- actual git changes.
938
-
939
- ```bash
940
- # Run in worktree directory
941
- git diff --stat <merge_base>..HEAD
942
- git log <merge_base>..HEAD --oneline
943
- ```
944
-
945
- **Gate conditions:**
946
-
947
- | Check | Pass | Fail action |
948
- |-------|------|-------------|
949
- | At least 1 commit exists | ≥1 commit | `implementer_settings.auto_commit=true`: `retryable` — re-dispatch the task-implementers for that wave with: "No commits were made. Implement the changes and commit them." `auto_commit=false`: the task-boundary commit (wave loop, after Step B) should already have committed each accepted result's files — if none exist, `retryable`: re-run that commit step for the wave's result files instead of re-dispatching workers. |
950
- | At least 1 file modified | ≥1 file changed | Same as above |
951
- | Claimed files actually modified | All files named in the result files appear in the diff | Log discrepancy as a concern, continue |
952
-
953
- Re-open the step before re-dispatching, so the attempt is counted:
954
-
955
- ```bash
956
- keryx job step <job-name> implement --status in-progress
957
- ```
958
-
959
- `metrics.steps[].retries` for `implement` goes up by one. Read it back with
960
- `keryx job status <job-name> --json` — the count is on disk, so it is still right
961
- after a session restart.
962
-
963
- **If the retry also produces no commits** → classify as `terminal` and stop:
964
-
965
- ```bash
966
- keryx job step <job-name> sanity-check --status failed --reason "task-implementer reported DONE twice with no git changes"
967
- ```
968
-
969
- ```
970
- "task-implementer returned STATUS: DONE twice but made no git changes.
971
- Please implement manually and re-run from the review step."
972
- ```
973
-
974
- **Record the outcome** in the journal, where it survives the session:
975
-
976
- ```bash
977
- keryx job step <job-name> sanity-check --status completed \
978
- --reason "<N> commits, <M> files changed, +<A>/-<R> lines"
979
- ```
980
-
981
- There is no `sanity_check` field in `state.json` and nothing writes one — the
982
- journal line is the record.
983
-
984
- ---
985
-
986
- ### 2.6 Step: REVIEW
987
-
988
- `review-orchestrator` is the review path. It is not one strategy among several: it is
989
- the only entry point that produces a **managed review record**, and every round this
990
- skill runs is a round that must be citable afterwards. The legacy alternatives —
991
- launching `code-ai-review` / `code-learned-review` / `code-style-review` by hand, or the
992
- never-bundled `code-review` 4-agent skill — are gone. They emitted prose into a chat
993
- transcript and nothing else, which is precisely the failure the managed pipeline
994
- replaced.
995
-
996
- A pull request driven by this orchestrator has to pass the completion gate shipped in
997
- 0.2.71. Its five conditions are what 2.6 and 2.7 are built to satisfy:
998
-
999
- | Gate condition | Satisfied by |
1000
- |---|---|
1001
- | every fix round has a managed record | `keryx review start` before, `keryx review ingest` after (2.6.1, 2.7) |
1002
- | every finding has a terminal disposition | `keryx review complete --finding … --disposition … --evidence …` (2.7) |
1003
- | scope B is recorded when a scope-B reviewer ran | `keryx review blast-radius --json` → `review ingest --blast-radius` (2.6.1) |
1004
- | no inbound PR comment is unanswered | `keryx review comments collect` every round, `… reply --final` once (2.6.2) |
1005
- | verification stats exist | `review-verifier` dispatched, passed as `--verifications` (2.6.1) |
1006
-
1007
- #### 2.6.0 Review Scope Selection
1008
-
1009
- Ask which reviewer set to use. The flags are `review-orchestrator`'s, and they select
1010
- reviewers — there is no "quick vs thorough" mode:
1011
-
1012
- ```
1013
- Which reviewers should run on this branch?
1014
-
1015
- A) Auto-detect from the diff (recommended) — review-orchestrator picks from changed files
1016
- B) Named domains — e.g. --backend --security, --frontend --testing-practices
1017
- C) Everything — --all
1018
- D) Skip review entirely
1019
-
1020
- > pick a letter
1021
- ```
1022
-
1023
- Then ask which optional convention reviewers to include when local convention docs or matching
1024
- paths are present:
1025
-
1026
- ```
1027
- Which project-convention reviewers should I include?
1028
-
1029
- A) Include all detected convention reviewers (recommended)
1030
- B) Choose individually
1031
- C) Skip convention reviewers
1032
-
1033
- Detected reviewers:
1034
- - review-frontend-conventions: frontend files / stories / local frontend guide
1035
- - review-testing-practices: tests, stories, MSW, or e2e files
1036
- - review-core-boundaries: shared core/infrastructure files
1037
- - review-flow-graph: shared graph/flow abstraction files
1038
- ```
1039
-
1040
- Which reviewers are even applicable is **detected, not eyeballed**:
1041
-
1042
- ```bash
1043
- keryx review stack --json
1044
- ```
1045
-
1046
- It reads `package.json` once and every installed review-category skill's declared
1047
- `metadata.stack_requires`, and reports per reviewer whether the requirement is met.
1048
- Show only what it includes, and carry its exclusions with their reasons into the
1049
- report — a reviewer silently absent reads as a reviewer that found nothing.
1050
-
1051
- **Auto-select** (skip these questions) when:
1052
- - `review_flags` is explicitly set in automation settings → use that
1053
- - `convention_reviewers` is explicitly set in automation settings → use that for optional convention reviewers
1054
- - User already chose at Post-Implementation Checkpoint (2.5.1 option A) → use auto-detect (A)
1055
-
1056
- The selection is held for this run and named in the dispatch. There is no
1057
- `convention_reviewers` field in `state.json` and nothing writes one; the choice is
1058
- carried in the dispatch prompt and reported in 2.9.
1059
-
1060
- #### 2.6.1 Execute the Round
1061
-
1062
- **Step 1 — check the budget before dispatching, while stopping is still possible.**
1063
-
1064
- ```bash
1065
- keryx review budget --spent <usd-so-far> --outstanding <subagents this orchestrator has in flight>
1066
- ```
1067
-
1068
- `--outstanding` is not optional here. `src/review/caps.ts` names `job-orchestrator`
1069
- as the outermost of the three nesting levels — `job-orchestrator` →
1070
- `flow-orchestrator` → `review-orchestrator` — that its cap of 4 in-flight reviewers
1071
- was chosen to survive. keryx is a CLI invoked once per command; it cannot observe
1072
- subagents running inside another orchestrator's process. **The cap binds the nested
1073
- total only when the parent declares its own in-flight count.** Omit `--outstanding`
1074
- and the cap bounds the reviewer fan-out alone, which the record then states plainly.
1075
-
1076
- A non-zero exit means the spend ceiling (3 USD by default) is reached: stop and ask
1077
- the user rather than dispatching another fan-out.
1078
-
1079
- **Step 2 — open a managed round.**
1080
-
1081
- ```bash
1082
- keryx review start --target branch --ref <feature-branch> --head "$(git -C <worktree> rev-parse HEAD)"
1083
- # reviewing an existing PR instead:
1084
- keryx review start --target pull-request --ref <pr-number> --head <pr-head-sha>
1085
- ```
1086
-
1087
- **A fix round is managed, not optional.** A round whose findings were never ingested
1088
- cannot be cited as a completed round, because nothing durable records what it found.
1089
-
1090
- **Step 3 — collect inbound PR comments, every round.**
1091
-
1092
- ```bash
1093
- keryx review comments collect --repo <owner/repo> --pr <n> --sha <head-sha> \
1094
- --self <our-login> --round <n> --out <JOBS_ROOT>/<job-name>/comments-r<n>.json
1095
- ```
1096
-
1097
- `--sha` is required and is the commit collected against; the completion gate compares
1098
- it to the PR head, so a collection that ran before the comments arrived reads as
1099
- stale rather than clean. Bot reviewers count as reviewers. Do **not** reply yet —
1100
- replies happen once, in 2.7, after the last round.
1101
-
1102
- **Step 4 — build both scopes.**
1103
-
1104
- ```bash
1105
- BASE_SHA="$(git -C <worktree> merge-base HEAD <base_branch>)"
1106
- keryx review scope --ref "$BASE_SHA" --json > <JOBS_ROOT>/<job-name>/scope.json
1107
- keryx review blast-radius --ref "$BASE_SHA" --json > <JOBS_ROOT>/<job-name>/blast-radius.json
1108
- ```
1109
-
1110
- Scope A (`review scope`) is the bounded diff, with every drop recorded and its reason.
1111
- Scope B (`review blast-radius`) is what the change can break — the regression set.
1112
- **Keep both files.** `review ingest --blast-radius <file>` is refused on any round that
1113
- dispatched `review-regression`, which is every recommended and full round, and an
1114
- ingest carrying a scope-B finding without the record is refused in code.
1115
-
1116
- **Step 5 — compute the model per dispatch, never by hand.**
1117
-
1118
- ```bash
1119
- keryx review tier --scope <scope> --diff-lines <n> --findings <n> [--security] [--verifier reasoning] --json
1120
- ```
1121
-
1122
- Paste the `model` block it prints into that dispatch. `model_strategy: "current"` is
1123
- gone: it meant "do not switch models", which is exactly the behaviour this command
1124
- replaced. The command names no model — it ranks what the provider reports at runtime
1125
- and, when it cannot rank anything, prints `inherit: true`, which means the dispatch
1126
- runs on the session model. That is a correct answer, not a failure.
1127
-
1128
- **Step 6 — dispatch `review-orchestrator`.**
1129
-
1130
- ```
1131
- Task({
1132
- description: "Review round <n>: <job-name>",
1133
- subagent_type: "general-purpose",
1134
- prompt: |
1135
- Load skill: skills/gdskills/review/review-orchestrator/SKILL.md
1136
-
1137
- flags: <selected flags, e.g. --backend --security --testing-practices>
1138
- commit_range: <BASE_SHA>..HEAD
1139
- issue_url: <issue URL, when the job has one — enables the Stage 1 spec gate>
1140
- context_doc: <JOBS_ROOT>/<job-name>/ai/context.md
1141
- verification_mode: annotate
1142
- managed_review: { mode: "review-flow", target: "branch", target_ref: "<feature-branch>" }
1143
- is_fix_round: <true on any round after the first>
1144
- pr_comments: { enabled: <true when a PR exists> }
1145
-
1146
- Emit the unified report AND the fenced ```json keryx:findings``` block.
1147
- Dispatch review-verifier (Wave C) over the consolidated findings and return
1148
- its verification claims as a file path.
1149
- })
1150
- ```
1151
-
1152
- **Step 7 — verification is part of the round, not an extra.** `review-orchestrator`
1153
- dispatches `review-verifier` in Wave C over the consolidated findings. The verifier
1154
- **runs something** and can only delete — it never raises a severity, adds a finding,
1155
- or rewrites one, and it never verifies a finding raised by the same reviewer. Its
1156
- claims are merged by the CLI, not by hand.
1157
-
1158
- **Step 8 — ingest the round.** This is what makes it citable.
1159
-
1160
- ```bash
1161
- keryx review ingest --report <path/to/review-report.md> --ref <feature-branch> \
1162
- --head "$(git -C <worktree> rev-parse HEAD)" \
1163
- --scope <JOBS_ROOT>/<job-name>/scope.json \
1164
- --blast-radius <JOBS_ROOT>/<job-name>/blast-radius.json \
1165
- --verifications <path/to/verifications.json> --verification-mode annotate \
1166
- --refuted <path/to/refuted.json> \
1167
- --spent <usd-so-far> --outstanding <subagents in flight>
1168
- ```
1169
-
1170
- An unrecognised option is **refused, not ignored** — a silently dropped flag writes
1171
- nothing and still reports success. `--refuted` carries findings this round raised and
1172
- then dismissed; without it the package keeps only the survivors of an unlogged triage.
1173
-
1174
- **Findings are the canonical shape.** One vocabulary, everywhere in this skill:
1175
-
1176
- - severities are `blocker`, `major`, `minor`, `info` — `review-finding.schema.json`;
1177
- - the report ends with **exactly one** fenced block whose info string is
1178
- ` ```json keryx:findings ` — ingest reads that block, not the prose, and a round
1179
- that emits only prose cannot seed the next one;
1180
- - `reviewer` is the reviewer that actually produced the finding, never the
1181
- orchestrator;
1182
- - identity for dedupe and for the stuck check is `dedupe_key` when the finding has
1183
- one, otherwise reviewer + file + symbol + problem — never the display id, which is
1184
- per-report.
1185
-
1186
- **Classify:**
1187
- ```
1188
- NEEDS_FIX = count(blocker) > 0 OR count(major) > 0
1189
- ```
1190
-
1191
- **Document:** record the report in the job package too, so the job and the review
1192
- record point at each other:
1193
-
1194
- ```bash
1195
- keryx job document <job-name> --type review --file <path/to/review-report.md>
1196
- ```
1197
-
1198
- #### 2.6.2 PR Review Report Publication
1199
-
1200
- If this job is reviewing an existing GitHub PR, or a PR number was resolved before the
1201
- review step, ask whether to publish the consolidated review report — after the round is
1202
- ingested and before any fix decisions.
1203
-
1204
- Ask unless automation settings explicitly set `publish_pr_review_report`:
1205
-
1206
- ```text
1207
- Publish the review report to the PR?
1208
-
1209
- A) Concise PR comment only
1210
- B) Concise PR comment + detailed AI markdown artifact (recommended for follow-up fixes)
1211
- C) Do not publish
1212
-
1213
- > pick a letter (default: C)
1214
- ```
1215
-
1216
- **Rules:**
1217
- - The PR comment and AI artifact must be written in English only, regardless of the chat language or reviewer output language.
1218
- - Default is C. Never publish to a PR without explicit user confirmation or `publish_pr_review_report: comment`, `publish_pr_review_report: comment-and-ai-artifact`.
1219
- - If the user chooses A, delegate concise comment formatting to `review-orchestrator`'s PR Review Report Publication contract.
1220
- - If the user chooses B, also generate `.metaproject/jobs/<job-name>/review-ai-report.md` using `review-orchestrator`'s Detailed AI Markdown Artifact contract, and include in the comment's `Meta` section both an `AI artifact` path and an `AI artifact description` row explaining that the file carries detailed findings, fix guidance, patch guidance, regression coverage, validation plan, and follow-up agent context.
1221
- - **If no PR exists yet**, do not ask now and do not stash a pending decision — nothing persists one. Ask this question again after the PR step (2.10) creates the PR, when the answer can actually be acted on.
1222
- - The decision is acted on immediately or not at all. There is no `publication_plan` field in `state.json`; what was published is stated in the 2.9 report.
1223
-
1224
- **Automation values:**
1225
- - `publish_pr_review_report: ask` -> ask the question above.
1226
- - `publish_pr_review_report: comment` -> publish the concise PR comment only.
1227
- - `publish_pr_review_report: comment-and-ai-artifact` -> publish the concise PR comment and create the detailed AI markdown artifact.
1228
- - `publish_pr_review_report: none` -> do not publish.
1229
-
1230
- #### 2.6.3 Post-Review Checkpoint
1231
-
1232
- After the round is ingested, present findings and ask the user:
1233
-
1234
- ```
1235
- Review round <n> complete:
1236
- 🔴 <N> blocker 🟠 <M> major 🟡 <K> minor 🔵 <L> info
1237
- verified: <V> claims recorded, <R> findings refuted
1238
- inbound PR comments this round: <C>
1239
-
1240
- A) 🔧 Auto-fix and continue (fix blocker + major)
1241
- B) 📋 Show all findings — I'll decide what to fix
1242
- C) ⏭ Skip fixes, proceed to PR as-is
1243
- D) ⏹ Stop — I'll fix manually
1244
- ```
1245
-
1246
- The counts come from the ingested package, not from re-reading the prose:
1247
-
1248
- ```bash
1249
- keryx review status <review-id-or-path>
1250
- ```
1251
-
1252
- **Mapping:**
1253
- - A → proceed to the FIX step (2.7)
1254
- - B → display all findings grouped by file, then re-ask A/C/D
1255
- - C → skip FIX, go to VERIFY (2.8) — allowed only when 0 blockers; refuse while a blocker stands
1256
- - D → close the open steps with a reason (2.1) and go to Phase 3
1257
-
1258
- Whichever branch is taken, **every finding still needs a disposition** before the
1259
- review can be completed — see 2.7. "Nobody chose to fix it" is `dismissed-wont-fix`
1260
- with evidence, not silence.
1261
-
1262
- **Auto-proceed** (skip this question) when:
1263
- - 0 findings → go straight to VERIFY (2.8)
1264
- - only `minor`/`info` findings → skip FIX, go to VERIFY (2.8)
1265
- - `auto_create_pr: true` → auto-select A
1266
-
1267
- ### 2.7 Step: FIX (conditional)
1268
-
1269
- Only runs if NEEDS_FIX is true. Default max: **3 iterations** (`max_review_iterations`).
1270
-
1271
- Three is the shared round bound: `task-implementer`, `flow-orchestrator` and
1272
- this skill all use it. *"The first three to four repair iterations account for
1273
- most achievable gains"* ([arXiv:2607.05197](https://arxiv.org/abs/2607.05197));
1274
- correctness falls **0.820 -> 0.673** across two forced revisions while
1275
- cumulative ever-correct is **0.847**
1276
- ([arXiv:2607.24604](https://arxiv.org/abs/2607.24604)). Aider hardcodes
1277
- `max_reflections = 3`; OpenHands' critic uses 3.
1278
-
1279
- The bound is a ceiling, not a target. Repetition ends the loop earlier and
1280
- **regardless of remaining iterations** — a counter cannot tell "converging
1281
- slowly" from "stuck", and an agent emitting the identical failing output three
1282
- times spends the whole budget before anything notices.
1283
-
1284
- **A finding leaves this loop by being dispositioned, never by being absent.** The
1285
- previous version of this section recomputed "unresolved" as whatever the next round
1286
- still reported — so a finding the next reviewer simply did not look at was recorded as
1287
- fixed. That is absence-as-evidence, and the completion gate refuses it.
1288
-
1289
- ```
1290
- UNRESOLVED_FINDINGS = all blocker + major findings from step 2.6
1291
- PREVIOUS_REVIEW_OUTPUT = <the ingested report from step 2.6>
1292
-
1293
- FOR iteration in [1, 2, 3]:
1294
- IF NOT NEEDS_FIX: BREAK
1295
-
1296
- keryx job step <job-name> fix --status in-progress # increments metrics.steps[].retries
1297
-
1298
- 1. Group UNRESOLVED_FINDINGS by file
1299
- 2. Construct fix prompt — MUST include unresolved findings from previous attempt:
1300
-
1301
- task_type: "fix"
1302
- findings: <UNRESOLVED_FINDINGS, in the canonical finding shape>
1303
- iteration: <N>
1304
- previously_unresolved: <findings that were in UNRESOLVED_FINDINGS last iteration but still present>
1305
- → Prefix: "These specific findings were NOT fixed in iteration <N-1>: [list]"
1306
-
1307
- 3. Launch task-implementer with the fix prompt (subagent_type: "general-purpose"),
1308
- on the model `keryx review tier --fix-attempt <N> --findings <n> --json` computes
1309
- 4. Run the sanity check (step 2.5.2 logic) — verify commits were made
1310
- 5. Run the next managed round — the FULL 2.6.1 sequence, not a bare re-dispatch:
1311
- keryx review budget --spent <usd> --outstanding <n>
1312
- keryx review start --target branch --ref <feature-branch> --head <new-head>
1313
- keryx review comments collect --repo <r> --pr <n> --sha <new-head> --round <N+1> --out <file>
1314
- keryx review scope --ref "$BASE_SHA" --json > scope.json
1315
- keryx review blast-radius --ref "$BASE_SHA" --previous blast-radius.json --json > blast-radius.json
1316
- <dispatch review-orchestrator with is_fix_round: true>
1317
- keryx review ingest --report <new-report> --ref <feature-branch> --head <new-head> \
1318
- --scope scope.json --blast-radius blast-radius.json \
1319
- --verifications <file> --refuted <file> --outstanding <n>
1320
- 6. Recompute NEEDS_FIX from the ingested findings
1321
- 7. Record what became of each finding raised in the PREVIOUS round — every one of
1322
- them, before the next iteration starts:
1323
-
1324
- keryx review complete <previous-review-id-or-path> \
1325
- --finding F-001 --disposition acted-on --evidence "fixed in <commit-sha>" \
1326
- --finding F-002 --disposition dismissed-incorrect --evidence "<what was run, what it showed>" \
1327
- --finding F-003 --disposition dismissed-out-of-scope --evidence "<decision, where written>"
1328
-
1329
- States: unknown, acted-on, dismissed-incorrect, dismissed-wont-fix,
1330
- dismissed-out-of-scope, dismissed-deprioritised. Everything except `unknown`
1331
- must cite where the outcome is written down. A recorded state and its citation
1332
- cannot be overwritten by a later close — record a correction as a new round.
1333
- Closing with no dispositions leaves every finding reading `unknown`, which means
1334
- "nobody wrote down what happened".
1335
- 8. UNRESOLVED_FINDINGS = the blocker + major findings of the NEW round that are
1336
- still without a terminal disposition
1337
-
1338
- 9. STUCK CHECK — runs before the next iteration and ignores the budget:
1339
- IF any finding identity is in UNRESOLVED_FINDINGS for the SECOND iteration
1340
- OR the new review output is identical to PREVIOUS_REVIEW_OUTPUT
1341
- THEN log "stuck: <what repeated>" and BREAK, even with iterations left.
1342
- Identity is the finding's dedupe_key when it has one, otherwise
1343
- reviewer + file + symbol + problem — never the display id, which is
1344
- per-report and would fire on every second iteration whatever happened.
1345
-
1346
- Detection is also available from the durable record rather than this
1347
- session's memory, which is the version that survives a restart:
1348
- keryx review loop --flow <flow-id>
1349
- It escalates with a non-zero exit on a recurring finding or two identical
1350
- consecutive rounds, regardless of the remaining budget.
1351
- 10. PREVIOUS_REVIEW_OUTPUT = the new ingested report
1352
-
1353
- keryx job step <job-name> fix --status completed
1354
-
1355
- AFTER THE LAST ROUND ONLY — answer every inbound PR comment, once:
1356
- keryx review comments reply --repo <owner/repo> --pr <n> --outcomes <file> \
1357
- --sha <head-sha> --final [--flow-link <url>]
1358
-
1359
- IF still NEEDS_FIX after max iterations, or the stuck check broke the loop:
1360
- Log "Unresolved after <N> iterations" with finding list, and say WHICH of the
1361
- two ended it — a budget exhausted and a loop detected call for different next
1362
- steps. Give every surviving finding a disposition (dismissed-wont-fix or
1363
- dismissed-deprioritised, with evidence) rather than leaving it `unknown`
1364
- → continue to VERIFY (2.8)
1365
- ```
1366
-
1367
- `comments reply` **refuses without `--final`**: replying per round turns one review
1368
- thread into six, and a reply written mid-loop states an intention rather than an
1369
- outcome. Each reply is cut in code to 2 sentences and 600 characters, threaded where
1370
- GitHub gives a thread, capped at 30 with one summary comment for the remainder.
1371
- `--dry-run` rehearses the whole pass without posting.
1372
-
1373
- **Fix prompt escalation pattern:**
1374
- - Iteration 1: "Fix these findings: [list]"
1375
- - Iteration 2: "These findings were NOT fixed in iteration 1: [subset]. Fix them now."
1376
- - Iteration 3: "FINAL attempt. These findings remain after 2 fix passes: [subset]. This is the last fix iteration."
1377
-
1378
- ### 2.8 Step: VERIFY (code-verifier)
1379
-
1380
- Dispatch `code-verifier` as a sub-agent. This is the quality gate; there is no separate
1381
- `CHECKS` step, and nothing in this document jumps to one.
1382
-
1383
- ```
1384
- Task({
1385
- description: "Quality gate: <job-name>",
1386
- subagent_type: "general-purpose",
1387
- prompt: |
1388
- You are code-verifier. Load skill: skills/gdskills/orchestration/code-verifier/SKILL.md
1389
-
1390
- codebase_path: <worktree_path>
1391
- base_branch: <base_branch>
1392
- scope: changed
1393
-
1394
- Run all 4 phases and return VERIFICATION_RESULT.
1395
- })
1396
- ```
1397
-
1398
- **Handle result:**
1399
- ```
1400
- IF VERIFICATION_RESULT.gate == "PASS" or "PASS_WITH_WARNINGS":
1401
- → Proceed to review
1402
- → Log findings as informational in the job report
1403
-
1404
- IF VERIFICATION_RESULT.gate == "FAIL":
1405
- → Extract blocker/major findings
1406
- → Check whether the fix step has already run:
1407
- keryx job status <job-name> --json # retries["fix"] is the recorded count
1408
- - If it has not → run the fix step (2.7) with these findings
1409
- - If `retries["fix"]` has reached 3 → escalate to the user and go to report.
1410
- Three is the bound, and it is the same three everywhere in this skill.
1411
- ```
1412
-
1413
- **Document result:** write the verification report, then record it:
1414
-
1415
- ```bash
1416
- keryx job document <job-name> --type verification-report --file <path/to/verification-report.md>
1417
- keryx job step <job-name> verify --status completed --reason "gate: <PASS|PASS_WITH_WARNINGS|FAIL>"
1418
- ```
1419
-
1420
- ### 2.8.1 Step: VERIFY-POST-FIX (code-verifier, conditional)
1421
-
1422
- After fix iterations, dispatch `code-verifier` again with identical parameters.
1423
-
1424
- ```
1425
- IF fix ran:
1426
- keryx job step <job-name> verify-post-fix --status in-progress
1427
- Dispatch code-verifier (same params as step 2.8)
1428
- IF gate still FAIL:
1429
- Log "Verification failed after fix" → go to report with a warning
1430
- IF gate PASS:
1431
- Proceed to report
1432
- keryx job document <job-name> --type verification-report --file <path/to/verification-post-fix.md>
1433
- keryx job step <job-name> verify-post-fix --status completed --reason "gate: <status>"
1434
-
1435
- IF fix did not run:
1436
- keryx job step <job-name> verify-post-fix --status skipped --reason "no fix round was needed"
1437
- ```
1438
-
1439
- ### 2.8.2 Step: PERF-CHECK (optional)
1440
-
1441
- Auto-trigger `perf-check` when frontend/bundle files were modified:
1442
-
1443
- ```
1444
- IF any modified file matches: *.tsx, *.jsx, *.css, *.scss, webpack.*, vite.*, next.config.*
1445
- AND project has build output (dist/, build/, .next/)
1446
- THEN:
1447
- Dispatch perf-check --bundle
1448
- Add findings to report (informational, not blocking)
1449
- ```
1450
-
1451
- Skip if no frontend files changed or no build output exists. Results are advisory — they don't block the PR. Either way the step is closed on the record:
1452
-
1453
- ```bash
1454
- keryx job step <job-name> perf-check --status completed|skipped --reason "<result or why it did not run>"
1455
- ```
1456
-
1457
- ### 2.8.3 Step: SKILL LEARNING (conditional)
1458
-
1459
- Close the self-learning loop (see `rules/core/skill-lifecycle.mdc`). Collect the
1460
- learning signals produced upstream:
1461
- - `skill_drift` fields from each task-implementer result (`stale:`/`missing:`).
1462
- - the `## Skill Learning` block from `review-orchestrator`.
1463
-
1464
- ```
1465
- IF no skill_drift and Skill Learning == none:
1466
- → skip this step (log "no skill drift")
1467
-
1468
- ELSE for each flagged project-skill:
1469
- 1. Dispatch a subagent to build the learning proposal:
1470
- - Model: COMPUTED, not chosen — run
1471
- keryx review tier --findings 1 --diff-lines 0 --json
1472
- and paste the `model` block into the dispatch. The command names no model:
1473
- it ranks what the provider reports at runtime, and when it cannot rank
1474
- anything it prints `inherit: true`, which means the dispatch runs on the
1475
- session model. See rules/core/model-selection.mdc for what the tiers mean.
1476
- - Command: keryx skills learn --from-review <review-report-path> \
1477
- --skill <module>/<skill>
1478
- (or --from-test / --from-failure when the signal came from verification)
1479
- - The subagent returns the proposal path. It does NOT apply.
1480
- 2. The orchestrator (flagship) reads the proposal and either:
1481
- - keryx skills learn apply <proposal.json> (accept), or
1482
- - discards it and notes why in the report.
1483
- ```
1484
-
1485
- Never apply a proposal unread, and never run `learn` in a hook. Record applied
1486
- skill updates in the Job Report under "Skill Updates".
1487
-
1488
- ### 2.9 Step: REPORT
1489
-
1490
- Aggregate all information into a human-readable summary.
1491
-
1492
- **Report structure:**
1493
- ```markdown
1494
- # Job Report: <Title>
1495
-
1496
- ## Summary
1497
- - **Intent:** <implement / analyze / review>
1498
- - **Source:** <issue URL or description>
1499
- - **Branch:** `<branch_name>`
1500
- - **Tasks:** <completed>/<total> completed
1501
- - **Review Rounds:** <N> (managed records: <review-id list>)
1502
- - **Final Status:** <READY FOR PR | HAS WARNINGS | HAS ISSUES | ANALYSIS ONLY>
1503
-
1504
- ## Analysis
1505
- <analysis summary>
1506
-
1507
- ## Tasks
1508
- ### task-1: <Name>
1509
- - **Status:** success
1510
- - **Files:** <list>
1511
- - **Commits:** <hashes>
1512
-
1513
- ## Review Results
1514
- Round <n> — `.metaproject/reviews/<review-id>/`
1515
- | Reviewer | blocker | major | minor | info |
1516
- |---|---|---|---|---|
1517
- | review-logic | <N> | <N> | <N> | <N> |
1518
- | … | | | | |
1519
-
1520
- Verification: <V> claims recorded, <R> findings refuted, <U> unverified.
1521
- Reviewers excluded by `keryx review stack`: <name — reason>.
1522
- Inbound PR comments: <C> collected, <A> answered in the final reply pass.
1523
-
1524
- ## Unresolved Issues
1525
- - [ ] <file>:<line> — <message> (from <reviewer>, disposition `<state>`, evidence `<ref>`)
1526
-
1527
- ## Final Checks
1528
- - Lint: PASS
1529
- - Type Check: PASS
1530
- - Tests: 42 passed, 0 failed
1531
-
1532
- ## Skill Updates
1533
- - `<module>/<skill>` v1.2.0 → v1.3.0 (from review F-012; applied) | none
1534
-
1535
- ## Changes Summary
1536
- ### Files Modified (<N>)
1537
- - `src/...`
1538
-
1539
- ### Files Created (<N>)
1540
- - `src/...`
1541
-
1542
- ### Commits (<N>)
1543
- - `abc1234` feat(pipelines): add validation
1544
- ```
1545
-
1546
- ### 2.10 Step: PR (conditional)
1547
-
1548
- Only runs if `create_pr` is true and intent is `implement`.
1549
-
1550
- **Dispatch `pr-issue-documenter` to generate the PR description:**
1551
-
1552
- Pass the following context to `pr-issue-documenter`:
1553
- ```
1554
- ACTION: generate-pr-description
1555
- JOB_NAME: <job-name>
1556
- BRANCH: <feature_branch>
1557
- BASE: <base_branch>
1558
- ISSUE_NUMBER: <issue_number if available>
1559
- CONTEXT_PATH: <JOBS_ROOT>/<job-name>/ai/context.md
1560
- ```
1561
-
1562
- `pr-issue-documenter` will analyze the branch diff and produce a structured PR description (Summary + Changes by area + Key Files table). Use its output as the `body` for the PR.
1563
-
1564
- **Enrich PR with changelog entry:**
1565
-
1566
- Dispatch `changelog` skill to generate a changelog snippet for this branch:
1567
- ```
1568
- changelog <base_branch>..HEAD --format compact
1569
- ```
1570
- Append the changelog snippet to the PR body under a `## Changelog` section.
1571
-
1572
- **Present to user:**
1573
- ```
1574
- Implementation complete. Draft PR proposal:
1575
-
1576
- Title: <type>(#<issue>): <description>
1577
- Base: <base> ← <head>
1578
-
1579
- <pr-issue-documenter output>
1580
-
1581
- ## Changelog
1582
- <changelog snippet>
1583
-
1584
- Create this draft PR? (yes/no/edit)
1585
- ```
1586
-
1587
- If user says "edit" → show the full body, let them modify before creating.
1588
-
1589
- **If confirmed:**
1590
- ```bash
1591
- gh pr create --title "<title>" --body "$(cat <<'EOF'
1592
- <body>
1593
- EOF
1594
- )" --base <base_branch> --head <feature_branch> --draft
1595
- ```
1596
-
1597
- Then record the step, with the PR on the record:
1598
-
1599
- ```bash
1600
- keryx job step <job-name> pr --status completed --reason "<PR URL>"
1601
- ```
1602
-
1603
- If the job had review findings but no PR until now, ask the 2.6.2 publication
1604
- question here — this is the point at which it can be acted on.
1605
-
1606
- ---
1607
-
1608
- ## Phase 3: COMPLETION
1609
-
1610
- ### 3.1 Close the Job Package
1611
-
1612
- ```bash
1613
- keryx job complete <job-name>
1614
- ```
1615
-
1616
- This is a **gate, not a formality.** It refuses while any step is still open or
1617
- `failed`, and the refusal names them:
1618
-
1619
- ```
1620
- Cannot complete job <name> — 12/15 steps terminal (not terminal: perf-check, deploy; failed: fix).
1621
- Close each with: keryx job step <name> <step-id> --status completed|skipped [--reason "<why>"]
1622
- ```
1623
-
1624
- So close every remaining step first, with a reason that says what happened:
1625
-
1626
- ```bash
1627
- keryx job step <job-name> deploy --status skipped --reason "user declined the staging deploy"
1628
- ```
1629
-
1630
- A job that ended badly is closed the same way — each unfinished step recorded as
1631
- `skipped` with the reason it stopped. There is no "aborted" status to set: what
1632
- happened is in the step statuses and in `journal.md`, which is a record, not a label.
1633
-
1634
- On success the package moves to `phase: COMPLETION` and `plan.current_step` is
1635
- cleared, so 0.0 will no longer offer it for resumption.
1636
-
1637
- ### 3.2 Present Results
1638
-
1639
- Tell user:
1640
- 1. What was accomplished (summary)
1641
- 2. Where the package is: `.metaproject/jobs/<job-name>/`
1642
- 3. PR URL (if created)
1643
- 4. Step durations and retries, read from the package
1644
- 5. Any unresolved issues, each with its recorded disposition
1645
-
1646
- ```
1647
- ✅ Job completed successfully.
1648
-
1649
- Package: <JOBS_ROOT>/<job-name>/
1650
- Branch: feature/<slug> (worktree: <path>)
1651
- PR: <URL or "not created">
1652
- Review: <N> managed rounds, .metaproject/reviews/<review-id>/
1653
- Steps: <done>/<total>, retries <sum>
1654
-
1655
- keryx job status <job-name> — the step list, retries and recorded documents
1656
- <JOBS_ROOT>/<job-name>/journal.md — every recorded event, in order
1657
- ```
1658
-
1659
- ### 3.3 Post-Completion Options
1660
-
1661
- After presenting results, offer next steps:
1662
-
1663
- ```
1664
- What would you like to do next?
1665
-
1666
- A) ✅ Done — nothing else needed
1667
- B) 🚀 Deploy to staging — run /deploy staging
1668
- C) 🔄 Start another job
1669
- D) 📝 Update CLAUDE.md with session learnings
1670
- ```
1671
-
1672
- - B → dispatch `deploy` skill with `staging` environment
1673
- - D → dispatch `claude-md-management` skill
1674
-
1675
- **Auto-skip** if the job was `analyze` or `review` intent (no deploy makes sense).
1676
-
1677
- ---
1678
-
1679
- ## Plan Extension (Dynamic Planning)
1680
-
1681
- When the orchestrator starts with an `analyze` intent and the user then says "yes, implement":
1682
-
1683
- 1. **Keep the existing package** — its completed steps (analyze, context, report) stay
1684
- completed and stay on the record.
1685
- 2. **Create the implementation package** and run it as an `implement` job:
1686
-
1687
- ```bash
1688
- keryx job init --name <analysis-job-name>-impl --intent implement --project <project_dir>
1689
- ```
1690
-
1691
- `keryx job` does not rewrite a package's plan after `init`, and this skill does not
1692
- ask it to: a plan that could be rewritten in place is a plan whose recorded history
1693
- cannot be trusted. The two packages are linked by naming and by a journal line:
1694
-
1695
- ```bash
1696
- keryx job step <analysis-job-name> proposal --status completed \
1697
- --reason "user accepted; implementation continues in job <analysis-job-name>-impl"
1698
- ```
1699
- 3. **Complete the analysis job** (`keryx job complete <analysis-job-name>`) once its
1700
- steps are closed, so it stops being offered for resumption in 0.0.
1701
- 4. **Continue execution** from Phase 1.3 of the new package.
1702
-
1703
- This is the core of dynamic planning — the work grows based on user decisions, and each
1704
- stage keeps its own auditable package rather than one package quietly changing shape.
1705
-
1706
- ---
1707
-
1708
- ## State Management
1709
-
1710
- There are two kinds of state, and confusing them is how a job loses its record.
1711
-
1712
- **Persisted — written by `keryx job`, survives the session.** This is exactly what
1713
- `state.schema.json` declares and exactly what the six commands write. The root carries
1714
- `additionalProperties: false`, so a field that is not on this list cannot be stored:
1715
-
1716
- ```
1717
- state.json:
1718
- phase: CONTEXT | PLAN | EXECUTION | COMPLETION (job init, job step, job complete)
1719
- intent: implement | analyze | review | custom (job init)
1720
- job_name: <slug matching ^[a-z0-9-]+$> (job init)
1721
- create_pr: <bool>
1722
- context:
1723
- project_dir: <path> (job init --project)
1724
- base_branch: <string>
1725
- issue: { number, title, url, type }
1726
- plan:
1727
- steps: [{ id, type, agent, depends, conditional,
1728
- status: pending|in_progress|completed|skipped|failed }] (job step)
1729
- current_step: <first step that is not terminal> (maintained by job step)
1730
- documentation:
1731
- job_path: .metaproject/jobs/<job-name>
1732
- documents_created: [<file name per recorded document>] (job document)
1733
- metrics:
1734
- steps: [{ step_id, status, started_at, completed_at, duration_ms, retries }] (job step)
1735
- jobs_root: .metaproject/jobs
1736
- updated_at: <ISO 8601, stamped on every write>
1737
- ```
1738
-
1739
- `journal.md` sits beside it: append-only, one timestamped line per event, with the
1740
- `--reason` text where one was given. Between the two, "what happened to this job" is
1741
- answerable without this session.
1742
-
1743
- **In-session — held by the orchestrator for this run, and NOT persisted.** Say it in
1744
- the dispatch prompt, or it does not reach the sub-agent:
1745
-
1746
- ```
1747
- branch: { name, worktree_path, merge_base, package_manager, run_command }
1748
- analysis: { total_tasks, tasks, dependency_order }
1749
- context_doc: the path to the job's ai/context.md
1750
- review: the current round's findings — the durable copy is the managed review
1751
- package, not this
1752
- ```
1753
-
1754
- Five fields this skill used to claim it recorded — `sanity_check`,
1755
- `convention_reviewers`, `publication_plan.mode`, `pending_pr_review_report_comment`,
1756
- `pending_review_ai_artifact` — are **not** persisted and are not in the schema. Nor is
1757
- a `paused` or `timeout` status. Nothing writes them, so nothing claims them: what would
1758
- have gone into them goes into a `--reason` on the journal, or into the 2.9 report.
1759
-
1760
- ---
1761
-
1762
- ## state.json Specification
1763
-
1764
- **Location:** `.metaproject/jobs/<job-name>/state.json`
1765
-
1766
- **Schema:** `skills/gdskills/orchestration/job-orchestrator/state.schema.json`, registered
1767
- as the contract `job-orchestrator-state`.
1768
-
1769
- **Who writes it:** `keryx job`, and nothing else. Every write is validated against the
1770
- registered contract first and a non-conforming state is **refused**, not written:
1771
-
1772
- ```
1773
- Refusing to write .metaproject/jobs/<name>/state.json — it does not validate against
1774
- job-orchestrator-state:
1775
- - /plan/steps/0/status: must be one of pending, in_progress, completed, skipped, failed
1776
- ```
1777
-
1778
- **Do not hand-write it.** No `cat > state.json`, no `jq` edit, no sub-agent writing it
1779
- directly. A hand-written state bypasses the validation and the journal, which is how a
1780
- package ends up describing a job that did not happen.
1781
-
1782
- Validate any state file against the contract directly if you need to:
1783
-
1784
- ```bash
1785
- keryx skills contracts validate .metaproject/jobs/<job-name>/state.json --schema job-orchestrator-state
1786
- ```
1787
-
1788
- **When it is written:**
1789
-
1790
- | Command | What it changes |
1791
- |---|---|
1792
- | `keryx job init` | creates the package, the plan, `phase: PLAN` |
1793
- | `keryx job step` | a step's status, `plan.current_step`, `metrics.steps[]` (including `retries`), `phase: EXECUTION` |
1794
- | `keryx job document` | `documentation.documents_created`, and copies the file in |
1795
- | `keryx job complete` | `phase: COMPLETION`, clears `plan.current_step` — refused unless every step is terminal |
1796
-
1797
- **Job resumption (Phase 0.0):** `keryx job list --json` finds packages whose `phase` is
1798
- not `COMPLETION`; `keryx job status <name> --json` names `next_step` — the first step
1799
- that is neither `completed` nor `skipped`. Both answers are computed from the file, so
1800
- a resumed session does not depend on remembering where it was.
1801
-
1802
- ---
1803
-
1804
- ## Interpreting Subagent Results
1805
-
1806
- **Rule:** `rules/core/subagent-status-protocol.md`
1807
-
1808
- All subagents dispatched by this orchestrator MUST begin their final response with `STATUS: <STATUS>`. The orchestrator reads this line first and routes accordingly.
1809
-
1810
- ### Iron Law
1811
-
1812
- **IF A SUBAGENT DOES NOT START WITH `STATUS:`, TREAT IT AS `NEEDS_CONTEXT` AND REQUEST A PROPERLY FORMATTED RESPONSE**
1813
-
1814
- Do not attempt to infer status from prose. Do not trust a response that "looks fine" but lacks the status line. Run one explicit retry: "Your response did not start with STATUS: <STATUS>. Please reformat using the subagent status protocol (rules/core/subagent-status-protocol.md) and resend your result."
1815
-
1816
- ### How to handle each status
1817
-
1818
- **`STATUS: DONE`**
1819
- - Accept result.
1820
- - Extract structured payload (JSON result, files changed, commits, verification results).
1821
- - Record it: `keryx job step <job-name> <step-id> --status completed`.
1822
- - Continue to next step in the plan.
1823
-
1824
- **`STATUS: DONE_WITH_CONCERNS`**
1825
- - Accept result as complete.
1826
- - Read the `## Concerns for orchestrator` section carefully.
1827
- - Decide: (a) log concern and continue, (b) surface concern to user at next checkpoint, or (c) re-dispatch with adjusted scope if the concern affects correctness.
1828
- - Do NOT silently discard concerns. Put them on the record and include them in the final report:
1829
- `keryx job step <job-name> <step-id> --status completed --reason "<the concern>"`
1830
- — the reason lands in `journal.md`, so the concern outlives the session.
1831
-
1832
- **`STATUS: BLOCKED`**
1833
- - Do NOT proceed to any step that depends on this task.
1834
- - Read `## Reason` and `## What I need from orchestrator`.
1835
- - Resolve the blocker: provide the missing file, make the decision, fix the dependency, or escalate to the user.
1836
- - Re-dispatch the subagent with the resolved context.
1837
- - If the blocker cannot be resolved (e.g., missing information requires user input) → surface to user: "Task <id> is blocked: <reason>. What would you like to do?"
1838
-
1839
- **`STATUS: NEEDS_CONTEXT`**
1840
- - Do NOT mark step as failed.
1841
- - Read `## Missing information` and `## Where it might be found`.
1842
- - Locate the missing information (check job context document, issue body, package.json, codebase).
1843
- - Re-dispatch the subagent with the enriched task input.
1844
- - If the information is not available anywhere → escalate to user with the specific question.
1845
-
1846
- ### Red Flag
1847
-
1848
- **"The subagent didn't use the status protocol, but the result looks fine"**
1849
-
1850
- Do not accept this. A subagent that ignores the status protocol is unpredictable — its next failure may not look fine. Enforce the protocol on every response. Run the retry. If the subagent still does not comply after the retry, log it as a critical failure and ask the user how to proceed.
1851
-
1852
- ---
1853
-
1854
- ## Constructing Subagent Context
1855
-
1856
- **Rule:** `rules/core/subagent-context-construction.md`
1857
-
1858
- Every prompt dispatched to a subagent must be **explicitly constructed** by the orchestrator. Subagents do not inherit session context, job state, or prior agent output — they only know what the orchestrator tells them.
1859
-
1860
- ### Template dispatch block
1861
-
1862
- Use this structure for every subagent dispatch:
1863
-
1864
- ```
1865
- Task({
1866
- description: "<one-line summary for logs>",
1867
- subagent_type: "general-purpose",
1868
- prompt: |
1869
- ## Task
1870
- <Exactly what to do — no ambiguity>
1871
-
1872
- ## Acceptance Criteria
1873
- - <criterion 1>
1874
- - <criterion 2>
1875
-
1876
- ## Context
1877
- <Only what is relevant for THIS task — decisions, constraints, background>
1878
-
1879
- ## Files to read
1880
- - <absolute/path/to/file1.ts>
1881
- - <absolute/path/to/file2.ts>
1882
-
1883
- ## Constraints
1884
- - Do NOT modify <file or pattern>
1885
- - <other hard stops>
1886
- })
1887
- ```
1888
-
1889
- `subagent_type` is **`general-purpose`**. That is the dispatcher's own name for a
1890
- general agent; `"general"` is not a value any dispatcher accepts, and a dispatch
1891
- carrying it does not run.
1892
-
1893
- ### Minimality principle
1894
-
1895
- Pass only what the subagent needs for this specific task. Do not dump job state, full analysis JSON, or conversation history. Extraneous context fills the subagent's context window with noise and increases hallucination risk.
1896
-
1897
- Each subagent type gets scoped context:
1898
- - `issue-analyzer` — issue data + codebase paths only
1899
- - `context-collector` — focus areas + analysis summary (not full analysis JSON)
1900
- - `task-implementer` — its specific task object + `CONTEXT_PATH` (not other tasks' data)
1901
- - Reviewers — diff range + file list (not implementation details)
1902
-
1903
- ### Red Flag
1904
-
1905
- **"The subagent can read the job state.json if it needs more context"**
1906
-
1907
- → Iron Law: **Orchestrator constructs context. Subagents receive, not retrieve.**
1908
-
1909
- The subagent must not fetch orchestrator state independently. If the subagent needs information, the orchestrator puts it in the dispatch prompt. A subagent reading `state.json` on its own is a sign the orchestrator dispatch was incomplete.
1910
-
1911
- ---
1912
-
1913
- ## Automation Settings
1914
-
1915
- | Setting | Default | Options | Description |
1916
- |---------|---------|---------|-------------|
1917
- | `skip_confirmation` | `true` | `true` only | Sub-agents run without per-dispatch confirmation. `{"const": true}` in the input contract. Does **not** cover the 0.4 operator gate — that one is `plan_approval`. |
1918
- | `base_branch` | auto-detect | any | Base branch (auto-detect from repo default, or ask user). No default in the contract. |
1919
- | `max_review_iterations` | `3` | 1-3 | Max review → fix iterations. Three everywhere: this table, 2.7, and the input contract's `maximum` and `default`. |
1920
- | `create_pr` | `true` | true/false | Whether to propose PR at the end |
1921
- | `auto_create_pr` | `false` | true/false | Auto-create PR without asking |
1922
- | `review_flags` | auto-detect | `review-orchestrator` flags | Reviewer selection passed to `review-orchestrator` (e.g. `--backend --security`). Unset means auto-detect from the diff. |
1923
- | `convention_reviewers` | `"ask"` | `"ask"` / `"all"` / `"none"` / skill names | Optional convention reviewers to include in review |
1924
- | `verification_mode` | `annotate` | `off`/`annotate`/`filter` | Passed to `review-orchestrator` and to `review ingest --verification-mode` |
1925
- | `run_final_checks` | `true` | true/false | Run lint/type-check/test |
1926
- | `run_interview` | `true` | true/false | Run interview skill in Phase 0 |
1927
- | `dry_run` | `false` | true/false | Plan-only mode: full Phase 0+1, no agent dispatch or git ops |
1928
- | `plan_approval` | `true` | true/false | Show agent plan and ask approve/adjust before execution (1.3) |
1929
- | `run_test_gen` | `true` | true/false | Auto-run test-gen if implementer skips tests |
1930
- | `run_security_audit` | `true` | true/false | Auto-run security-audit if auth/API/DB files touched |
1931
- | `run_perf_check` | `true` | true/false | Auto-run perf-check if frontend/bundle files changed |
1932
- | `run_changelog` | `true` | true/false | Auto-generate changelog entry and include in PR description |
1933
- | `publish_pr_review_report` | `ask` | `ask`/`comment`/`comment-and-ai-artifact`/`none` | Whether to publish a concise PR review comment and optional detailed AI markdown artifact |
1934
- | `run_deploy` | `ask` | `ask`/`true`/`false` | Post-PR deploy: ask user (ask), always deploy (true), never (false) |
1935
-
1936
- `review_mode` is gone. It defaulted to `"code-review"` — a skill that is not bundled
1937
- and not catalogued — and its `"individual"` alternative named the legacy hand-dispatch
1938
- path 2.6 replaced. Reviewer selection is `review_flags`, and the reviewers are
1939
- `review-orchestrator`'s.
1940
-
1941
- ## Dry-Run Mode
1942
-
1943
- When `dry_run: true` is set (or `--dry-run` is passed):
1944
-
1945
- 1. **Phase 0** runs fully — context collection, interviewer (if applicable), summary + confirm
1946
- 2. **Phase 1** runs fully — plan is built and displayed with step tree
1947
- 3. **Phase 2 is skipped entirely** — no sub-agents dispatched, no git operations
1948
- 4. **Output:** Full plan tree with agent names, input data shapes, dependencies:
1949
-
1950
- ```
1951
- Dry-run plan for: issue-4141--pipeline-validation
1952
- ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
1953
- Step 1: analyze [issue-analyzer] → input: issue #4141
1954
- Step 2: context [context-collector] → input: analysis result, project_dir
1955
- Step 3: prepare [orchestrator] → creates: feature/pipeline-validation worktree
1956
- Step 4: tests-creator [tests-creator × 3] → RED stubs, one per task
1957
- Step 5: implement [task-implementer × 3] → wave-parallel, 3 tasks
1958
- Step 6: sanity-check [orchestrator] → verifies commits exist
1959
- Step 7: verify [code-verifier] → lint + type-check + test + imports
1960
- Step 8: review [review-orchestrator] → managed round, ingested
1961
- Step 9: security [security-audit] → conditional: auth/API/DB/env files
1962
- Step 10: fix [task-implementer] → conditional: if NEEDS_FIX
1963
- Step 11: verify-post-fix [code-verifier] → conditional: after fix
1964
- Step 12: perf-check [perf-check] → conditional: frontend/bundle files
1965
- Step 13: report [orchestrator] → aggregates all results
1966
- Step 14: pr [orchestrator + gh CLI] → conditional: if create_pr
1967
- Step 15: deploy [deploy] → conditional: if user asks
1968
- ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
1969
- Estimated sub-agent calls: 11-14 (varies with tasks and review findings)
1970
- No changes will be made. Use without --dry-run to execute.
1971
- ```
1972
-
1973
- 5. Ask user: "Execute this plan? (yes / adjust / abort)"
1974
-
1975
- ## Budget Guards
1976
-
1977
- **There are no timeouts, because this execution model has no clock.** This skill runs
1978
- as a model inside a turn-based session: it cannot observe wall-clock time passing, it
1979
- cannot kill a sub-agent mid-flight, and it has no persisted start time to measure
1980
- against. A `step_timeout_ms` that "kills the agent if exceeded" was a guard nothing
1981
- could ever enforce, and a job could not end with a `timeout` status because no such
1982
- status exists in `state.schema.json`.
1983
-
1984
- What actually bounds this orchestrator:
1985
-
1986
- | Guard | Bound | Where it is enforced |
1987
- |-------|-------|----------------------|
1988
- | review → fix rounds | 3 | 2.7, and `max_review_iterations` (`maximum: 3`) in the input contract |
1989
- | repetition, whatever the count says | first repeat | the STUCK CHECK in 2.7, and `keryx review loop` against the durable record |
1990
- | retries per step | recorded, not guessed | `metrics.steps[].retries`, incremented by `keryx job step --status in-progress` and read back with `keryx job status --json` |
1991
- | reviewer fan-out | 4 in flight | `keryx review budget --outstanding <n>` before every dispatch (2.6.1) |
1992
- | spend | 3 USD by default | `keryx review budget --spent <usd>` — a non-zero exit means stop and ask |
1993
-
1994
- Each of these is a number some command reads or writes. A guard no command can
1995
- observe is not a guard; this section lists only observable ones.
1996
-
1997
- **Context passing rules (minimal context principle):**
1998
- - `issue-analyzer`: receives only issue data + codebase paths (NOT previous job state)
1999
- - `context-collector`: receives focus areas + analysis summary (NOT full analysis JSON)
2000
- - `task-implementer`: receives only its specific task object + context.md path (NOT other tasks' results)
2001
- - Reviewers: receive only the diff range + file list (NOT implementation details)
2002
-
2003
- ---
2004
-
2005
- ## Error Handling
2006
-
2007
- Each step failure is classified into one of three classes with different recovery paths:
2008
-
2009
- | Class | Meaning | Action |
2010
- |-------|---------|--------|
2011
- | `terminal` | Unrecoverable — cannot continue | ABORT immediately, surface actionable message |
2012
- | `retryable` | Transient failure — malformed output, an unusable reply, a command that failed on something transient | Auto-retry up to 2× with **identical prompt**, re-opening the step each time so `retries` counts it. After 2 failures → escalate to `recoverable` |
2013
- | `recoverable` | Partial success or skippable failure | Ask user with specific "continue from here / skip step / abort" options |
2014
-
2015
- ### Error Table
2016
-
2017
- | Error | Class | Action |
2018
- |-------|-------|--------|
2019
- | Issue not found (404) | `terminal` | ABORT — issue-analyzer reports 404 |
2020
- | Analysis returns 0 tasks | `recoverable` | Try smart fallback: (1) re-read issue with broader scope, (2) ask user to clarify, (3) if still 0 → ABORT |
2021
- | Branch/worktree creation fails | `terminal` | ABORT — report git error. NEVER fall back to `git checkout -b` |
2022
- | Interviewer `ready_to_proceed: false` | `terminal` | STOP — tell user which blockers remain |
2023
- | Sub-agent returns malformed JSON | `retryable` | Retry with: "Output was malformed. Fix: [errors]. Try again." (max 2×) |
2024
- | Sub-agent returns nothing usable | `retryable` | Re-open the step (`job step --status in-progress`, which counts the retry) and re-dispatch the identical prompt (max 2×) |
2025
- | Task implementation fails | `recoverable` | Ask: "Step failed. Continue remaining tasks / skip this task / abort?" |
2026
- | `keryx job` refuses a write | `terminal` | The message names the field that failed validation. Fix the input; do NOT hand-write `state.json` to route around it. |
2027
- | `keryx job complete` refuses | `recoverable` | It names the open and failed steps. Close each with `job step --status completed\|skipped --reason "<why>"`. |
2028
- | `keryx review ingest` refuses a scope-B finding | `terminal` for that round | Recompute `keryx review blast-radius --json` and re-ingest with `--blast-radius`. The round is not recordable until the set is supplied. |
2029
- | All reviewers fail | `recoverable` | Record the round as failed with a reason, add a warning to the report, continue to VERIFY (2.8) |
2030
- | Fix loop exceeds max_review_iterations | `recoverable` | Disposition every surviving finding, log which ended the loop, continue to VERIFY (2.8) |
2031
- | Final checks fail | `recoverable` | Include in report, still propose PR (user decides) |
2032
- | gh CLI not available | `recoverable` | Print PR data, user creates manually. `keryx review comments` needs it too — say so rather than reporting `0 outstanding`. |
2033
-
2034
- ### Retry Protocol (for `retryable` errors)
2035
-
2036
- ```
2037
- attempt 1: keryx job step <job-name> <step-id> --status in-progress
2038
- run step normally
2039
- → failure: classify error
2040
- → if retryable: keryx job step <job-name> <step-id> --status in-progress # retries += 1
2041
- retry with the EXACT same prompt + "Fix these errors: [list]"
2042
- → if fails again: escalate to recoverable → ask user
2043
- → if success: keryx job step <job-name> <step-id> --status completed
2044
- ```
2045
-
2046
- **Critical:** on retry, re-send the **same prompt** — hold it for the duration of the
2047
- step and re-send it verbatim. Never re-derive it; re-derivation causes drift.
2048
-
2049
- The prompt itself is **not** persisted: `keryx job` writes no `step.prompt` and no
2050
- prompt size, so do not instruct a resuming session to read one. What *is* persisted is
2051
- that the attempt happened — `metrics.steps[].retries`, incremented every time the step
2052
- re-enters `in_progress`, and the `--reason` line in `journal.md`. A resumed session
2053
- therefore knows how many attempts a step has had, which is the fact the retry budget
2054
- needs, and reconstructs the prompt from the plan and the analysis exactly as the first
2055
- attempt did.
2056
-
2057
- ---
2058
-
2059
- ## Progress Notifications
2060
-
2061
- The orchestrator must keep the user informed during long-running execution. This is especially important for non-interactive channels (Telegram, Slack, CI).
2062
-
2063
- **At each phase transition:**
2064
- ```
2065
- 🔄 Phase 0 → Phase 1: Building execution plan...
2066
- 🔄 Phase 1 → Phase 2: Executing 7 steps...
2067
- ✅ Phase 2 → Phase 3: Execution complete, generating report...
2068
- ```
2069
-
2070
- **At each step transition (Phase 2):**
2071
- ```
2072
- 📋 Job: issue-4141--pipeline-validation
2073
- ├─ ✅ Analyze issue — 3 tasks found
2074
- ├─ ✅ Collect context — context.md ready
2075
- ├─ ✅ Prepare branch — feature/pipeline-validation
2076
- ├─ 🔄 Implement (2/3 tasks done)
2077
- │ ├─ ✅ task-1: Add validation schema
2078
- │ ├─ ✅ task-2: Implement validator
2079
- │ └─ 🔄 task-3: Add integration tests...
2080
- ├─ ⏳ Verify
2081
- ├─ ⏳ Review
2082
- ├─ ⏳ Fix (if needed)
2083
- └─ ⏳ PR
2084
- ```
2085
-
2086
- **Notify at every step boundary** — before dispatching and after recording the result.
2087
- Those are the moments this skill actually regains control, so they are the only moments
2088
- it can say anything; a "notify every 30 seconds" rule would need a timer nothing here
2089
- has. `keryx job status <job-name>` renders the same tree from the package, which is
2090
- what to show a user who asks mid-run.
2091
-
2092
- **If notification tools are unavailable** (no MCP, no Telegram): fall back to inline text output between steps.
2093
-
2094
- ---
2095
-
2096
- ## Rules of Engagement
2097
-
2098
- Everything this orchestrator does is described once, with its reason, in the
2099
- section that owns it. This section is not a second copy of that. It carries the
2100
- three rules stated nowhere else, and the four whose cost, when you get them
2101
- wrong, cannot be undone by trying again.
2102
-
2103
- ### Stated only here
2104
-
2105
- - **Do not ask the user anything between Phase 0 and completion.** Two
2106
- exceptions: a critical failure, and a decision to extend the plan (analyze →
2107
- implement). Everything else was settled in Phase 0, or is settled by the
2108
- package rather than by asking.
2109
- - **Do not push the branch until the user confirms**, unless `auto_create_pr` is
2110
- set. A push is visible to everyone watching the repository, and there is no
2111
- version of un-pushing it that they do not see.
2112
- - **Say where the job package is when the job ends.** It is the only durable
2113
- record of the run, and a user who cannot find it is left with nothing to read.
2114
-
2115
- ### Unrecoverable if wrong
2116
-
2117
- - **Branch with `git worktree add`** — never `git checkout -b` or
2118
- `git switch -c`. Those switch the main working directory out from under the
2119
- user's own session, mid-run.
2120
- - **Run every later command in the worktree directory**, not the project root.
2121
- A build, test or commit that lands in the wrong tree is attributed to work
2122
- nobody did.
2123
- - **`keryx job` is the only writer of `state.json`**, this orchestrator
2124
- included. It validates each write against the `job-orchestrator-state`
2125
- contract; a hand-written file satisfies no contract, and the next session
2126
- resumes into a state that never existed.
2127
- - **Ask for the project directory in Phase 0.** There is no default. A wrong
2128
- guess writes a job package into somebody else's repository.
2129
-
2130
- ---
2131
-
2132
- ## Configurable Jobs Root
2133
-
2134
- `JOBS_ROOT` in this document is shorthand for **`.metaproject/jobs`, relative to the
2135
- project directory** — and that is the only value it takes. `keryx job` resolves it from
2136
- the working directory and records it in `state.json → jobs_root`; there is no
2137
- environment variable and no override, so do not tell a sub-agent to look one up.
2138
-
2139
- ```bash
2140
- JOBS_ROOT=".metaproject/jobs"
2141
- ```
2142
-
2143
- The project directory is the one collected in Phase 0.2 and passed as
2144
- `keryx job init --project <path>`. Run `keryx job` commands from that directory, and
2145
- expand `<JOBS_ROOT>` to the literal path when writing a sub-agent prompt — a subagent
2146
- receives paths, it does not resolve them.
2147
-
2148
- ---
2149
-
2150
- ## Post-Mortem (for failed/aborted jobs)
2151
-
2152
- When a job ends with a step recorded `failed`, or with unresolved blocker findings:
2153
-
2154
- 1. **Auto-generate post-mortem** document. The timeline is not recalled — it is read
2155
- off `journal.md`, which `keryx job` timestamped as the job ran, and the retry counts
2156
- come from `keryx job status <job-name> --json`:
2157
-
2158
- ```markdown
2159
- # Post-Mortem: <job-name>
2160
-
2161
- ## Timeline
2162
- (from .metaproject/jobs/<job-name>/journal.md — every line as recorded)
2163
- - <ISO timestamp> - created
2164
- - <ISO timestamp> - step: implement in-progress (retries 0)
2165
- - <ISO timestamp> - step: implement in-progress (retries 1)
2166
- - <ISO timestamp> - step: implement failed (retries 1) — <reason>
2167
-
2168
- ## What Went Wrong
2169
- - <Step name> failed with: <error class> — <error message>
2170
- - Recorded retries: <metrics.steps[].retries>
2171
- - Root cause hypothesis: <analysis>
2172
-
2173
- ## What Worked
2174
- - <N> tasks completed successfully
2175
- - Context collection was accurate
2176
-
2177
- ## Recommendations for Retry
2178
- - Fix <specific issue> before re-running
2179
- - Consider splitting task-3 into smaller subtasks
2180
- ```
2181
-
2182
- 2. Save to `.metaproject/jobs/<job-name>/post-mortem.md`
2183
- 3. Include in final user message: "Post-mortem saved to `.metaproject/jobs/<job-name>/post-mortem.md`"
2184
-
2185
- There is no `aborted` or `timeout` job status to key this on and nothing writes one.
2186
- The trigger is what the package says: a `failed` step, or findings still without a
2187
- terminal disposition.
2188
-
2189
- ---
2190
-
2191
- ## Metrics Collection
2192
-
2193
- `keryx job step` writes a metrics row per step. Nothing here is collected by hand.
2194
-
2195
- **Written per step, into `state.json → metrics.steps[]`:**
2196
- ```json
2197
- {
2198
- "step_id": "implement",
2199
- "status": "completed",
2200
- "started_at": "2026-08-30T10:30:00.000Z",
2201
- "completed_at": "2026-08-30T10:35:22.000Z",
2202
- "duration_ms": 322000,
2203
- "retries": 0
2204
- }
2205
- ```
2206
-
2207
- - `started_at` is stamped every time the step enters `in_progress`.
2208
- - `retries` counts attempts **beyond the first**: the first `--status in-progress`
2209
- leaves it at 0 and every re-entry adds one. It is on disk, so a resumed session
2210
- reads the real count instead of restarting at zero.
2211
- - `duration_ms` is `completed_at - started_at` for the last attempt.
2212
- - `total_tokens` is declared in the schema and **nothing writes it**. Do not report a
2213
- token figure as if it came from the package; if you have one, say where it came from.
2214
-
2215
- **Read it back:**
2216
- ```bash
2217
- keryx job status <job-name> --json # `retries` per step, plus phase and next_step
2218
- ```
2219
-
2220
- **Aggregated in the report:**
2221
- ```markdown
2222
- ## Metrics
2223
- | Step | Duration | Retries |
2224
- |------|----------|---------|
2225
- | Analyze | 45s | 0 |
2226
- | Context | 30s | 0 |
2227
- | Implement | 5m 22s | 1 |
2228
- | Review | 1m 10s | 0 |
2229
- | **Total** | **7m 47s** | **1** |
2230
- ```
2231
-
2232
- This data identifies which steps are bottlenecks and which ones needed a second attempt.