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