okstra 0.202.0 → 0.204.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (258) hide show
  1. package/README.md +3 -3
  2. package/dist/cli-registry.mjs +7 -7
  3. package/dist/cli-registry.mjs.map +1 -1
  4. package/dist/commands/lifecycle/install.mjs +50 -124
  5. package/dist/commands/lifecycle/install.mjs.map +1 -1
  6. package/dist/commands/memory/memory.mjs +41 -8
  7. package/dist/commands/memory/memory.mjs.map +1 -1
  8. package/dist/lib/install-assets.mjs +3 -0
  9. package/dist/lib/install-assets.mjs.map +1 -1
  10. package/dist/lib/runtime-manifest.mjs +2 -1
  11. package/dist/lib/runtime-manifest.mjs.map +1 -1
  12. package/dist/lib/types.d.mts +2 -1
  13. package/docs/architecture/storage-model.md +14 -11
  14. package/docs/architecture.md +25 -19
  15. package/docs/cli.md +15 -12
  16. package/docs/contributor-change-matrix.md +3 -2
  17. package/docs/performance-improvement-plan-v2.md +2 -3
  18. package/docs/project-structure-overview.md +35 -9
  19. package/docs/task-process/README.md +1 -1
  20. package/docs/task-process/common-flow.md +1 -1
  21. package/docs/task-process/final-verification.md +3 -1
  22. package/docs/task-process/implementation.md +1 -1
  23. package/docs/task-process/release-handoff.md +36 -39
  24. package/package.json +1 -2
  25. package/runtime/BUILD.json +2 -2
  26. package/runtime/agents/common.json +28 -0
  27. package/runtime/agents/operations/code-review.json +6 -0
  28. package/runtime/agents/operations/report-translation.json +6 -0
  29. package/runtime/agents/operations/schedule-verification.json +6 -0
  30. package/runtime/agents/roles/analyser.json +18 -0
  31. package/runtime/agents/roles/critic.json +18 -0
  32. package/runtime/agents/roles/designer.json +18 -0
  33. package/runtime/agents/roles/implementer.json +20 -0
  34. package/runtime/agents/roles/leader.json +20 -0
  35. package/runtime/agents/roles/planner.json +18 -0
  36. package/runtime/agents/roles/report-writer.json +19 -0
  37. package/runtime/agents/roles/translator.json +19 -0
  38. package/runtime/agents/roles/verifier.json +18 -0
  39. package/runtime/bin/lib/okstra/usage.sh +5 -5
  40. package/runtime/prompts/duties/acceptance-critic.json +32 -0
  41. package/runtime/prompts/duties/acceptance-verifier.json +32 -0
  42. package/runtime/prompts/duties/analysis-worker.json +32 -0
  43. package/runtime/prompts/duties/code-reviewer.json +32 -0
  44. package/runtime/prompts/duties/diagnosis-worker.json +32 -0
  45. package/runtime/prompts/duties/direction-selection-worker.json +32 -0
  46. package/runtime/prompts/duties/discovery-worker.json +32 -0
  47. package/runtime/prompts/duties/implementation-executor.json +32 -0
  48. package/runtime/prompts/duties/implementation-verifier.json +32 -0
  49. package/runtime/prompts/duties/lead.json +32 -0
  50. package/runtime/prompts/duties/planning-worker.json +36 -0
  51. package/runtime/prompts/duties/report-writer.json +32 -0
  52. package/runtime/prompts/duties/reverification-worker.json +32 -0
  53. package/runtime/prompts/duties/schedule-verifier.json +32 -0
  54. package/runtime/prompts/duties/scope-critic.json +32 -0
  55. package/runtime/prompts/duties/technical-verification-worker.json +32 -0
  56. package/runtime/prompts/duties/translator.json +32 -0
  57. package/runtime/prompts/launch.template.md +2 -1
  58. package/runtime/prompts/lead/adapters/cmux.md +1 -1
  59. package/runtime/prompts/lead/convergence.md +4 -4
  60. package/runtime/prompts/lead/okstra-lead-contract.md +113 -4
  61. package/runtime/prompts/lead/plan-body-verification.md +6 -6
  62. package/runtime/prompts/lead/report-writer.md +3 -3
  63. package/runtime/prompts/profiles/_common-contract.md +2 -2
  64. package/runtime/prompts/profiles/_implementation-executor.md +4 -1
  65. package/runtime/prompts/profiles/_implementation-verifier.md +2 -2
  66. package/runtime/prompts/profiles/change-impact-analysis.json +31 -0
  67. package/runtime/prompts/profiles/change-impact-analysis.md +0 -20
  68. package/runtime/prompts/profiles/error-analysis.json +39 -0
  69. package/runtime/prompts/profiles/error-analysis.md +0 -25
  70. package/runtime/prompts/profiles/feature-analysis.json +31 -0
  71. package/runtime/prompts/profiles/feature-analysis.md +0 -20
  72. package/runtime/prompts/profiles/final-verification.json +30 -0
  73. package/runtime/prompts/profiles/final-verification.md +3 -22
  74. package/runtime/prompts/profiles/forbidden-actions.json +4 -3
  75. package/runtime/prompts/profiles/implementation-option-selection.json +31 -0
  76. package/runtime/prompts/profiles/implementation-option-selection.md +0 -20
  77. package/runtime/prompts/profiles/implementation-planning.json +40 -0
  78. package/runtime/prompts/profiles/implementation-planning.md +4 -29
  79. package/runtime/prompts/profiles/implementation.json +30 -0
  80. package/runtime/prompts/profiles/implementation.md +1 -20
  81. package/runtime/prompts/profiles/improvement-discovery.json +31 -0
  82. package/runtime/prompts/profiles/improvement-discovery.md +0 -20
  83. package/runtime/prompts/profiles/project-analysis.json +31 -0
  84. package/runtime/prompts/profiles/project-analysis.md +0 -20
  85. package/runtime/prompts/profiles/release-handoff.json +5 -0
  86. package/runtime/prompts/profiles/release-handoff.md +71 -73
  87. package/runtime/prompts/profiles/requirements-discovery.json +39 -0
  88. package/runtime/prompts/profiles/requirements-discovery.md +0 -25
  89. package/runtime/prompts/profiles/technical-verification.json +39 -0
  90. package/runtime/prompts/profiles/technical-verification.md +0 -25
  91. package/runtime/prompts/wizard/prompts.ko.json +12 -17
  92. package/runtime/python/okstra_ctl/adapters/hosts/antigravity/relay.md +1 -0
  93. package/runtime/python/okstra_ctl/adapters/hosts/claude-code/adapter.py +3 -0
  94. package/runtime/python/okstra_ctl/adapters/hosts/claude-code/manifest.json +1 -1
  95. package/runtime/python/okstra_ctl/adapters/hosts/claude-code/relay.md +4 -3
  96. package/runtime/python/okstra_ctl/adapters/hosts/claude-code/worker-session.md +108 -0
  97. package/runtime/python/okstra_ctl/adapters/hosts/codex/relay.md +1 -0
  98. package/runtime/python/okstra_ctl/adapters/hosts/grok/relay.md +2 -0
  99. package/runtime/python/okstra_ctl/adapters/hosts/kimi/relay.md +2 -0
  100. package/runtime/python/okstra_ctl/adapters/providers/antigravity/adapter.py +8 -1
  101. package/runtime/python/okstra_ctl/adapters/providers/claude/adapter.py +8 -0
  102. package/runtime/python/okstra_ctl/adapters/providers/codex/adapter.py +23 -6
  103. package/runtime/python/okstra_ctl/adapters/providers/grok/adapter.py +6 -2
  104. package/runtime/python/okstra_ctl/agent/invocation.py +168 -113
  105. package/runtime/python/okstra_ctl/agent/prompt_cli/cli.py +120 -0
  106. package/runtime/python/okstra_ctl/agent/prompt_cli/materialize.py +107 -2
  107. package/runtime/python/okstra_ctl/agent/prompt_cli/run_identity.py +0 -49
  108. package/runtime/python/okstra_ctl/analysis_packet.py +4 -1
  109. package/runtime/python/okstra_ctl/application/open_worker.py +6 -1
  110. package/runtime/python/okstra_ctl/assignment_resolver.py +16 -5
  111. package/runtime/python/okstra_ctl/cmux.py +69 -20
  112. package/runtime/python/okstra_ctl/code_review_target.py +16 -8
  113. package/runtime/python/okstra_ctl/conformance.py +43 -0
  114. package/runtime/python/okstra_ctl/consumers.py +6 -3
  115. package/runtime/python/okstra_ctl/container.py +31 -8
  116. package/runtime/python/okstra_ctl/context_cost.py +11 -15
  117. package/runtime/python/okstra_ctl/contract_refreeze.py +156 -0
  118. package/runtime/python/okstra_ctl/convergence_provenance.py +7 -1
  119. package/runtime/python/okstra_ctl/design_prep.py +34 -1
  120. package/runtime/python/okstra_ctl/dispatch_core.py +53 -27
  121. package/runtime/python/okstra_ctl/domain/host.py +5 -0
  122. package/runtime/python/okstra_ctl/domain/worker_runtime.py +10 -0
  123. package/runtime/python/okstra_ctl/error_report.py +4 -3
  124. package/runtime/python/okstra_ctl/execution_manifest.py +71 -18
  125. package/runtime/python/okstra_ctl/handoff.py +167 -277
  126. package/runtime/python/okstra_ctl/implementation_stage.py +9 -0
  127. package/runtime/python/okstra_ctl/initial_prompt_materialization.py +113 -0
  128. package/runtime/python/okstra_ctl/lead_progress.py +1 -1
  129. package/runtime/python/okstra_ctl/legacy_model_selection.py +2 -2
  130. package/runtime/python/okstra_ctl/manager_cli.py +92 -4
  131. package/runtime/python/okstra_ctl/manager_launch.py +1 -1
  132. package/runtime/python/okstra_ctl/manager_paths.py +14 -3
  133. package/runtime/python/okstra_ctl/manager_store.py +210 -3
  134. package/runtime/python/okstra_ctl/manager_sync.py +4 -1
  135. package/runtime/python/okstra_ctl/manager_view.py +2 -1
  136. package/runtime/python/okstra_ctl/model_discovery.py +30 -0
  137. package/runtime/python/okstra_ctl/model_io/lines.py +14 -1
  138. package/runtime/python/okstra_ctl/model_io/renderers.py +4 -3
  139. package/runtime/python/okstra_ctl/models.py +1 -1
  140. package/runtime/python/okstra_ctl/next_phase.py +16 -6
  141. package/runtime/python/okstra_ctl/operation_invocation.py +86 -0
  142. package/runtime/python/okstra_ctl/option_comparison.py +168 -0
  143. package/runtime/python/okstra_ctl/path_hints.py +9 -0
  144. package/runtime/python/okstra_ctl/paths.py +3 -0
  145. package/runtime/python/okstra_ctl/profile_show.py +42 -1
  146. package/runtime/python/okstra_ctl/registry/host_discovery.py +20 -12
  147. package/runtime/python/okstra_ctl/registry/host_registry.py +11 -0
  148. package/runtime/python/okstra_ctl/render.py +50 -0
  149. package/runtime/python/okstra_ctl/report_contract.py +1 -1
  150. package/runtime/python/okstra_ctl/report_html/view_models/release_handoff.py +21 -3
  151. package/runtime/python/okstra_ctl/report_synthesis_packet.py +177 -17
  152. package/runtime/python/okstra_ctl/report_translation.py +2 -1
  153. package/runtime/python/okstra_ctl/report_translation_dispatch.py +69 -9
  154. package/runtime/python/okstra_ctl/role_requirements.py +142 -129
  155. package/runtime/python/okstra_ctl/rollup.py +3 -1
  156. package/runtime/python/okstra_ctl/run.py +76 -29
  157. package/runtime/python/okstra_ctl/schedule_semantics.py +17 -6
  158. package/runtime/python/okstra_ctl/stage_fix_carry.py +23 -4
  159. package/runtime/python/okstra_ctl/stage_integrate.py +178 -18
  160. package/runtime/python/okstra_ctl/stage_map.py +16 -2
  161. package/runtime/python/okstra_ctl/stage_targets.py +209 -43
  162. package/runtime/python/okstra_ctl/team.py +22 -13
  163. package/runtime/python/okstra_ctl/time_report.py +2 -1
  164. package/runtime/python/okstra_ctl/usage_report.py +3 -1
  165. package/runtime/python/okstra_ctl/wizard/confirmation.py +3 -9
  166. package/runtime/python/okstra_ctl/wizard/ids.py +1 -1
  167. package/runtime/python/okstra_ctl/wizard/registry.py +1 -1
  168. package/runtime/python/okstra_ctl/wizard/state.py +3 -5
  169. package/runtime/python/okstra_ctl/wizard/steps_plan.py +3 -23
  170. package/runtime/python/okstra_ctl/worker_prompt_contract.py +5 -1
  171. package/runtime/python/okstra_ctl/worker_prompt_headers.py +35 -7
  172. package/runtime/python/okstra_ctl/worker_prompt_policy.py +66 -48
  173. package/runtime/python/okstra_ctl/workflow.py +1 -1
  174. package/runtime/python/okstra_ctl/worktree/__init__.py +3 -1
  175. package/runtime/python/okstra_ctl/worktree/naming.py +9 -0
  176. package/runtime/python/okstra_ctl/worktree_registry.py +38 -9
  177. package/runtime/python/okstra_token_usage/pricing.py +6 -4
  178. package/runtime/schemas/agent-common-v1.schema.json +34 -0
  179. package/runtime/schemas/agent-duty-v1.schema.json +38 -0
  180. package/runtime/schemas/agent-operation-v1.schema.json +11 -0
  181. package/runtime/schemas/agent-profile-v1.schema.json +46 -0
  182. package/runtime/schemas/agent-role-v1.schema.json +29 -0
  183. package/runtime/schemas/final-report-v2.0.schema.json +118 -97
  184. package/runtime/schemas/final-report-v3.0.schema.json +118 -97
  185. package/runtime/skills/okstra-brief-gen/SKILL.md +84 -4
  186. package/runtime/skills/okstra-chat/SKILL.md +2 -2
  187. package/runtime/skills/okstra-code-review/SKILL.md +23 -9
  188. package/runtime/skills/okstra-container-build/SKILL.md +10 -10
  189. package/runtime/skills/okstra-inspect/SKILL.md +1 -1
  190. package/runtime/skills/okstra-inspect/facets/cost.md +1 -1
  191. package/runtime/skills/okstra-inspect/facets/error-zip.md +9 -9
  192. package/runtime/skills/okstra-inspect/facets/errors.md +16 -16
  193. package/runtime/skills/okstra-inspect/facets/logs.md +7 -7
  194. package/runtime/skills/okstra-inspect/facets/recap.md +2 -2
  195. package/runtime/skills/okstra-inspect/facets/report.md +1 -1
  196. package/runtime/skills/okstra-inspect/facets/status.md +4 -3
  197. package/runtime/skills/okstra-inspect/facets/time.md +11 -10
  198. package/runtime/skills/okstra-manager/SKILL.md +18 -2
  199. package/runtime/skills/okstra-pr-gen/SKILL.md +6 -5
  200. package/runtime/skills/okstra-rollup/SKILL.md +5 -5
  201. package/runtime/skills/okstra-run/SKILL.md +31 -12
  202. package/runtime/skills/okstra-schedule-gen/SKILL.md +19 -14
  203. package/runtime/skills/okstra-setup/SKILL.md +12 -10
  204. package/runtime/skills/okstra-setup/references/project-config.md +7 -6
  205. package/runtime/skills/okstra-usage/SKILL.md +1 -1
  206. package/runtime/skills/okstra-user-response/SKILL.md +1 -1
  207. package/runtime/templates/manager/view.template.html +1 -0
  208. package/runtime/templates/report-writer-prompt-preamble.md +8 -0
  209. package/runtime/templates/reports/brief.template.md +14 -4
  210. package/runtime/templates/reports/html/i18n/en.json +5 -4
  211. package/runtime/templates/reports/html/i18n/ko.json +5 -4
  212. package/runtime/templates/reports/html/tasks/release-handoff.template.html +8 -5
  213. package/runtime/templates/reports/i18n/en.json +1 -1
  214. package/runtime/templates/reports/md/tasks/release-handoff.template.md +1 -1
  215. package/runtime/templates/reports/release-handoff-input.template.md +6 -4
  216. package/runtime/templates/translator-prompt-preamble.md +36 -0
  217. package/runtime/validators/checks/validate-assets-01.py +7 -8
  218. package/runtime/validators/validate-brief.py +70 -0
  219. package/runtime/validators/validate-implementation-plan-stages.py +2 -1
  220. package/runtime/validators/validate-run.py +59 -9
  221. package/runtime/validators/validate-schedule.py +9 -0
  222. package/docs/for-ai/README.md +0 -68
  223. package/docs/for-ai/skills/okstra-brief-gen.md +0 -262
  224. package/docs/for-ai/skills/okstra-chat.md +0 -34
  225. package/docs/for-ai/skills/okstra-code-review.md +0 -57
  226. package/docs/for-ai/skills/okstra-container-build.md +0 -129
  227. package/docs/for-ai/skills/okstra-inspect.md +0 -262
  228. package/docs/for-ai/skills/okstra-manager.md +0 -86
  229. package/docs/for-ai/skills/okstra-memory.md +0 -126
  230. package/docs/for-ai/skills/okstra-pr-gen.md +0 -49
  231. package/docs/for-ai/skills/okstra-rollup.md +0 -114
  232. package/docs/for-ai/skills/okstra-run.md +0 -250
  233. package/docs/for-ai/skills/okstra-schedule-gen.md +0 -240
  234. package/docs/for-ai/skills/okstra-setup.md +0 -167
  235. package/docs/for-ai/skills/okstra-usage.md +0 -29
  236. package/docs/for-ai/skills/okstra-user-response.md +0 -72
  237. package/runtime/agents/workers/claude-worker.md +0 -128
  238. package/runtime/agents/workers/report-writer-worker.md +0 -37
  239. package/runtime/agents/workers/translator-worker.md +0 -63
  240. package/runtime/prompts/duties/acceptance-critic.md +0 -44
  241. package/runtime/prompts/duties/acceptance-verifier.md +0 -44
  242. package/runtime/prompts/duties/analysis-worker.md +0 -44
  243. package/runtime/prompts/duties/code-reviewer.md +0 -44
  244. package/runtime/prompts/duties/common.md +0 -39
  245. package/runtime/prompts/duties/diagnosis-worker.md +0 -44
  246. package/runtime/prompts/duties/direction-selection-worker.md +0 -44
  247. package/runtime/prompts/duties/discovery-worker.md +0 -44
  248. package/runtime/prompts/duties/implementation-executor.md +0 -44
  249. package/runtime/prompts/duties/implementation-verifier.md +0 -44
  250. package/runtime/prompts/duties/lead.md +0 -44
  251. package/runtime/prompts/duties/planning-worker.md +0 -52
  252. package/runtime/prompts/duties/report-writer.md +0 -44
  253. package/runtime/prompts/duties/reverification-worker.md +0 -44
  254. package/runtime/prompts/duties/schedule-verifier.md +0 -44
  255. package/runtime/prompts/duties/scope-critic.md +0 -44
  256. package/runtime/prompts/duties/technical-verification-worker.md +0 -44
  257. package/runtime/prompts/duties/translator.md +0 -44
  258. package/runtime/python/okstra_ctl/pane_title.py +0 -154
package/docs/cli.md CHANGED
@@ -500,9 +500,9 @@ The Codex worker (`--workers codex`, `--codex-model`) and Codex lead runtime are
500
500
 
501
501
  > Every `--*-model` flag accepts only aliases registered in the provider mappings in `scripts/okstra_ctl/models.py`. An unregistered value is immediately rejected with `UnknownModelError`, preventing a contract violation where the manifest's `modelExecutionValue` differs from the actual execution value. Allowed values:
502
502
  > - Claude (`--lead-model` / `--claude-model` / `--report-writer-model`): `fable`, `fable-5-1`, `claude-fable-5-1`, `fable-5`, `claude-fable-5`, `opus`, `opus-5`, `claude-opus-5`, `sonnet`, `sonnet-5`, `claude-sonnet-5`, `haiku`, `haiku-4-5`, `claude-haiku-4-5`
503
- > - Codex (`--codex-model`): `gpt-5.6-sol`, `gpt-5.6-terra`, `gpt-5.6-luna`, `gpt-5.4-mini`, `codex-auto-review`. Codex slugs are gated at dispatch against the provider catalog the CLI caches in `~/.codex/models_cache.json`; a slug that catalog does not list is rejected rather than renamed.
504
- > - Antigravity (`--antigravity-model`): `gemini-3.1-pro` (default), `gemini-3.7-flash`, and their space-separated aliases. The antigravity worker uses the `agy` CLI to run Gemini-family models, so model IDs retain the `gemini-*` form.
505
- > - Grok (`--worker-model grok=<model>`): `grok-4.6`, `grok-build-0.1`
503
+ > - Codex (`--codex-model`): `gpt-6-astra`, `gpt-5.6-sol`, `gpt-5.6-terra`, `gpt-5.6-luna` — the newest generation this account actually serves per tier. `gpt-6-sol` and `gpt-6-luna` stay in the catalog (a ChatGPT-account login is refused with HTTP 400 for them, measured 2026-09-23) together with `gpt-5.4-mini` and `codex-auto-review`, so past runs still price and an account that does serve them can still be pinned explicitly, but they are not offered. Codex slugs are gated at dispatch against the provider catalog the CLI caches in `~/.codex/models_cache.json`; a slug that catalog does not list is rejected rather than renamed.
504
+ > - Antigravity (`--antigravity-model`): `gemini-3.1-pro` (default), `gemini-3.8-flash`, and their space-separated aliases. The antigravity worker uses the `agy` CLI to run Gemini-family models, so model IDs retain the `gemini-*` form.
505
+ > - Grok (`--worker-model grok=<model>`): `grok-4.7`
506
506
  > - Kimi (`--worker-model kimi=<model>`): `kimi-k3`, `k3`, `k3-256k` and their registered display aliases
507
507
  >
508
508
  > Not every registered alias is offered for selection. A model whose `ModelSpec` sets `selectable=False` stays in the catalog — so served-model attestation and historical pricing still resolve it — but it is hidden from the wizard's role-model picker, from `okstra model list`, and from `--role-model`. `okstra model list` still prints them, marked `selectable: no` with the reason. Currently hidden: `claude/fable-5-1`, `claude/fable-5`, `claude/opus-5`, `claude/sonnet-5`, `claude/haiku-4-5`, `claude/haiku-4-5-20251001` (each one the pinned twin of a channel entry that already appears; `claude/fable-5` is the previous served id, kept for attestation and pricing), `kimi/k3` (same model as `kimi/kimi-k3`), `codex/gpt-5.4-mini`, `codex/codex-auto-review`, `grok/grok-build-0.1`, `kimi/k3-256k`.
@@ -571,11 +571,11 @@ The central-default environment variables are:
571
571
  Fallback defaults are:
572
572
 
573
573
  - Claude Code lead: `opus`
574
- - Codex lead: `gpt-5.6-sol`
574
+ - Codex lead: `gpt-6-sol`
575
575
  - Antigravity lead: `gemini-3.1-pro`
576
576
  - `Report writer worker`: `sonnet`
577
577
  - `Claude worker`: `opus`
578
- - `Codex worker`: `gpt-5.6-sol`
578
+ - `Codex worker`: `gpt-6-sol`
579
579
  - `Antigravity worker`: `gemini-3.1-pro`
580
580
  - Implementation executor: `claude`, so the default is `Claude executor`.
581
581
 
@@ -585,12 +585,12 @@ Selects the provider that performs the Executor role for `--task-type implementa
585
585
 
586
586
  - Default: `OKSTRA_DEFAULT_EXECUTOR` → fallback `claude`.
587
587
  - The Executor is the **only worker allowed to mutate project files** in this run. The other providers are dispatched as strict read-only verifiers in the same run.
588
- - The Executor reuses the provider's worker model flag. With `--executor codex`, its model comes from `--codex-model`, default `gpt-5.6-sol`; with `--executor antigravity`, it comes from `--antigravity-model`, default `gemini-3.1-pro`. With `--executor grok`, its model comes from `--worker-model grok=`, default `grok-4.6`.
588
+ - The Executor reuses the provider's worker model flag. With `--executor codex`, its model comes from `--codex-model`, default `gpt-6-sol`; with `--executor antigravity`, it comes from `--antigravity-model`, default `gemini-3.1-pro`. With `--executor grok`, its model comes from `--worker-model grok=`, default `grok-4.7`.
589
589
  - All three Claude, Codex, and Antigravity verifiers are always dispatched regardless of the Executor provider. Even the verifier using the same provider runs in a separate CLI session with isolated context, preserving the self-review safeguard.
590
590
  - Codex and Antigravity mutate files through each CLI's auto-edit mode, for example `codex exec --sandbox danger-full-access`, without passing through Claude-side Edit/Write tools. Mutations occur in the task worktree described below. Every `okstra-<provider>-exec.sh` entrypoint receives the worktree path as its fourth positional argument and adds it to the worker's write scope, which each provider is told as repeated `--add-dir` (Codex names the project root with `-C` and skips the repeat). No provider CLI enforces a sandbox boundary: the write scope tells a worker where its work belongs, and the run checks afterwards that it stayed there.
591
591
  - **Claude Executor cwd handling**: Claude's Bash tool has no per-call cwd argument and inherits the lead session cwd. To run cwd-sensitive toolchains such as `cargo`, `npm`, `pnpm`, `bun`, `pytest`, `make`, or `go` inside the worktree, prefix the invocation with `cd {{EXECUTOR_WORKTREE_PATH}} && <cmd>`. Keep `cd` as the leading token in a single Bash call so Claude Code permission auto-allow works; do not wrap it in `bash -lc "..."` or `bash -c "..."`, which hides `cd` and causes a permission prompt on every call. Prefer a tool's working-directory option—such as `git -C <path>`, `cargo --manifest-path`, or `pytest --rootdir`—over a `cd && ` chain. Edit/Write/Read tools already use absolute paths and need no cwd handling. This rule applies only to the Claude Executor; the Codex and Antigravity wrappers inject cwd.
592
- - **Task worktree (automatic isolation for every task type)**: During the first phase's preparation for any task type, prepare creates a `git worktree` at `~/.okstra/worktrees/<project-id>/<task-group-segment>/<task-id-segment>/` and branches `<work-category-namespace>/<task-id-segment>` from the resolved commit of the user-selected `--base-ref`, for example `feature/dev-9436` or `fix/dev-7311`. Later phases for the same task key reuse the path and branch and record status `reused`; no new `git worktree add` occurs during run preparation. Special characters such as `/` and `:` in every segment are normalized to `-`, and `~/.okstra/worktrees/registry.json` globally manages task-key-to-path/branch mappings under flock. Executor edits, writes, builds, tests, and commits—and verifier reads—run in this worktree. If the caller is already in another worktree or project_root is not a Git repository, provisioning is skipped and records `skipped-in-worktree` or `skipped-not-git`. Path or branch collisions fail immediately with `PrepareError`. Worktrees are not deleted after a run; remove one manually with `git worktree remove`, then `git branch -D`, then delete the registry entry. **The implementation stage isolation below is the exception.**
593
- - **`implementation` stage isolation (concurrent parallelism)**: The task-key worktree above applies only from `requirements-discovery` through `implementation-planning`. Each `implementation` run executes in a **stage-specific isolated worktree** at `~/.okstra/worktrees/<project-id>/<task-group-segment>/<task-id-segment>--stage-<N>/` (a sibling of the task worktree — a nested layout made the task tree's prettier/tsc read the stage tree as source; whole-task `final-verification` prepare moves any remaining nested stage worktree out with `git worktree move` and updates the registry), on branch `<work-category-namespace>/<task-id-segment>-s<N>`. The registry atomically reserves a stage key, `<task-key>#stage-<N>`, under flock. `_resolve_effective_stages` excludes `started` rows in `consumers.jsonl` and reserved stages. Stage selection, worktree creation, and registry reservation all happen in one critical section protected by the task-key provisioning mutex at `~/.okstra/.locks/worktree-provision/`, so concurrent `implementation` runs safely select different ready stages: **one run = one stage**. A stage worktree's base depends on its dependency shape: independent (`depends-on (none)`) uses the common anchor fixed once at first stage entry; a single dependency (`depends-on X`) uses the predecessor stage's completed `head_commit`; multiple dependencies (`depends-on X,Y…`) use task-worktree HEAD after all predecessors have been merged, verified with `git merge-base --is-ancestor`, and otherwise fail with `PrepareError` and merge guidance. Select the stage with `--stage <auto|N>` for `okstra.sh`/`render-bundle`, or with the okstra-run wizard's `stage_pick` step. If `project_root` is not a Git repository or is a nested worktree, stage isolation also degrades to flat operation.
592
+ - **Task worktree (automatic isolation for every task type)**: During the first phase's preparation for any task type, prepare creates a `git worktree` at `~/.okstra/worktrees/<project-id>/<task-group-segment>/<task-id-segment>/` and branches `<work-category-namespace>/<task-id-segment>` from the resolved commit of the user-selected `--base-ref`, for example `feature/dev-9436` or `fix/dev-7311`. Later phases for the same task key reuse the path and branch and record status `reused`; no new `git worktree add` occurs during run preparation. Special characters such as `/` and `:` in every segment are normalized to `-`, and `~/.okstra/worktrees/registry.json` manages task-key-to-path/branch mappings under flock — paths machine-wide, branch names within one project id. Executor edits, writes, builds, tests, and commits—and verifier reads—run in this worktree. If the caller is already in another worktree or project_root is not a Git repository, provisioning is skipped and records `skipped-in-worktree` or `skipped-not-git`. Path or branch collisions fail immediately with `PrepareError`. Worktrees are not deleted after a run; remove one manually with `git worktree remove`, then `git branch -D`, then delete the registry entry. **The implementation stage isolation below is the exception.**
593
+ - **`implementation` stage isolation (concurrent parallelism)**: The task-key worktree above applies only from `requirements-discovery` through `implementation-planning`. Each `implementation` run executes in a **stage-specific isolated worktree** at `~/.okstra/worktrees/<project-id>/<task-group-segment>/<task-id-segment>--stage-<N>/` (a sibling of the task worktree — a nested layout made the task tree's prettier/tsc read the stage tree as source; whole-task `final-verification` prepare moves any remaining nested stage worktree out with `git worktree move` and updates the registry), on branch `<work-category-namespace>/<task-id-segment>-s<N>`. The registry atomically reserves a stage key, `<task-key>#stage-<N>`, under flock. `_resolve_effective_stages` excludes `started` rows in `consumers.jsonl` and reserved stages. Stage selection, worktree creation, and registry reservation all happen in one critical section protected by the task-key provisioning mutex at `~/.okstra/.locks/worktree-provision/`, so concurrent `implementation` runs safely select different ready stages: **one run = one stage**. A stage worktree's base depends on its dependency shape: independent (`depends-on (none)`) uses the common anchor fixed once at first stage entry; a single dependency (`depends-on X`) uses the predecessor stage's completed `head_commit`; multiple dependencies (`depends-on X,Y…`) use a base holding exactly those predecessors — the predecessor commit that already contains the others, or else a branch merging them (`<work-category-namespace>/<task-id-segment>-g<n1>-<n2>`, built by `stage_integrate.ensure_stage_merge_branch` and reused as that stage's PR base in release-handoff). The branch is advanced when a predecessor's done commit moves, and only a predecessor commit missing from the repository fails the run. Select the stage with `--stage <auto|N>` for `okstra.sh`/`render-bundle`, or with the okstra-run wizard's `stage_pick` step. If `project_root` is not a Git repository or is a nested worktree, stage isolation also degrades to flat operation.
594
594
  - **Single-stage `final-verification` artifact isolation**: `--task-type final-verification --stage <N>` reuses the implementation stage worktree read-only from the registry. Run artifacts are isolated per stage under `runs/final-verification/stage-<N>/`, and the team name receives a `-fv-s<N>` suffix. Concurrent final-verification runs for different stages do not collide in state, worker results, or team names. For concurrent verification of the same stage, `teamName` is only an audit label and each session has its own implicit team, so the sessions can coexist without a TeamCreate/name collision. This statement is limited to per-session team identity and does not claim safety for shared mutable state. Whole-task verification with an empty stage keeps the flat `runs/final-verification/` layout.
595
595
 
596
596
  Example:
@@ -819,7 +819,7 @@ The `okstra` Node CLI (`bin/okstra`) provides both installer/admin commands and
819
819
  | `okstra paths [--field <name>\|--shell]` | Print package, runtime, home, bin, Python path, and version locations |
820
820
  | `okstra install [--runtime claude-code\|codex\|antigravity\|external\|all] [--refresh\|--dry-run\|--link <repo>]` | Install or update the runtime, templates, skills, and agents. The default runtime is `auto`; skill targets are not runtimes. `~/.agents/skills/` is always created, and Claude skills and agents are also installed when `~/.claude` exists |
821
821
  | `okstra ensure-installed [--runtime claude-code\|codex\|antigravity\|external\|all] [-q]` | Check installation state and reinstall stale assets for the same runtime. Default `auto` continues without a host signal and checks drift in the Agent skill target and any existing Claude target |
822
- | `okstra uninstall [--purge -y]` | Remove installed assets. By default, removes files listed by the `installed-skills.json` targets and `installed-agents.json` while preserving user data |
822
+ | `okstra uninstall [--purge -y]` | Remove installed assets. By default, removes the installed trees under `~/.okstra` (including `agents/`), the skill targets recorded in `installed-skills.json`, and any host agent files `installed-agents.json` proves a past install owned, while preserving user data |
823
823
  | `okstra doctor [--runtime claude-code\|codex\|antigravity\|external\|all] [--phase <phase>] [--json]` | Diagnose the runtime, Python imports, skill/agent installation, and model-pool state. The JSON `modelPool` object reports pool errors, default errors, binding precision, observed model, max write boundary, and invocation downgrade reason. It never sends an inference call. The `codex`, `antigravity`, and `external` runtimes omit Claude skill checks. `--phase` adds readiness checks for `implementation`, `final-verification`, `release-handoff`, or `improvement-discovery` |
824
824
  | `okstra model list [--role <role>] [--host <host>] [--json]` | List catalog models for a host and optional role. Unselectable exact bindings report `exact binding unavailable`. No inference call |
825
825
  | `okstra model default set\|unset <role> ... --scope project\|global [--cwd <dir>]` | Atomically write or remove `modelDefaults` for one canonical role |
@@ -856,7 +856,7 @@ The `okstra` Node CLI (`bin/okstra`) provides both installer/admin commands and
856
856
  | `okstra model-io active-context-input --project-root <dir> --run-manifest <path>` | Resolve the prior implementation-planning active context only through the current project and run authority, then emit fixed fields such as the executor base ref. Caller-supplied active-context paths are not accepted. |
857
857
  | `okstra report-translate <source\|write\|check-data> --run-manifest <path> …` | Resolve the report data and translation sidecar from the run manifest. `source` emits a source digest with the fixed translation queue; `write` requires that digest and rejects a stale report; `check-data` verifies the derived sidecar. Models never choose the data or sidecar path. |
858
858
  | `okstra convergence prepare-groups --run-manifest <path> --input <grouping.md>` | Parse fixed grouping Markdown, validate distinct per-worker evidence and group semantics against the run authority, then publish the schema-valid groups artifact at the run-owned path. |
859
- | `okstra manager <init\|discover-projects\|new\|task\|list\|view> [--json]` | Public CLI for grouping cross-project okstra tasks into manager-owned context. The default is purpose-specific fixed text for model use; `--json` preserves the machine contract and exit codes. `new project --project-root` accepts only existing directories and performs setup-equivalent registration only if `.okstra/project.json` is absent. `list managers`, `list projects --manager-id <id>` and `list tasks --manager-id <id>` enumerate manager state; `view --manager-id <id>` writes `~/.okstra/managers/<id>/view/index.html` and prints its path and `file://` URL. `task split --plan <json>` writes one validated brief with a `## Project Scope` section into each project an issue is assigned to and registers those children; `task run` then passes `--task-brief`. |
859
+ | `okstra manager <init\|discover-projects\|new\|task\|list\|remove\|view> [--json]` | Public CLI for grouping cross-project okstra tasks into manager-owned context. The default is purpose-specific fixed text for model use; `--json` preserves the machine contract and exit codes. `new project --project-root` accepts only existing directories and performs setup-equivalent registration only if `.okstra/project.json` is absent. `list managers`, `list projects --manager-id <id>` and `list tasks --manager-id <id>` enumerate manager state; `view --manager-id <id>` writes `~/.okstra/managers/<id>/view/index.html` and prints its path and `file://` URL. `task split --plan <json>` writes one validated brief with a `## Project Scope` section into each project an issue is assigned to and registers those children; `task run` then passes `--task-brief`. `list task-groups` lists groups including empty ones; `task update` edits a task's objective, common brief or progress mode; `remove project`, `remove task`, `remove task-group` and `task remove-child` print their targets and delete manager files only with `--confirm`, and `remove project` keeps the project's children marked unlinked. |
860
860
  | `okstra rollup [--task-group <group>] [--project-root <dir>] [--cwd <dir>] [--text\|--json]` | Read-only backend for the okstra-rollup skill. `--text` emits ordered fixed labels for model use. The default and `--json` preserve the full machine JSON contract and exit codes. Omitting `--task-group` targets the whole project catalog. |
861
861
  | `okstra usage-report [--days <positive-int>] [--project-root <dir>] [--cwd <dir>] [--text\|--json]` | Read-only backend for the okstra-usage skill. `--text` emits ordered fixed labels for model use. The default and `--json` preserve the full machine JSON contract and exit codes. Defaults to the current project's last 30 days. |
862
862
  | `okstra worker-state transition --team-state <path> --worker <id> --status <in-progress\|completed\|timeout\|error\|not-run> [--reason <text>] [--model <execution-value>]` | Atomically update one persisted worker row. `in-progress` records the authoritative `startedAt` and clears `endedAt`; terminal states record `endedAt`; `timeout`, `error`, and `not-run` require a reason. Dispatch adapters use this same transition path, so CLI-backed and in-process orchestration share the status timestamp contract |
@@ -866,6 +866,7 @@ The `okstra` Node CLI (`bin/okstra`) provides both installer/admin commands and
866
866
  | `okstra log-report [--project-root <dir>] [--cwd <dir>] [--top <N>] [--json]` | Read-only inventory of wrapper transcript `.log` files and their sibling prompt `.md` files. Each ranked entry preserves `path` / `sizeBytes` for compatibility and also reports `transcriptPath`, `transcriptBytes`, `promptPath`, `promptBytes`, and `transcriptToPromptRatio`; totals distinguish prompt bytes from transcript bytes and count paired files. Ranking remains transcript-size descending |
867
867
  | `okstra recap <assemble\|record\|note> (<task-root\|task-key> \| --task-group <group>) …` | Backend for the okstra-inspect `recap` facet. `assemble` is read-only: for a task it prints a JSON summary of phase transitions across its runs; with `--task-group` it prints the group's start order (briefs in ordinal order, each `done` / `in progress` / `not started` from the catalog's task-manifests, memory entries only for tasks the catalog does not know) and every recorded task's latest conclusion from `group-context.md`'s Task Memory. `okstra model-io recap-input --task-group <group>` is the fixed-text projection of the same join. `record --kind <summary\|qa> --mode <artifact\|code> --answer <text> [--question <text>] [--citation <path:line> …]` appends one line to `<task-root>/recap/recap-log.jsonl`, or with `--task-group` to `.okstra/tasks/<group>/.recap/recap-log.jsonl`, and never mutates other artifacts. `note` is task-only. `note --kind <verification-evidence\|decision-draft\|analysis-note> --slug <topic> --purpose <text> --scope-note <text> (--body <markdown>\|--body-file <path>)` writes an agent-authored note to `<task-root>/notes/` and prints its path plus the `--clarification-response` argument for feeding it into a later run |
868
868
  | `okstra user-response <list-view\|show-view\|begin\|answer\|plan-decision\|legacy-report-authoring\|finalize> …` | Backend for the `/okstra-user-response` skill. `list-view` and `show-view --report <md\|data.json> --project-root <dir>` are fixed-text model views; `show-view` validates that the report belongs to the explicit project root and prints each open row's why-asked line, linked plan items, and cited `path:line` artifacts so the skill can read them before asking. The legacy `list` and `show` JSON reads retain their automation-compatible fields. `begin --report <md\|data.json> --task-key <key>` returns an opaque transaction id. A predefined clarification choice uses `answer --transaction <id> --clarification-id <C-NNN> --kind <kind> --option-number <N>`; Python resolves the answer, disposition, reach, and scope effects from the validated report. Direct input instead uses `--disposition <answer\|reframe> --value-file <md> [--rationale-file <md>]`. Every value, rationale, and reason file must be a regular file under `<PROJECT_ROOT>/.okstra/tmp/user-response/`; external paths and symbolic links are rejected. `plan-decision` accepts `approved`, `revision-requested`, or `rejected`, validates any `--implementation-option` against the report candidates, and requires `--reason-file` for the latter two statuses. `legacy-report-authoring` is restricted to report contract 2.0. `finalize` validates the complete existing sidecar before a lossless merge, uses compare-and-swap under a run-local lock, and atomically publishes only the user-owned sidecar; exit 0 ok / 1 error. |
869
+ | `okstra option-comparison --report <data.json\|md>` | Read-only backend for the okstra-run comparison material. Prints one implementation-option-selection report's comparison facts as JSON: `criteria` (the eight evaluation criteria and their weights), `workers` (voting analysts in first-seen order), and per ranked direction `scores`, `scoreRationales`, the recorded `weightedScore` (publication already checks it against the recalculated value), `coverage` (verdict, counts, requirement ids), `safetyBlockers` and `unresolvedFeasibilityFacts` counts, and `votes` per worker (verdict, rationale, counterevidence); plus the report's `narrative` texts and `nextStep`, which is the next-phase pointer rationale. Exits 2 when the record has no `implementationOptionSelection` block or ranks no direction. |
869
870
  | `okstra pr <template\|branches\|gen> … [--json]` | Backend for the okstra-pr-gen skill. Git-only—no project registration required. `template list\|show <name\|default>\|add --name <name> (--content <text>\|--file <path>)\|path` manages PR body templates under `~/.okstra/template/pr/` (bundled fallback `src/commands/pr/default.md`); `branches` recommends a base branch; `gen --base <ref> [--template <name\|default>]` emits fixed `Base`, `Current branch`, `Template name`, `Commits`, `Diff stat`, and `Template` sections by default. `--json` preserves the machine bundle for automation. |
870
871
  | `okstra migrate [--apply] [--cwd <dir>] [--quiet]` | One-time migration of the project artifact root from `.project-docs/okstra/` to `.okstra/`. It is a dry run by default; `--apply` performs the move with `git mv` in a Git worktree, removes an empty `.project-docs/`, and synchronizes the `<PROJECT>/CLAUDE.md` import line, `.gitignore`, the project's rows in `~/.okstra/{recent,active}.jsonl`, and `~/.okstra/worktrees/registry.json`. It exits 1 if `.okstra/` already exists or the legacy directory is absent. Scheduled for removal by the end of v0.x |
871
872
  | `okstra task-list [--project-root <path>]` | Combine `list_project_tasks` and `read_latest_task` into JSON containing the task catalog and latest task |
@@ -879,14 +880,16 @@ The `okstra` Node CLI (`bin/okstra`) provides both installer/admin commands and
879
880
  | `okstra worktree-lookup <project-id> <task-group> <task-id>` | Return the `worktree_registry.lookup` result: reserved path, branch, base ref, and current status |
880
881
  | `okstra worktree-status [--path <dir>] [--check-clean]` | Answer "is this worktree clean?" over source paths only, excluding what okstra provisioned there — `.okstra`, the configured sync entries (`.project-docs`, `.claude`, …), and any nested stage worktree. A bare `git status --porcelain` in a task worktree is never empty for that reason, so a plan step asserting a clean tree with one fails on okstra's scaffolding instead of on the stage's own work; this is the same gate `handoff` and stage integration use. Output is JSON `{ ok, path, clean, entries, excluded }` where `entries` holds the `git status --short` rows that made it dirty. Exit code is 0 regardless unless `--check-clean` is given, which exits 1 on a dirty tree so it can stand as a shell assertion (`okstra worktree-status --check-clean`). okstra writes `stage-<N>-exit` itself when it settles the stage, so a plan step must not tag. A path outside a git work tree exits 2 rather than reporting a clean tree |
881
882
  | `okstra plan-validate <plan-path>` | Run `_validate_approved_plan` and report frontmatter `approved` recognition plus unresolved Blocks=approval rows |
882
- | `okstra render-bundle <args…> [--stage <auto\|N>] [--stages <csv>]` | Thin shim over `prepare_task_bundle(render_only=True)` with the same signature as `python3 -m okstra_ctl.run --render-only`. `--stage` is for `implementation` and `final-verification`: for implementation, `auto` (default) selects the earliest incomplete stage with satisfied dependencies, while `<N>` forces a stage; for final-verification, `<N>` verifies one stage with artifacts under `runs/final-verification/stage-<N>/` and a `-fv-s<N>` team suffix, while an empty value performs whole-task verification with the flat layout. The separate `--stages <csv>` channel is for `release-handoff`: stage-group mode bundles the listed stage numbers into one PR, while an empty value selects whole-task mode. Preparation enforces eligibility—`done` + accepted `verified` + not yet `pr`—and automatically creates an input document that cites verification reports |
883
+ | `okstra render-bundle <args…> [--stage <auto\|N>] [--stages <csv>]` | Thin shim over `prepare_task_bundle(render_only=True)` with the same signature as `python3 -m okstra_ctl.run --render-only`. `--stage` is for `implementation` and `final-verification`: for implementation, `auto` (default) selects the earliest incomplete stage with satisfied dependencies, while `<N>` forces a stage; for final-verification, `<N>` verifies one stage with artifacts under `runs/final-verification/stage-<N>/` and a `-fv-s<N>` team suffix, while an empty value performs whole-task verification with the flat layout. The separate `--stages <csv>` channel is for `release-handoff`: it names the stages to open a PR for, one PR per stage, and an empty value takes every eligible stage. Preparation enforces eligibility—`done` + accepted `verified` + not yet `pr`—and automatically creates an input document that cites verification reports |
883
884
  | `okstra profile show <task-type> [--resolved]` | Print a phase profile. `--resolved` expands its `{{INCLUDE:}}` targets and appends the lazy-read sidecars named in the profile body — transitively, because sidecars name sidecars of their own (`_implementation-executor.md` points at the coding-conventions preflight, the diff-review sweep, and the completion self-check). That matters because a profile is assembled from three places, so grepping only the top-level file returns false negatives: `grep clarification prompts/profiles/implementation.md` finds nothing while the assembled profile has many hits. One grep over this output answers whether a task-type covers a rule. The sidecar list is read from the profile body, never hard-coded, so a newly added sidecar is picked up without a code change. Read-only: it writes no manifest and registers no run, which is what separates it from `render-bundle` — `render-bundle` answers the same question but records a run in `recent.jsonl`, so it cannot be used to look something up. Exits 2 for an unknown task-type |
884
885
  | `okstra codex-run <args…>` | Codex lead-adapter dry-run entry point. Accepts the same arguments as `render-bundle` but owns `--render-only --lead-runtime codex`. It prepares the task bundle and prints the prompt for the Codex lead without dispatching workers |
885
886
  | `okstra worker-dispatch --project-root <dir> --run-manifest <path> [--workers <csv>] [--dry-run]` | Provider-neutral deterministic dispatcher for `runner=cli-wrapper` assignments. It verifies each adjacent invocation specification against the immutable run manifest immediately before process creation and records `core-pre-dispatch`; native-session rows stay with the host. The default selects CLI analysis assignments only. Phase 6 uses explicit `--workers report-writer`, and a mixed analysis/report batch is rejected. `--dry-run` performs the same verification and resolution without starting a provider process. |
886
887
  | `okstra codex-dispatch --project-root <dir> --run-manifest <path> [--workers <csv>] [--dry-run]` | Compatibility alias for `okstra worker-dispatch`; it no longer selects a Codex-only transport-agent path. |
888
+ | `okstra agent-prompt resolve-operation --operation <id> [--json]` | Print what a non-run operation runs: its duty, its canonical role, the worker count, and one slot line per worker carrying that slot's provider and model reference. The operation contract (`agents/operations/<id>.json`) owns the duty and the count; the models come from the same project/global/bundled default chain a run uses, one distinct model per slot. A machine with fewer distinct models than the contract requires fails here rather than dispatching a short roster. The default output is fixed text because a skill body must not instruct a model to parse okstra-owned JSON; `--json` is for programmatic callers. |
887
889
  | `okstra agent-prompt jobs --project-root <dir> --run-manifest <path> --dispatch-kind <kind> --metadata <path> [--metadata <path>] --out <path> [--json]` | Generate an immutable v2 jobs file from verified invocation metadata. Reads canonical identity, role, five digests, and actual result anchors; validates the full batch through the dispatch consumer before publishing. Rejects mixed runs or dispatch kinds, duplicate attempts, and translator input (use canonical `worker-dispatch --workers translator`). Reuses identical output; preserves differing output and requests a new `--out` path. Does not launch workers. |
888
890
  | `okstra agent-prompt materialize\|check-corrections\|apply-corrections\|verify\|record-dispatch\|link-result\|reject-result\|abandon-attempt\|materialize-result\|complete\|verify-completion` | Internal invocation-contract CLI. `materialize` composes model assignment, functional duty, and task instructions; `verify` rejects identity, path, snapshot, assignment, source, or digest drift. Every run-branch report-writer prompt gets its `## Output` section (narrative, pointer record, reading audit) rendered by okstra, and an instruction body that writes a `## Output` or `## Corrections` heading is refused. A corrective report-writer round — the narrative at `reportNarrativePath` already exists and its structure parses, value defects included — must pass `--corrections <ledger>` (`schemas/report-writer-corrections-v1.0.schema.json`: `replace` / `remove` / `add` / `move` / `rewrite` entries keyed by the validator's field-path grammar, `baseNarrativePath` naming a preserved copy of the attempt, and optional `baseNarrativeSha256` binding that version): the ledger is applied to that base and checked against the writer-owned schema and the task's semantic validator before dispatch, every defect is reported at once, and okstra renders the prompt's `## Corrections` section from it; a report-writer materialization without a ledger over such a narrative is refused before any prompt is written, while a narrative whose structure does not parse (line grammar, unknown top-level field) is re-authored without one. `check-corrections --run-manifest <path> --corrections <ledger> [--json]` runs the same check without materializing (exit 1 lists the defects; `mechanical: true` means every entry is a validated `replace`, `remove`, `add`, or `move`, including derived planning step counts). `apply-corrections` with the same arguments applies such a mechanical ledger without a writer round: it writes the corrected narrative to `reportNarrativePath` and records a `lead-correction-applied` activity row (`evidenceRefs` = ledger path + correction ids) through the run's activity contract; `--rewrite-results <file>` also accepts hash-bound replacement values for exactly the requested rewrite ids. Correction-only materialization sends those target fields, evidence, and constraints instead of the initial instructions and complete synthesis packet; the runtime merges the submitted values and checks the complete narrative before writing. It refuses unresolved `rewrite` entries or any defect, a stale live narrative, a base that is the live narrative, a run without `activityContractVersion` 1, and a ledger already applied. An empty ledger can preflight the initial writer result and derive `stageMap[].stepCount` from matching execution rows without another writer call. Run-backed calls resolve `assignmentRef` from the manifest, enforce `authorizedPaths`, and reject real-path or symbolic-link escape. `record-dispatch` records a verified host-native specification before dispatch and `link-result` binds the accepted result; one result path belongs to one dispatch, so a corrective round retires the first attempt with `reject-result --dispatch-id <first> --superseded-by <corrective> --reason <text>` before the new link is accepted — the rejected row stays in `agentResultLinks` carrying `supersededBy` and `rejectionReason` rather than being deleted. The corrective dispatch is a new invocation: an invocation whose last attempt finished with a mutation takes no further attempt (`execution_manifest._validate_next_attempt` lets only `failed-no-mutation` be followed), so a retry attempt of the rejected invocation itself is refused by the manifest, and `reject-result` does not make it possible. `abandon-attempt --invocation-ref <ref> --reason <text>` closes a started attempt whose worker died without producing a result — the one case neither `link-result` (which needs the result file) nor the dispatch-failure path covers — so a retry can follow it instead of the run having to be re-rendered. It refuses any attempt whose `writePolicy.sourcePolicy.mode` is not `source-readonly`: closing an attempt records `failed-no-mutation`, which is true by policy for a read-only worker and a guess for a mutating one. Standalone calls are identified by `(purpose, invocationId)` under `.okstra/agent-invocations/<purpose>/`; they publish a canonical result envelope and publish the completion marker last. Consumers use only the `returnedBody` from `verify-completion`. Metadata contains exactly `catalogDigest`, `assignmentDigest`, `dutyDigest`, `instructionDigest`, and `promptDigest`; JSON inputs use UTF-8, sorted keys, compact separators, and no non-finite values, while duty files use versioned sorted-name/byte framing. Instruction sources use `{kind: project\|runtime, path: <relative POSIX path>}` and never persist an installed absolute runtime path. A published prompt is immutable, so re-running `materialize` with an edited instruction file fails as `existing_invocation_conflict`; `--replace-undispatched` is the one exit, for a call that failed a pre-dispatch gate and therefore ran nowhere — it covers a differing prompt and a differing metadata alike, since the two are published together and describe one call. It republishes prompt and metadata together, and it is verified rather than trusted — a row in `agentDispatches` or `workerDispatches` naming this `invocationId` refuses the replacement and names the dispatch that used it. |
889
- | `okstra team dispatch --project-root <dir> --run-manifest <path> [--workers <csv>] [--jobs-file <path>] [--dry-run]` / `okstra team await --project-root <dir> --run-manifest <path> [--json]` / `okstra team teardown --project-root <dir> --run-manifest <path> [--dry-run] [--json]` | Read a `leadRuntime=external` run manifest and dispatch, await, or tear down pane-backed workers. Default dispatch excludes report writer; Phase 6 selects it explicitly, and mixed analysis/report jobs are rejected. If a pane cannot be opened, gracefully degrade to the CLI wrapper and record the fallback in `workerDispatches[].degradedFrom` |
891
+ | `okstra agent-prompt refreeze-contracts --project-root <dir> --run-manifest <path> [--json]` | Re-freeze one run's duty contract snapshot in the installed format and stamp `agentContract.catalogDigest` and `contractFormatVersion` on its run manifest. A run freezes its contracts at prepare time and pins their digest; installing a release that changed the contract format leaves that digest unmatchable, so the run can materialize no further prompt and `materialize` stops with the format message naming this command. It replaces the frozen directory's contents (no file of the old format is kept), touches no prompt, result or ledger, and reports `changed: false` when the run is already on the installed format. User-invoked recovery only — nothing runs it automatically, because a run's contracts are frozen on purpose. |
892
+ | `okstra team dispatch --project-root <dir> --run-manifest <path> [--workers <csv>] [--jobs-file <path>] [--dry-run]` / `okstra team await --project-root <dir> --run-manifest <path> [--json]` / `okstra team teardown --project-root <dir> --run-manifest <path> [--dry-run] [--json]` | Read a `leadRuntime=external` run manifest and dispatch, await, or tear down pane-backed workers. Default dispatch excludes report writer; Phase 6 selects it explicitly, and mixed analysis/report jobs are rejected. If a pane cannot be opened, gracefully degrade to the CLI wrapper, print a `DEGRADED <role>: cmux-pane -> cli-wrapper (<why>)` line, and record the fallback in `workerDispatches[].degradedFrom` with the reason in `degradedReason`. A degraded worker is not waited for inside the dispatch — it settles through `okstra team await` like a pane worker, so the round still runs concurrently |
890
893
  | `okstra agent-activity append --project-root <dir> --run-manifest <path> --kind <kind> --agent <assigned-id> (--summary <text>\|--summary-file <markdown>) --outcome <outcome> [--plan-item-id <current-id>]… [--command <text> --command-cwd <dir> --command-exit-code <n> --command-output-file <markdown>] [--request-ref <returned-ref>]` | Append one structured activity after checking the agent against this run's role assignments and every plan item against its current convergence state. Python returns an `activityRequestRef`; supply only that returned value with `--request-ref` to retry idempotently. A new call without it remains a distinct activity even with identical contents. Legacy JSON command records remain automation compatibility only. |
891
894
  | `okstra agent-activity project --project-root <dir> --run-manifest <path> --data <data.json>` | Project this run's canonical activity events into `agentActivity[]`. The command preserves event order, rejects duplicate or decreasing activity IDs, and replaces no other report field. A historical manifest without `activityContractVersion: 1` returns an empty projection and leaves data.json unchanged. Normal Phase 7 execution reaches this behavior through `report-finalize`; use the standalone command only for diagnostics. |
892
895
  | `okstra lead-progress append --project-root <dir> --run-manifest <path> --phase <phase-id> [--worker <role>] [--field NAME=VALUE]… [--detail <text>]` | Append one `PROGRESS:` checkpoint to the run's `leadEventsPath` and print the line to emit to the user as `progressLine`. The checkpoint is what `validate_session_conformance.py` reads, and on a host whose adapter declares `sessionAccounting: artifact-only` the ledger is the only place it can read one — a conversation line alone is not retained there. `--phase` accepts the phase ids the lead contract's "Progress reporting (BLOCKING)" list defines; the fixed-prose checkpoints render their contract wording without `--detail`. `--worker` is resolved against team-state and rewritten to the roster `workers[].role` the per-worker checks match, so a phase-specific functional label still lands on the right worker; a name that matches no roster row is written through with a note on stderr. |
@@ -6,8 +6,9 @@ Use this matrix before changing high-risk repo contracts. Update the source file
6
6
  |---|---|---|
7
7
  | Add CLI flag | `src/`, `scripts/okstra_ctl/run.py`, `docs/cli.md`, `prompts/wizard/` | JS CLI tests and pytest CLI contracts |
8
8
  | Add Node subcommand | `src/cli-registry.mts`, `src/commands/`, `docs/cli.md`, `docs/project-structure-overview.md` | `tests-js/cli-registry.test.mjs` plus command-specific JS/Python tests |
9
- | Add public skill | `src/lib/skill-catalog.mts`, `.claude-plugin/plugin.json`, `skills/<name>/SKILL.md`, `docs/for-ai/README.md`, `docs/project-structure-overview.md`, `README.md` | `tests-js/skill-catalog.test.mjs`, `tests/contract/test_docs_runtime_contract.py` |
10
- | Change manager contract | `scripts/okstra_ctl/manager_*.py`, `skills/okstra-manager/SKILL.md`, `docs/for-ai/skills/okstra-manager.md`, `docs/cli.md`, `docs/architecture/storage-model.md` | `tests-js/cli-wrapper-contract.test.mjs`, `tests/test_okstra_manager_*.py` |
9
+ | Add public skill | `src/lib/skill-catalog.mts`, `.claude-plugin/plugin.json`, `skills/<name>/SKILL.md`, `docs/skills/<name>.md`, `docs/skills/README.md`, `docs/project-structure-overview.md`, `README.md` | `tests-js/skill-catalog.test.mjs`, `tests/contract/test_docs_runtime_contract.py` |
10
+ | Change manager contract | `scripts/okstra_ctl/manager_*.py`, `skills/okstra-manager/SKILL.md`, `docs/skills/okstra-manager.md`, `docs/cli.md`, `docs/architecture/storage-model.md` | `tests-js/cli-wrapper-contract.test.mjs`, `tests/test_okstra_manager_*.py` |
11
+ | Change a skill's behaviour | `skills/<name>/SKILL.md`, `docs/skills/<name>.md` (every Guarantees row names its enforcement or says `unenforced`) | `tests/contract/test_skill_specs.py` |
11
12
  | Add phase | `scripts/okstra_ctl/workflow.py`, `prompts/profiles/`, `validators/`, `tests/` | workflow and validation contract tests |
12
13
  | Change worker roster | `prompts/profiles/*.md`, `scripts/okstra_ctl/workers.py`, `tests/contract/test_repo_contracts.py` | worker roster contract tests |
13
14
  | Change report section | `schemas/final-report-v2.0.schema.json`, `templates/reports/final-report-v2.template.md`, `scripts/okstra_ctl/render_final_report.py`, `validators/validate-run.py` | final-report schema, renderer, and validator tests |
@@ -227,13 +227,12 @@ Goals:
227
227
 
228
228
  Cautions:
229
229
 
230
- - Before extracting shared worker text into `agents/workers/_cli-wrapper-template.md`, confirm that install/packaging paths and skill/agent loaders support includes.
230
+ - Superseded (2026-08-13, `cf9fcfe`): the shared CLI-wrapper template and the per-provider worker parameter files this item planned to edit were removed. Worker prompts are now composed by `okstra agent-prompt materialize`, so shared worker text belongs in the materializer's inputs, not in a wrapper template.
231
231
  - Merely moving text into a separate file can increase cost if the runtime does not inline it and the worker must read another file.
232
232
 
233
233
  Change targets:
234
234
 
235
- - `agents/workers/codex-worker.params.json`
236
- - `agents/workers/antigravity-worker.params.json`
235
+ - `scripts/okstra_ctl/agent/prompt_cli/materialize.py` (replaces the removed per-provider worker parameter files)
237
236
  - `prompts/lead/team-contract.md`
238
237
  - Install/build packaging
239
238
 
@@ -138,8 +138,8 @@ Runtime/install asset changes follow this checklist:
138
138
  - `runtime/templates/*` → `~/.okstra/templates/`
139
139
  - `runtime/skills/<name>` (the fourteen user-facing skills only) → `~/.agents/skills` always, plus `~/.claude/skills` when `~/.claude` exists
140
140
  - `runtime/prompts/*` → `~/.okstra/prompts/` (lead contracts under `prompts/lead/`, coding-preflight pack under `prompts/coding-preflight/`)
141
- - the native Claude execution adapters in `runtime/agents/workers/` → `~/.claude/agents/` when `~/.claude` exists; retired provider transport-agent files are removed only when the prior install manifest owned them
142
- - install manifests → `~/.okstra/installed-skills.json` (target-aware), `~/.okstra/installed-agents.json`
141
+ - `runtime/agents/*` → `~/.okstra/agents/` (the common contract, the nine role contracts under `agents/roles/`, and the non-run operation contracts under `agents/operations/`). Nothing is written to a host-global agent discovery path such as `~/.claude/agents/`; agent definitions a previous version installed there are removed only when the prior install manifest proves okstra owned them (ADR-0017)
142
+ - install manifests → `~/.okstra/installed-skills.json` (target-aware), `~/.okstra/installed-agents.json` (now only the record of host files to reclaim)
143
143
  - version stamp → `~/.okstra/version`
144
144
 
145
145
  `--link <repo>` mode is for development and symlinks installed files back to repo sources.
@@ -166,7 +166,7 @@ The Module column below is where the command's behaviour lives — a `src/` modu
166
166
  | `install`, `ensure-installed` | `src/commands/lifecycle/install.mts` | Install or refresh runtime, skills, agents, templates |
167
167
  | `uninstall` | `src/commands/lifecycle/uninstall.mts` | Remove managed runtime/skills/agents, optionally purge data |
168
168
  | `doctor` | `src/commands/lifecycle/doctor.mts` | Diagnose runtime and Python imports |
169
- | `setup` | `src/commands/lifecycle/setup.mts` | Create/update `<PROJECT_ROOT>/.okstra/project.json` |
169
+ | `setup` | `src/commands/lifecycle/setup.mts` | Create/update `<PROJECT_ROOT>/.okstra/project.json`; also appends/refreshes the okstra citation-guidance block in an existing `CLAUDE.md` / `AGENTS.md` via `src/lib/citation-guidance.mts` (neither file is created) |
170
170
  | `check-project` | `src/commands/lifecycle/check-project.mts` | Verify project registration |
171
171
  | `preflight` | `src/commands/lifecycle/preflight.mts` | One-call skill preflight: ensure-installed + check-project + host-specific runtime readiness (single JSON) |
172
172
  | `config` | `src/commands/lifecycle/config.mts` | Read/write project/global settings such as PR template path |
@@ -327,7 +327,7 @@ Important modules:
327
327
  | `plan_run_root.py` | shared helper deriving `approved_plan_path` → `plan_run_root` and back-tracing the task-key |
328
328
  | `manager_cli.py` | `okstra manager` Python entrypoint — purpose-specific fixed text by default, machine JSON with `--json` |
329
329
  | `manager_paths.py` | Manager state path SSOT under `~/.okstra/managers/<manager-id>/`; slug fallback uses `u-<sha1-prefix>` when a safe segment would be empty |
330
- | `manager_store.py` | Manager-owned state mutation — project membership, task planning, assignment, directives, event append — plus the `list managers/projects/tasks` readers |
330
+ | `manager_store.py` | Manager-owned state mutation — project membership, task planning, assignment, directives, event append — plus the `list managers/projects/task-groups/tasks` readers, `task update`, and the `remove project/task/task-group` and `task remove-child` operations |
331
331
  | `manager_sync.py` | One-way child project `.okstra` snapshot reader; corrupt child state becomes row-level `error` so other children continue |
332
332
  | `manager_launch.py` | Child launch packet and manager child context renderer; records `prepared` launch metadata/events without changing project-local task state |
333
333
  | `manager_view.py` | `okstra manager view` — renders one manager's projects, tasks, child summaries, directives and events into `view/index.html` from `templates/manager/view.template.html`; reads manager-owned files only |
@@ -383,6 +383,31 @@ Important modules:
383
383
  | `json_boundary.py` | strict JSON persistence boundaries for okstra-owned artifacts — a sealed `ExternalJsonSource` (validated producer + path) is the only way owned JSON is read, and `JsonBoundaryError` names artifact / reason / path when a write cannot satisfy its contract; the SSOT that keeps the model out of internal JSON key/path authorship |
384
384
  | `fixed_text.py` | shared scalar-line format for the model-facing fixed-text projections — `scalar` neutralises complex values and control characters (backticks escaped for the code span `line` wraps it in), `block` projects a prose body outside any code span with its backticks intact, `line` renders one static-labelled Markdown list row, and `value_lines` losslessly flattens a JSON-shaped value into fixed name/order/value rows |
385
385
  | `model_io_cli.py`, `model_io/` | renders purpose-scoped fixed Markdown input from okstra-owned JSON for the model boundary — resolves the current run/project through the run manifest (`validated_run_authority`, `canonical_run_state_artifact`) and emits only each command's allow-listed fields in fixed order instead of expanding arbitrary nested objects. `model_io_cli.py` is the argparse surface only; inside the package, `references` resolves paths and reads JSON, `lines` turns an already-read mapping into fixed Markdown and opens nothing, and `renderers` composes the two into one function per command |
386
+ | `assignment_environment.py` | loads ambient host-adapter facts once, outside the deterministic assignment logic; read by `run.py`, `dispatch_core.py`, the wizard's role step, and `agent-prompt materialize` |
387
+ | `execution_identity.py` | provider-neutral execution identity value objects — participant assignment, role execution, invocation, attempt, execution manifest — and their versioned readers |
388
+ | `attempt_evidence.py` | atomic attempt-evidence seals and the orchestrator-owned host event streams written around each worker attempt |
389
+ | `execution_mutation_audit.py` | batch-scoped source and Git mutation audit for worker invocations (snapshots taken around a dispatch batch) |
390
+ | `mutation_recovery.py` | recovery decisions after a sealed or unsealed implementer attempt that mutated source |
391
+ | `write_policy.py` | canonical invocation write policy — which paths an invocation may write — and the enforcement the runner truthfully reports; read by the provider wrapper, `worker_request.py`, `dispatch_core.py`, and report assembly |
392
+ | `role_requirements.py` | parses the canonical role requirements that phase profiles declare |
393
+ | `model_defaults.py` | pure replacement of role-model default scopes |
394
+ | `legacy_model_selection.py` | normalises canonical role selections and legacy provider CLI flags into one selection |
395
+ | `validation_contract.py` | the validation contract version pinned at prepare time (`CURRENT_VALIDATION_CONTRACT_VERSION`) |
396
+ | `usage_identity.py` | projects usage rows from stored execution-identity refs; shared by usage-report, time-report, error-report, and the token collector |
397
+ | `user_response_values.py` | value types and parsers of the `user-responses/` sidecar |
398
+ | `stage_map_view.py` | read-side Stage Map view behind `okstra stage-map` |
399
+ | `lead_progress.py` | `okstra lead-progress append` — records the lead's `PROGRESS:` checkpoints in the lead-events ledger |
400
+ | `plan_verify_cli.py` | `okstra plan-verify` entry point |
401
+ | `doctor_cli.py` | diagnostic projection that `okstra doctor` (`src/commands/lifecycle/doctor.mts`) calls |
402
+ | `worktree_cli.py` | handlers behind `okstra worktree-lookup` and `okstra worktree-status` |
403
+ | `interactive_cli.py` | lookup helpers for the `okstra.sh` interactive input path (`scripts/lib/okstra/interactive.sh`) |
404
+ | `brief_frontmatter.py` | shared lightweight parser for a brief's frontmatter; read by `run.py`, direct completion, the task-group context, the wizard's brief suggestions, and the improvement-report validator |
405
+ | `convergence_provenance.py` | Round-0 grouping provenance — checks that every source item a group cites exists in the canonical worker result; shared by the convergence engine, the critic prompts, and `validate-run.py` |
406
+ | `verdict_blocks.py` | parser for the worker verdict block that plan-body verification and convergence re-verification share |
407
+ | `worker_artifacts.py` | the roster worker-id vocabulary and the artifact paths derived from it |
408
+ | `worker_state.py` | `okstra worker-state transition` — the authoritative status transitions of one persisted team-state |
409
+ | `usage_cells.py` | how a token, cost, or duration figure reads in a report cell; shared by the Markdown and HTML report renderers |
410
+ | `report_contract.py` | single registry of the public final-report task contracts, read by prepare, rendering, approval decisions, and the report synthesis packet |
386
411
 
387
412
  > `i18n.py` (the final-report i18n dictionary loader + Jinja2 lookup) is an intentionally undocumented internal helper — it is a render helper that users and contributors do not need to know about in the canonical docs, so it is excluded from the module map.
388
413
 
@@ -433,6 +458,8 @@ Token/cost accounting:
433
458
  | `templates/worker-prompt-preamble.md` | Initial analysis audience procedure and output contract |
434
459
  | `templates/implementation-worker-preamble.md` | Shared implementation executor/verifier procedure, including coding-preflight and worktree rules |
435
460
  | `templates/report-writer-prompt-preamble.md` | Report-writer input and authoring procedure without analysis or implementation instructions |
461
+ | `templates/translator-prompt-preamble.md` | Translator output ownership and translation conduct, delivered to every provider regardless of host |
462
+ | `scripts/okstra_ctl/adapters/hosts/claude-code/worker-session.md` | Rules that hold because a worker runs inside the lead's Claude Code session; delivered to `runner=native-session` prompts only |
436
463
  | `templates/worker-error-contract.md` | Audience-neutral error-path, sidecar schema, and write protocol shared by every initial worker |
437
464
 
438
465
  ### 4.8 `schemas/`
@@ -490,11 +517,11 @@ Boilerplate shared by several skills (bash invocation rule, outdated-CLI preflig
490
517
 
491
518
  | File | Role |
492
519
  |---|---|
493
- | `agents/workers/claude-worker.md` | Claude analyzer/verifier/executor spec |
494
- | `agents/workers/report-writer-worker.md` | data.json SSOT author and audit sidecar writer |
495
- | `agents/workers/translator-worker.md` | Claude-native final-report translation execution adapter |
520
+ | `agents/common.json` | The contract every okstra LLM call carries, ahead of role and duty |
521
+ | `agents/roles/<role>.json` | One of the nine canonical roles: identity, responsibilities, required capabilities, prohibitions |
522
+ | `agents/operations/<operation>.json` | A non-run operation's duty and worker count (`okstra agent-prompt resolve-operation`) |
496
523
 
497
- These files are native Claude execution adapters, not provider-neutral LLM transport wrappers. Non-native providers execute through the deterministic `worker-dispatch` process boundary. The neutral lead lifecycle contract lives at `prompts/lead/okstra-lead-contract.md`. Executable host strategies and their relay contracts live together under `scripts/okstra_ctl/adapters/hosts/<host-id>/`; `prompts/lead/adapters/cmux.md` remains the environment-selected cmux worker-backend contract. Lead resources are installed under `~/.okstra/prompts/lead/`, while executable host adapters are installed under `~/.okstra/lib/python/okstra_ctl/adapters/hosts/`. They are runtime resources, not agent skills.
524
+ These are provider-neutral contracts rendered into every dispatch prompt, not host agent definitions: okstra registers nothing in a host-global discovery path (ADR-0017). Non-native providers execute through the deterministic `worker-dispatch` process boundary. The neutral lead lifecycle contract lives at `prompts/lead/okstra-lead-contract.md`. Executable host strategies and their relay contracts live together under `scripts/okstra_ctl/adapters/hosts/<host-id>/`; `prompts/lead/adapters/cmux.md` remains the environment-selected cmux worker-backend contract. Lead resources are installed under `~/.okstra/prompts/lead/`, while executable host adapters are installed under `~/.okstra/lib/python/okstra_ctl/adapters/hosts/`. They are runtime resources, not agent skills.
498
525
 
499
526
  ### 4.12 `tests/` and `tests-e2e/`
500
527
 
@@ -589,7 +616,6 @@ Both Markdown and HTML are derived, not authoring sources. The schema is the con
589
616
  - `scripts/okstra_ctl/domain/role.py` — canonical roles and duty mapping.
590
617
  - `scripts/okstra_ctl/model_pool.py` — unified catalog lookup.
591
618
  - `scripts/okstra_ctl/model_cli.py` — `okstra model list` and atomic `modelDefaults` writes. No inference call.
592
- - `scripts/okstra_ctl/pane_title.py` — pane titles from stored `executionLabel`.
593
619
  - `scripts/okstra_ctl/doctor.py` — `model_pool_diagnostics()` for `okstra doctor --json`.
594
620
 
595
621
  ---
@@ -55,7 +55,7 @@ Launch selection is role slots and model refs, not a provider roster. The wizard
55
55
  | okstra-run skill procedure | [`skills/okstra-run/SKILL.md`](../../skills/okstra-run/SKILL.md) |
56
56
  | wizard state machine | [`scripts/okstra_ctl/wizard/`](../../scripts/okstra_ctl/wizard/) |
57
57
  | wizard prompt text | [`prompts/wizard/prompts.ko.json`](../../prompts/wizard/prompts.ko.json) |
58
- | render-bundle Node shim | [`src/commands/execute/render-bundle.mjs`](../../src/commands/execute/render-bundle.mjs) |
58
+ | render-bundle Node shim | [`src/commands/execute/render-bundle.mts`](../../src/commands/execute/render-bundle.mts) |
59
59
  | single entrypoint for bundle creation | [`scripts/okstra_ctl/run.py`](../../scripts/okstra_ctl/run.py) |
60
60
  | implementation stage selection/provisioning | [`scripts/okstra_ctl/implementation_stage.py`](../../scripts/okstra_ctl/implementation_stage.py) |
61
61
  | Stage Lifecycle Snapshot + stage target/base/verification policy | [`scripts/okstra_ctl/stage_targets.py`](../../scripts/okstra_ctl/stage_targets.py) |
@@ -95,7 +95,7 @@ sequenceDiagram
95
95
  Skill->>FS: read lead-execution-prompt.md
96
96
  ```
97
97
 
98
- The Node shim for `render-bundle` is [`src/commands/execute/render-bundle.mjs`](../../src/commands/execute/render-bundle.mjs). This shim attaches the `--workspace-root`, `--render-only`, and runtime resolution arguments directly. As a result, on the okstra-run path the initial run status starts at `prepared` and the task status starts at `ready-for-lead`.
98
+ The Node shim for `render-bundle` is [`src/commands/execute/render-bundle.mts`](../../src/commands/execute/render-bundle.mts). This shim attaches the `--workspace-root`, `--render-only`, and runtime resolution arguments directly. As a result, on the okstra-run path the initial run status starts at `prepared` and the task status starts at `ready-for-lead`.
99
99
 
100
100
  ## 5. Okstra lead phase 1-7
101
101
 
@@ -118,10 +118,12 @@ flowchart TD
118
118
 
119
119
  `## 7. Final Verdict` must contain exactly one `Verdict Token` field, and its value is one of the following three.
120
120
 
121
- - `accepted`: a state that becomes a candidate for plain `release-handoff` when whole-task, or `release-handoff(stage-group)` when single-stage
121
+ - `accepted`: a state that becomes a release-handoff candidate — whole-task for every stage it covers, single-stage for that one stage's PR
122
122
  - `conditional-accept`: all conditions must be stated explicitly, and when a condition is a gate it blocks the next phase
123
123
  - `blocked`: a state that has acceptance blockers and cannot proceed to release-handoff
124
124
 
125
+ A blocked or conditional run routes to the phase that owns the defect. When every remaining blocker is an environment or configuration fault this report already diagnosed - a `qaCommands` entry naming a path that no longer exists, a missing credential, a stale fixture - the target is `final-verification` itself: repair the configuration and re-verify the same head, rather than spending a root-cause phase on a cause that is already known.
126
+
125
127
  Vague phrasings such as "looks good" or "mostly ready" are not allowed.
126
128
 
127
129
  ## 6. Deliverables
@@ -170,7 +170,7 @@ flowchart LR
170
170
 
171
171
  Stage selection is `auto` or a number. If `--stage` comes from another task-type, it is a `PrepareError`. The runtime reads `done`/`started` of `consumers.jsonl`, carry sidecar backfill, and the active stage-key of the registry together in the Stage Lifecycle Snapshot, and excludes occupied stages. The Snapshot is not a new stored file but a read-side view of `stage_targets.py`.
172
172
 
173
- The stage worktree base is decided by dependency shape. An independent stage uses the task-key worktree HEAD fixed at first implementation entry as its anchor, and a single-dependency stage branches from the predecessor stage's done `head_commit`. A multi-dependency stage branches from the task-key worktree HEAD after confirming that every predecessor done commit is an ancestor of that HEAD.
173
+ The stage worktree base is decided by dependency shape. An independent stage uses the task-key worktree HEAD fixed at first implementation entry as its anchor, and a single-dependency stage branches from the predecessor stage's done `head_commit`. A multi-dependency stage branches from a commit holding exactly its predecessors: the predecessor commit that already contains the others, or else an integration branch merging them (`<work-category-namespace>/<task-id-segment>-g<n1>-<n2>`). okstra creates that branch itself, so a predecessor that has not been merged into the task branch no longer blocks the stage; release-handoff later reuses the same branch as that stage's PR base.
174
174
 
175
175
  ## 6. Deliverables
176
176
 
@@ -14,7 +14,9 @@
14
14
 
15
15
  ## 1. Purpose
16
16
 
17
- `release-handoff` is the terminal phase that pushes an already-committed implementation result with a release-ready verdict, or hands it off as a PR. whole-task mode packages the verified task branch as-is. stage-group mode can assemble the selected stages into a collector branch and bundle them into a single PR, and the merge commit created here is produced only by `okstra handoff assemble`.
17
+ `release-handoff` is the terminal phase that pushes already-committed implementation stages with a release-ready verdict, or hands them off as pull requests. **One stage is one PR.** The PR head is that stage's stack branch; the base comes from its `depends-on` — the release base for a stage with no live dependency, the predecessor's branch for a stage with one (a stacked PR), and a branch merging the predecessors for a stage with several. The only commits this phase may create are the merge commits `okstra handoff pr-plan` makes on such a merge-base branch.
18
+
19
+ Because the PRs are a stack, they must be merged in ascending stage order with a merge commit or a rebase-merge. A squash replaces the commits the next PR's base points at, so the stack breaks — every PR body states this, and the lead never merges.
18
20
 
19
21
  This phase has no worker dispatch. It does not use a provider or report-writer roster; the host-native Okstra lead performs git/gh inspection, user questions, the PR draft, and the final report inline.
20
22
 
@@ -25,7 +27,7 @@ flowchart TD
25
27
  Start[/okstra-run/] --> Common[common task identity flow]
26
28
  Common --> Type[task-type = release-handoff]
27
29
  Type --> Plan[approved plan auto/pick]
28
- Plan --> Scope[handoff stage pick<br/>whole-task or eligible stages]
30
+ Plan --> Scope[handoff stage pick<br/>eligible stages, one PR each]
29
31
  Scope --> Worktree{active task worktree?}
30
32
  Worktree -->|yes| RoleCount[role-count min..max<br/>omit uses recommended; skip if min==max]
31
33
  Worktree -->|no| BaseRef[base-ref pick/text]
@@ -39,7 +41,7 @@ flowchart TD
39
41
  Confirm --> Render[render-bundle]
40
42
  ```
41
43
 
42
- `release-handoff` has no analysis-worker dispatch. Launch selection still shows any applicable role-count / role-model steps; current-session lead is this session and is listed on the confirmation summary. There is no provider roster multi-pick and no `Use defaults / Customize` fork. Dynamic verifiers are not chosen at launch. `--workers` is not a launch picker, and the runtime forces the worker list to empty. The wizard outcome's `renderArgs` includes `pr-template-path` only for release-handoff. Scope selection finishes before prepare, and the project/global save runs before `render-bundle` via the `config.set pr-template-path` action of `outcome.persistActions[]`. whole-task requires an accepted whole-task verification report, and for stage-group only the stages that were marked `verified` by an accepted single-stage verification in the Stage Lifecycle Snapshot but not yet covered by a `pr` become candidates.
44
+ `release-handoff` has no analysis-worker dispatch. Launch selection still shows any applicable role-count / role-model steps; current-session lead is this session and is listed on the confirmation summary. There is no provider roster multi-pick and no `Use defaults / Customize` fork. Dynamic verifiers are not chosen at launch. `--workers` is not a launch picker, and the runtime forces the worker list to empty. The wizard outcome's `renderArgs` includes `pr-template-path` only for release-handoff. Scope selection finishes before prepare, and the project/global save runs before `render-bundle` via the `config.set pr-template-path` action of `outcome.persistActions[]`. Only the stages that were marked `verified` by an accepted single-stage verification in the Stage Lifecycle Snapshot and are not yet covered by a `pr` become candidates; leaving `--stages` empty takes all of them.
43
45
 
44
46
  Note that this phase is also a target of task worktree provisioning. The normal flow reuses the implementation/final-verification result of the same task-key. Starting a new task may create a new branch, and it is likely to be blocked at the entry gate's "implementation commit exists" condition.
45
47
 
@@ -74,26 +76,21 @@ flowchart TD
74
76
  Source -->|no| Block[blocked<br/>route final-verification]
75
77
  Source -->|yes| Verdict{Verdict Token == accepted?}
76
78
  Verdict -->|no| Block
77
- Verdict -->|yes| Mode{HANDOFF_MODE}
78
- Mode -->|stage-group| Eligible[each selected stage<br/>verified and not in PR]
79
- Mode -->|whole-task| Status{git status --short clean?}
80
- Eligible --> Status
79
+ Verdict -->|yes| Eligible[each selected stage<br/>verified and not in PR]
80
+ Eligible --> Status{git status --short clean?}
81
81
  Status -->|no| Dirty[blocked<br/>dirty tree]
82
- Status -->|yes| Branch{current branch is base branch?}
83
- Branch -->|yes| BaseBlock[blocked<br/>never operate on base branch]
84
- Branch -->|no| Commits{git log base..HEAD non-empty?}
82
+ Status -->|yes| Commits{each stage has commits<br/>over its own base?}
85
83
  Commits -->|no| ImplBlock[blocked<br/>route implementation]
86
84
  Commits -->|yes| Ready[handoff questions may begin]
87
85
  ```
88
86
 
89
87
  Before asking the user whether to push/PR, the lead confirms the following.
90
88
 
91
- - The `## Source Verification Report` of the input document (`release-handoff-input.md`) generated by prepare contains the mode (`HANDOFF_MODE`) and the cited report table. The brief is the input of the entry phase, so it does not exist in release-handoff — the user's stage selection finishes before prepare via the wizard `handoff_stage_pick` or the CLI `--stages`.
92
- - In whole-task mode, the latest verification execution must have passed validation and carry a release-ready `verificationScope=whole-task` report. A newer unfinished, broken, or blocked execution prevents fallback to an older success. The lead compares the delivery branch tip with the captured verification commit at entry and before push.
93
- - In stage-group mode, each cited single-stage report must be the latest validated execution for that stage and must match the recorded implementation commit. Prepare and `okstra handoff assemble` re-check this evidence and the dependency closure. A new implementation start or completion invalidates the earlier approval.
89
+ - The `## Source Verification Report` of the input document (`release-handoff-input.md`) generated by prepare lists the selected stages (`HANDOFF_STAGES`) and the cited report table. The brief is the input of the entry phase, so it does not exist in release-handoff — the user's stage selection finishes before prepare via the wizard `handoff_stage_pick` or the CLI `--stages` (empty takes every eligible stage).
90
+ - Each cited single-stage report must be the latest validated execution for that stage and must match the recorded implementation commit. A newer unfinished, broken, or blocked execution prevents fallback to an older success. Prepare and `okstra handoff pr-plan` re-check this evidence. A new implementation start or completion invalidates the earlier approval.
94
91
  - The working tree is clean.
95
- - The current branch is not a base branch such as `main`, `master`, `prod`, `preprod`, `staging`, or `dev`.
96
- - The `<base>..HEAD` commit range is non-empty.
92
+ - The current branch is recorded as evidence, not used as a PR head: every head comes from `okstra handoff pr-plan`. A release base branch such as `main`, `master`, `prod`, `preprod`, `staging`, or `dev` is never pushed.
93
+ - Each stage's `<base_commit>..<head_commit>` range is non-empty.
97
94
 
98
95
  `accepted` is release-ready. `conditional-accept` is release-ready only when its non-empty condition list explicitly sets every `blocksReleaseHandoff` to `false`; those conditions remain in the generated input and PR body. `blocked`, missing conditions, and ambiguous verdicts stop delivery. `okstra_ctl.release_gate.release_handoff_allowed` owns this rule.
99
96
 
@@ -107,12 +104,10 @@ stateDiagram-v2
107
104
  Gate --> Q1: action selection
108
105
  Q1 --> LocalCheckout: local checkout
109
106
  Q1 --> Skip: skip
110
- Q1 --> Q2: push + PR whole-task
111
- Q1 --> G2: push + PR stage-group
112
- state "base select + stage confirmation / okstra handoff assemble" as Assemble
113
- G2 --> Assemble
114
- Assemble --> Q3: collector branch ready
115
- Q2 --> Probe: choose PR base
107
+ Q1 --> Q2: push + PR
108
+ state "okstra handoff pr-plan (head/base per stage)" as Plan
109
+ Q2 --> Plan: choose release base
110
+ Plan --> Probe: rows ready
116
111
  Probe --> Q3: no conflict
117
112
  Probe --> Conflict: conflict detected
118
113
  Conflict --> Q2: change base branch
@@ -120,8 +115,8 @@ stateDiagram-v2
120
115
  Conflict --> Cancel: cancel
121
116
  Q3 --> Push: use as-is or edit then proceed
122
117
  Q3 --> Cancel: cancel
123
- Push --> ReuseOrCreate: git push feature branch
124
- ReuseOrCreate --> FinalReport: gh pr list / gh pr create
118
+ Push --> ReuseOrCreate: push each branch in stage order
119
+ ReuseOrCreate --> FinalReport: gh pr list / gh pr create per stage
125
120
  LocalCheckout --> FinalReport
126
121
  Skip --> FinalReport
127
122
  Cancel --> FinalReport
@@ -131,18 +126,18 @@ stateDiagram-v2
131
126
  User interaction is exactly three steps.
132
127
 
133
128
  1. Q1 action: `local checkout`, `push + PR`, `skip`
134
- 2. Q2 PR base: a branch from the profile menu such as `staging`, `preprod`, `main`, or Enter directly
135
- 3. Q3 PR title/body: `use as-is`, `edit then proceed`, `cancel`
129
+ 2. Q2 release base: a branch from the profile menu such as `staging`, `preprod`, `main`, or Enter directly
130
+ 3. Q3 PR title/body: every stage's draft in one question — `use as-is`, `edit then proceed`, `cancel`
136
131
 
137
- The merge-conflict probe happens only for `push + PR`.
132
+ The merge-conflict probe happens only for `push + PR`, once per stage against that stage's own base.
138
133
 
139
- In stage-group mode, `local checkout` is not offered. After choosing `push + PR`, first select the PR base, confirm the already-fixed `HANDOFF_STAGES`, and then `okstra handoff assemble` creates the collector branch. After that, the conflict probe and PR title/body confirmation take the collector branch as head.
134
+ `local checkout` takes one stage and hands that stage's branch to the main worktree; there is no whole-task target.
140
135
 
141
136
  ```mermaid
142
137
  flowchart TD
143
138
  PushPR[push + PR selected] --> Fetch[git fetch origin chosen-base]
144
- Fetch --> MergeTree[git merge-tree --write-tree<br/>handoff-branch origin/base]
145
- MergeTree --> Conflict{conflict?}
139
+ Fetch --> MergeTree[git merge-tree --write-tree<br/>stage head vs its own PR base]
140
+ MergeTree --> Conflict{any stage conflicts?}
146
141
  Conflict -->|no| Draft[show PR draft]
147
142
  Conflict -->|yes| Ask[ask proceed/change base/cancel]
148
143
  Ask -->|proceed anyway| Draft
@@ -177,21 +172,21 @@ flowchart TD
177
172
  Commands[git/gh commands + exit codes] --> Report
178
173
  Commits[git log base..HEAD commit list] --> Report
179
174
  Probe[Merge Conflict Probe] --> Report
180
- PR[PR created / reused / skipped] --> Report
175
+ PR[one PR row per stage:<br/>created / reused / skipped] --> Report
181
176
  Report --> Done[routing recommendation: done]
182
177
  ```
183
178
 
184
179
  The final report requires at least the following.
185
180
 
186
- - originating final-verification report path and quoted `accepted` verdict row
187
- - handoff mode (`whole-task` or `stage-group`) and selected stages
188
- - feature branch and run start `git status --short`
181
+ - per selected stage, the originating final-verification report path and its quoted verdict row
182
+ - the selected stages and the chosen release base
183
+ - the pr-plan rows: stage, head branch, base kind, base branch — the merge order of the stack
184
+ - the run's current branch and run start `git status --short`
189
185
  - record of user selections
190
186
  - all executed git/gh commands and exit codes
191
- - implementation commit list
187
+ - the implementation commit list, attributed per stage
192
188
  - merge-conflict probe result
193
- - for stage-group, the collector branch, merge commit SHA, and dependency-closure result
194
- - PR created, reused, or skipped result
189
+ - one PR outcome row per stage: created, reused, or skipped
195
190
  - routing recommendation `done`
196
191
 
197
192
  ## 8. Forbidden actions
@@ -201,12 +196,13 @@ flowchart TD
201
196
  RH[release-handoff] --> Allowed[read git/gh, fetch base, merge-tree probe,<br/>push feature branch, create/reuse PR]
202
197
  RH -. forbidden .-> Commit[git add / commit / stash]
203
198
  RH -. forbidden .-> Force[force push or +refspec]
204
- RH -. forbidden .-> BasePush[push directly to base branch]
199
+ RH -. forbidden .-> BasePush[push directly to a release base branch]
205
200
  RH -. forbidden .-> NoVerify[--no-verify / -n]
206
201
  RH -. forbidden .-> Publish[release publish / deploy]
207
202
  RH -. forbidden .-> Edit[source edit]
208
203
  RH -. forbidden .-> Team[TeamCreate or Agent dispatch]
209
- RH -. forbidden .-> Merge[gh pr merge]
204
+ RH -. forbidden .-> Merge[gh pr merge or squash-merge]
205
+ RH -. forbidden .-> Rewrite[rebase / amend / cherry-pick a stage branch]
210
206
  ```
211
207
 
212
208
  A failed `git push` must not be retried with weaker safeguards. When a failure such as non-fast-forward occurs, stop and take the user's instruction, and `--force`-family flags are forbidden even if the user requests them.
@@ -219,5 +215,6 @@ A failed `git push` must not be retried with weaker safeguards. When a failure s
219
215
  - [`scripts/okstra_ctl/wizard/`](../../scripts/okstra_ctl/wizard/)
220
216
  - [`scripts/okstra_ctl/run.py`](../../scripts/okstra_ctl/run.py)
221
217
  - [`scripts/okstra_ctl/pr_template.py`](../../scripts/okstra_ctl/pr_template.py)
222
- - [`src/commands/lifecycle/config.mjs`](../../src/commands/lifecycle/config.mjs)
218
+ - [`src/commands/lifecycle/config.mts`](../../src/commands/lifecycle/config.mts)
219
+ - [`scripts/okstra_ctl/handoff.py`](../../scripts/okstra_ctl/handoff.py)
223
220
  - [`scripts/okstra_ctl/worktree/`](../../scripts/okstra_ctl/worktree/)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "okstra",
3
- "version": "0.202.0",
3
+ "version": "0.204.0",
4
4
  "description": "Host-aware multi-provider cross-verification orchestrator runtime and agent skills.",
5
5
  "license": "MIT",
6
6
  "author": "devonshin",
@@ -23,7 +23,6 @@
23
23
  "docs/container.md",
24
24
  "docs/contributor-change-matrix.md",
25
25
  "docs/follow-ups/2026-07-10-final-report-option-3.md",
26
- "docs/for-ai/",
27
26
  "docs/performance-improvement-plan-v2.md",
28
27
  "docs/pr-template-usage.md",
29
28
  "docs/project-structure-overview.md",
@@ -1,5 +1,5 @@
1
1
  {
2
- "package": "0.202.0",
3
- "builtAt": "2026-09-19T06:41:23.090Z",
2
+ "package": "0.204.0",
3
+ "builtAt": "2026-09-24T03:40:07.902Z",
4
4
  "repoRoot": "/home/runner/work/okstra/okstra"
5
5
  }
@@ -0,0 +1,28 @@
1
+ {
2
+ "schemaVersion": "1.0",
3
+ "id": "common",
4
+ "assignmentFidelity": [
5
+ "Perform the assigned work exactly as scoped. Preserve explicit inclusions, exclusions, priorities, and acceptance conditions, and stay inside the project's established architecture, terminology, and ownership boundaries. Do not silently broaden, narrow, replace, or reinterpret the assignment; prefer the smallest change that satisfies it over a novel abstraction or unrelated cleanup."
6
+ ],
7
+ "requiredInputs": [
8
+ "Read every required input before acting and cover it completely. Report a missing, unreadable, stale, or contradictory input instead of inventing its contents or relying on an expected shape."
9
+ ],
10
+ "evidenceFirst": [
11
+ "Base conclusions on inspected inputs and observed results. Trace material claims to concrete evidence, prefer stronger evidence over repetition or vote count, and distinguish verified facts from inferences and unknowns. Prioritize the checks that can change the outcome; a settled fact does not need re-verification without a stated cause."
12
+ ],
13
+ "authorityAndScope": [
14
+ "Use only the permissions, tools, and project scope granted by the invocation. Do not perform unrelated work, assume missing authority, or take outward-facing action unless the assignment explicitly authorizes it."
15
+ ],
16
+ "collaborationAndIndependence": [
17
+ "Respect the boundaries of every assigned duty. Produce independent judgment when independence is required, do not seed or coordinate another agent's conclusion, preserve evidence-backed dissent, and do not transfer your own required decision to another role."
18
+ ],
19
+ "instructionPrecedence": [
20
+ "When this contract and the task instructions both govern one action, the task instructions win: they are written for this invocation and name the concrete procedure, exemption, gate, or artifact this contract states only in general terms. What no task instruction may grant is the authority, independence, and honesty boundaries above — an instruction that widens one of those is a conflict to report, not an override to apply."
21
+ ],
22
+ "conflictHandling": [
23
+ "When instructions conflict, preserve safety, evidence, and the boundaries this contract reserves. Identify the exact conflict, continue any separable safe work, and return the smallest unresolved decision to the responsible lead."
24
+ ],
25
+ "completionHonesty": [
26
+ "Do not report unperformed work as complete, and do not stop at a plausible partial result: carry the assignment through every required check and deliverable, recovering from safe local failures where possible. Name remaining work, failed or skipped checks, unresolved uncertainty, and blockers precisely, including their effect on the requested outcome."
27
+ ]
28
+ }