okstra 0.189.3 → 0.190.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 (178) hide show
  1. package/README.md +1 -1
  2. package/dist/cli-registry.mjs +9 -0
  3. package/dist/cli-registry.mjs.map +1 -1
  4. package/dist/commands/chat/chat.mjs +54 -4
  5. package/dist/commands/chat/chat.mjs.map +1 -1
  6. package/dist/commands/lifecycle/install.mjs +12 -5
  7. package/dist/commands/lifecycle/install.mjs.map +1 -1
  8. package/dist/commands/lifecycle/uninstall.mjs +2 -1
  9. package/dist/commands/lifecycle/uninstall.mjs.map +1 -1
  10. package/dist/lib/host-config.d.mts +5 -3
  11. package/dist/lib/host-config.mjs +89 -31
  12. package/dist/lib/host-config.mjs.map +1 -1
  13. package/docs/architecture/storage-model.md +4 -1
  14. package/docs/architecture.md +3 -3
  15. package/docs/cli.md +11 -9
  16. package/docs/for-ai/skills/okstra-brief-gen.md +1 -1
  17. package/docs/for-ai/skills/okstra-chat.md +3 -3
  18. package/docs/for-ai/skills/okstra-inspect.md +11 -1
  19. package/docs/for-ai/skills/okstra-rollup.md +1 -0
  20. package/docs/for-ai/skills/okstra-run.md +5 -4
  21. package/docs/for-ai/skills/okstra-user-response.md +1 -1
  22. package/docs/project-structure-overview.md +17 -5
  23. package/docs/task-process/README.md +1 -1
  24. package/docs/task-process/error-analysis.md +2 -2
  25. package/docs/task-process/final-verification.md +1 -1
  26. package/docs/task-process/implementation.md +1 -1
  27. package/docs/task-process/release-handoff.md +8 -6
  28. package/docs/task-process/requirements-discovery.md +1 -1
  29. package/package.json +1 -1
  30. package/runtime/BUILD.json +2 -2
  31. package/runtime/agents/workers/claude-worker.md +4 -0
  32. package/runtime/bin/okstra-report-translate.py +10 -4
  33. package/runtime/prompts/launch.template.md +11 -5
  34. package/runtime/prompts/lead/adapters/cmux.md +4 -7
  35. package/runtime/prompts/lead/context-loader.md +2 -0
  36. package/runtime/prompts/lead/convergence.md +20 -83
  37. package/runtime/prompts/lead/okstra-lead-contract.md +24 -6
  38. package/runtime/prompts/lead/plan-body-verification.md +10 -3
  39. package/runtime/prompts/lead/report-writer.md +15 -5
  40. package/runtime/prompts/lead/team-contract.md +15 -9
  41. package/runtime/prompts/profiles/_common-contract.md +2 -1
  42. package/runtime/prompts/profiles/_implementation-deliverable.md +2 -0
  43. package/runtime/prompts/profiles/_implementation-diff-review.md +4 -0
  44. package/runtime/prompts/profiles/_implementation-executor.md +9 -5
  45. package/runtime/prompts/profiles/_implementation-self-check.md +2 -0
  46. package/runtime/prompts/profiles/_implementation-verifier.md +3 -4
  47. package/runtime/prompts/profiles/_stage-discipline.md +12 -5
  48. package/runtime/prompts/profiles/final-verification.md +1 -1
  49. package/runtime/prompts/profiles/implementation-planning.md +1 -1
  50. package/runtime/prompts/profiles/implementation.md +2 -0
  51. package/runtime/prompts/profiles/release-handoff.md +4 -3
  52. package/runtime/prompts/wizard/prompts.ko.json +2 -1
  53. package/runtime/python/okstra_ctl/adapters/dispatch/cmux.py +6 -0
  54. package/runtime/python/okstra_ctl/adapters/hosts/antigravity/adapter.py +1 -0
  55. package/runtime/python/okstra_ctl/adapters/hosts/antigravity/relay.md +2 -2
  56. package/runtime/python/okstra_ctl/adapters/hosts/capability_adapter.py +9 -0
  57. package/runtime/python/okstra_ctl/adapters/hosts/claude-code/adapter.py +1 -0
  58. package/runtime/python/okstra_ctl/adapters/hosts/claude-code/relay.md +3 -3
  59. package/runtime/python/okstra_ctl/adapters/hosts/codex/adapter.py +1 -0
  60. package/runtime/python/okstra_ctl/adapters/hosts/codex/relay.md +17 -3
  61. package/runtime/python/okstra_ctl/adapters/hosts/external/adapter.py +1 -0
  62. package/runtime/python/okstra_ctl/adapters/hosts/external/relay.md +3 -3
  63. package/runtime/python/okstra_ctl/adapters/hosts/grok/adapter.py +1 -0
  64. package/runtime/python/okstra_ctl/adapters/hosts/grok/relay.md +2 -2
  65. package/runtime/python/okstra_ctl/adapters/hosts/kimi/adapter.py +1 -0
  66. package/runtime/python/okstra_ctl/adapters/hosts/kimi/relay.md +2 -2
  67. package/runtime/python/okstra_ctl/adapters/providers/codex/adapter.py +3 -3
  68. package/runtime/python/okstra_ctl/agent/invocation.py +107 -5
  69. package/runtime/python/okstra_ctl/agent/prompt_cli/cli.py +16 -0
  70. package/runtime/python/okstra_ctl/agent/prompt_cli/dynamic_verifier.py +3 -2
  71. package/runtime/python/okstra_ctl/agent/prompt_cli/jobs.py +87 -0
  72. package/runtime/python/okstra_ctl/agent/prompt_cli/materialize.py +72 -3
  73. package/runtime/python/okstra_ctl/analysis_packet.py +47 -6
  74. package/runtime/python/okstra_ctl/cmux.py +34 -13
  75. package/runtime/python/okstra_ctl/consumers.py +30 -7
  76. package/runtime/python/okstra_ctl/convergence.py +110 -21
  77. package/runtime/python/okstra_ctl/convergence_provenance.py +83 -0
  78. package/runtime/python/okstra_ctl/dispatch_core.py +127 -5
  79. package/runtime/python/okstra_ctl/dispatch_state.py +17 -9
  80. package/runtime/python/okstra_ctl/domain/host.py +5 -0
  81. package/runtime/python/okstra_ctl/domain/wizard/interaction.py +1 -0
  82. package/runtime/python/okstra_ctl/error_log_write.py +44 -4
  83. package/runtime/python/okstra_ctl/execution_mutation_audit.py +84 -7
  84. package/runtime/python/okstra_ctl/fixed_text.py +25 -7
  85. package/runtime/python/okstra_ctl/group_context.py +475 -10
  86. package/runtime/python/okstra_ctl/handoff.py +109 -32
  87. package/runtime/python/okstra_ctl/handoff_verification.py +80 -0
  88. package/runtime/python/okstra_ctl/initial_prompt_materialization.py +52 -10
  89. package/runtime/python/okstra_ctl/lead_progress.py +291 -0
  90. package/runtime/python/okstra_ctl/model_io/renderers.py +60 -1
  91. package/runtime/python/okstra_ctl/model_io_cli.py +6 -1
  92. package/runtime/python/okstra_ctl/ports/worker_dispatch.py +4 -0
  93. package/runtime/python/okstra_ctl/recap.py +179 -17
  94. package/runtime/python/okstra_ctl/reconcile.py +55 -4
  95. package/runtime/python/okstra_ctl/render.py +34 -8
  96. package/runtime/python/okstra_ctl/report_assembly.py +17 -10
  97. package/runtime/python/okstra_ctl/report_finalize.py +204 -11
  98. package/runtime/python/okstra_ctl/report_html/common.py +241 -113
  99. package/runtime/python/okstra_ctl/report_html/context_links.py +121 -0
  100. package/runtime/python/okstra_ctl/report_html/models.py +11 -5
  101. package/runtime/python/okstra_ctl/report_html/render.py +69 -17
  102. package/runtime/python/okstra_ctl/report_html/view_models/change_impact_analysis.py +8 -1
  103. package/runtime/python/okstra_ctl/report_html/view_models/error_analysis.py +8 -1
  104. package/runtime/python/okstra_ctl/report_html/view_models/feature_analysis.py +11 -1
  105. package/runtime/python/okstra_ctl/report_html/view_models/final_verification.py +13 -1
  106. package/runtime/python/okstra_ctl/report_html/view_models/implementation.py +9 -1
  107. package/runtime/python/okstra_ctl/report_html/view_models/implementation_option_selection.py +29 -2
  108. package/runtime/python/okstra_ctl/report_html/view_models/implementation_planning.py +14 -9
  109. package/runtime/python/okstra_ctl/report_html/view_models/improvement_discovery.py +8 -1
  110. package/runtime/python/okstra_ctl/report_html/view_models/project_analysis.py +15 -1
  111. package/runtime/python/okstra_ctl/report_html/view_models/release_handoff.py +7 -1
  112. package/runtime/python/okstra_ctl/report_html/view_models/requirements_discovery.py +9 -1
  113. package/runtime/python/okstra_ctl/report_translation.py +58 -1
  114. package/runtime/python/okstra_ctl/run.py +54 -14
  115. package/runtime/python/okstra_ctl/stage_targets.py +66 -0
  116. package/runtime/python/okstra_ctl/verdict_blocks.py +39 -12
  117. package/runtime/python/okstra_ctl/wizard/__init__.py +148 -0
  118. package/runtime/python/okstra_ctl/wizard/__main__.py +13 -0
  119. package/runtime/python/okstra_ctl/wizard/cli.py +176 -0
  120. package/runtime/python/okstra_ctl/wizard/confirmation.py +331 -0
  121. package/runtime/python/okstra_ctl/wizard/engine.py +363 -0
  122. package/runtime/python/okstra_ctl/wizard/ids.py +411 -0
  123. package/runtime/python/okstra_ctl/wizard/prompts.py +202 -0
  124. package/runtime/python/okstra_ctl/wizard/registry.py +836 -0
  125. package/runtime/python/okstra_ctl/wizard/render.py +189 -0
  126. package/runtime/python/okstra_ctl/wizard/roles.py +737 -0
  127. package/runtime/python/okstra_ctl/wizard/sources.py +703 -0
  128. package/runtime/python/okstra_ctl/wizard/state.py +689 -0
  129. package/runtime/python/okstra_ctl/wizard/statefile.py +145 -0
  130. package/runtime/python/okstra_ctl/wizard/steps_analysis.py +558 -0
  131. package/runtime/python/okstra_ctl/wizard/steps_identity.py +828 -0
  132. package/runtime/python/okstra_ctl/wizard/steps_options.py +340 -0
  133. package/runtime/python/okstra_ctl/wizard/steps_plan.py +959 -0
  134. package/runtime/python/okstra_ctl/wizard/steps_roles.py +672 -0
  135. package/runtime/python/okstra_ctl/worker_prompt_contract.py +43 -3
  136. package/runtime/python/okstra_ctl/worker_prompt_headers.py +14 -0
  137. package/runtime/python/okstra_ctl/workflow.py +2 -2
  138. package/runtime/python/okstra_ctl/worktree/__init__.py +2 -0
  139. package/runtime/python/okstra_ctl/worktree/cleanliness.py +7 -4
  140. package/runtime/python/okstra_ctl/worktree/git_ops.py +7 -0
  141. package/runtime/python/okstra_ctl/worktree/naming.py +15 -6
  142. package/runtime/python/okstra_ctl/worktree/provision.py +2 -1
  143. package/runtime/python/okstra_ctl/worktree_registry.py +27 -0
  144. package/runtime/python/okstra_ctl/wrapper_status.py +4 -0
  145. package/runtime/schemas/final-report-v2.0.schema.json +4 -0
  146. package/runtime/schemas/final-report-v3.0.schema.json +4 -0
  147. package/runtime/skills/okstra-brief-gen/SKILL.md +22 -3
  148. package/runtime/skills/okstra-chat/SKILL.md +8 -6
  149. package/runtime/skills/okstra-inspect/SKILL.md +2 -2
  150. package/runtime/skills/okstra-inspect/facets/recap.md +52 -4
  151. package/runtime/skills/okstra-rollup/SKILL.md +1 -1
  152. package/runtime/skills/okstra-run/SKILL.md +17 -7
  153. package/runtime/skills/okstra-schedule-gen/SKILL.md +2 -0
  154. package/runtime/skills/okstra-user-response/SKILL.md +1 -1
  155. package/runtime/templates/reports/brief.template.md +15 -7
  156. package/runtime/templates/reports/final-verification-input.template.md +2 -0
  157. package/runtime/templates/reports/group-context.template.md +7 -0
  158. package/runtime/templates/reports/html/base.template.html +13 -3
  159. package/runtime/templates/reports/html/i18n/en.json +43 -5
  160. package/runtime/templates/reports/html/i18n/ko.json +43 -5
  161. package/runtime/templates/reports/html/macros/forms.html +4 -4
  162. package/runtime/templates/reports/html/tasks/final-verification.template.html +11 -1
  163. package/runtime/templates/reports/html/tasks/implementation-option-selection.template.html +16 -15
  164. package/runtime/templates/reports/html/tasks/implementation-planning.template.html +5 -5
  165. package/runtime/templates/reports/html/tasks/release-handoff.template.html +2 -2
  166. package/runtime/templates/reports/html/tasks/requirements-discovery.template.html +1 -1
  167. package/runtime/templates/reports/implementation-planning-input.template.md +3 -0
  168. package/runtime/templates/reports/improvement-discovery-input.template.md +3 -0
  169. package/runtime/templates/reports/release-handoff-input.template.md +5 -3
  170. package/runtime/templates/reports/schedule.template.md +13 -4
  171. package/runtime/templates/reports/task-brief.template.md +1 -1
  172. package/runtime/templates/reverify-output-contract.md +5 -0
  173. package/runtime/templates/worker-error-contract.md +2 -0
  174. package/runtime/templates/worker-prompt-preamble.md +1 -1
  175. package/runtime/validators/validate-report-views.py +30 -1
  176. package/runtime/validators/validate-run.py +194 -25
  177. package/runtime/validators/validate_session_conformance.py +102 -2
  178. package/runtime/python/okstra_ctl/wizard.py +0 -7168
@@ -25,10 +25,10 @@ okstra chat ack --room <name> --as <display> --through <id>
25
25
 
26
26
  Display names are typed. The CLI does not generate them.
27
27
 
28
- Unread is the inbox after the read cursor minus messages whose `from` equals `--as`. It does not move the cursor. `inbox` and `log` keep those messages. Rows are `id @from YYYY-MM-DD HH:MM body`. A reply inserts `↑parentId` after the time. Recipient is not on the line.
28
+ Unread is the inbox after the read cursor minus messages whose `from` equals `--as`. It does not move the cursor. `inbox` and `log` keep those messages. Rows are `id @from YYYY-MM-DD HH:MM body`. A reply inserts `↑parentId` after the time. Recipient is not on the line. A body with several lines continues on rows indented by two spaces; those rows carry no id.
29
29
 
30
- `send --to` may equal `--as`. `--to` and `--reply-to` are exactly one. `--body` and `--body-file` are exactly one. A reply inherits `to` from the parent. `members` is the full roster.
30
+ `send --to` may equal `--as`. `--to` and `--reply-to` are exactly one. `--body` and `--body-file` are exactly one; either may hold several lines, and only an all-blank body is rejected. A reply inherits `to` from the parent. `members` is the full roster. `ack --through` rejects an id behind the current cursor. `.` and `..` are reserved names. A stale `.lock` (dead owner pid, or older than 5 s) is reclaimed by the next writer.
31
31
 
32
- The skill picker is `all` plus `members` minus the current display name. Skill send and reply use `--body`, not `--body-file`. After showing unread rows, the skill runs `ack --through` with the last unread id unless the output is `no unread`. The Step 3 menu is send, unread, inbox, log, reply, done. Reply takes a free-input id and body; there is no recipient picker and no `okstra chat reply` subcommand.
32
+ The skill picker is `all` plus `members` minus the current display name. Skill send and reply use `--body`, not `--body-file`. Before joining an existing room the skill runs `members`; if the typed display name is already listed, it asks whether this session is already in the room under that name (a re-entry after context loss) and, if so, continues with `--as` without joining. After showing unread rows, the skill runs `ack --through` with the id of the last row that starts with an id, unless the output is `no unread`. The Step 3 menu is send, unread, inbox, log, reply, done. Reply takes a free-input id and body; there is no recipient picker and no `okstra chat reply` subcommand.
33
33
 
34
34
  Read the fixed text rows. Do not parse JSON.
@@ -33,7 +33,7 @@ No sub-command writes outside this machine.
33
33
  | `errors` | aggregate task error logs into a timestamped markdown report | generates report |
34
34
  | `error-zip` | build an anonymized zip of cross-project error logs | generates zip |
35
35
  | `run-audit` | check every run's artifacts against progress invariants — catches a run that ended wrong without ever logging a failure | read |
36
- | `recap` | summarize a task's before/after runs and record Q&A | appends `recap-log.jsonl` |
36
+ | `recap` | summarize a task's before/after runs, or a task-group's per-brief status and latest conclusions, and record Q&A | appends `recap-log.jsonl` (task `recap/`, group `.recap/`) |
37
37
 
38
38
  ## Preflight
39
39
 
@@ -225,12 +225,22 @@ okstra model-io recap-input --project-root <projectRoot> --task-ref <task-key>
225
225
 
226
226
  Use the emitted `Run count` and repeated `Transition` fields in order. Do not parse recap JSON or open recap state files directly.
227
227
 
228
+ Group scope — when the user names a task-group, or the bare token resolves only via `taskGroup`:
229
+
230
+ ```bash
231
+ okstra model-io recap-input --project-root <projectRoot> --task-group <task-group>
232
+ ```
233
+
234
+ The projection joins the group's briefs (start order, `waits for` edges), the catalog / task-manifests (real status, progress, run count, next phase, report), and the group document's Task Memory (headline, decisions, watch-outs, follow-ups). Read `Brief count` / `Task count` / `Next in group`, then the repeated `Queue entry` and `Task` blocks. Run-count / time / error totals belong to `okstra-rollup`.
235
+
228
236
  record:
229
237
 
230
238
  ```bash
231
239
  okstra recap record <task-key> --project-root <projectRoot> --kind <summary|qa> --mode <artifact|code> --question "<question>" --answer "<summary>" --citation "<path:line>"
232
240
  ```
233
241
 
242
+ In group scope, `--task-group <task-group>` replaces `<task-key>` and the line lands at `.okstra/tasks/<task-group>/.recap/recap-log.jsonl`. `recap note` has no group form.
243
+
234
244
  Enter code mode only when the user explicitly requests it, such as "including the diff" or "the code changes too". Entering recap alone does not read the code diff.
235
245
 
236
246
  ## Output rules
@@ -28,6 +28,7 @@ Use it when:
28
28
  Do not use it when:
29
29
 
30
30
  - A single task's report/time/errors/recap → `okstra-inspect` (report / time / errors / recap facet).
31
+ - "Where does the group stand" — which briefs are done / in progress / not started, what is next, each task's latest conclusion → `okstra-inspect` recap facet with `--task-group`. rollup keeps the numbers (runs, time, errors) and the cross-task digest.
31
32
  - A forward-looking work plan (a client-facing schedule of non-done tasks) → `okstra-schedule-gen`. rollup is **retrospective**, collecting past run results; schedule is **forward-looking**, planning future work.
32
33
  - Actual phase execution → `okstra-run`.
33
34
 
@@ -4,7 +4,7 @@
4
4
 
5
5
  - Skill source: [`skills/okstra-run/SKILL.md`](../../../skills/okstra-run/SKILL.md)
6
6
  - wizard CLI wrapper: [`src/commands/execute/wizard.mjs`](../../../src/commands/execute/wizard.mjs)
7
- - wizard state machine: [`scripts/okstra_ctl/wizard.py`](../../../scripts/okstra_ctl/wizard.py)
7
+ - wizard state machine: [`scripts/okstra_ctl/wizard/`](../../../scripts/okstra_ctl/wizard/)
8
8
  - render-bundle CLI: [`src/commands/execute/render-bundle.mjs`](../../../src/commands/execute/render-bundle.mjs)
9
9
  - prepare entrypoint: [`scripts/okstra_ctl/run.py`](../../../scripts/okstra_ctl/run.py)
10
10
 
@@ -14,7 +14,7 @@
14
14
 
15
15
  Single authority:
16
16
 
17
- - Question order, branching, validation: `scripts/okstra_ctl/wizard.py`
17
+ - Question order: `scripts/okstra_ctl/wizard/registry.py` (`STEPS`); branching: `engine.py`; per-step validation: `steps_*.py`
18
18
  - task bundle materialization: `prepare_task_bundle()`
19
19
  - Skill document: thin prompt-relay loop
20
20
 
@@ -109,12 +109,13 @@ Important: never trim, hide, or restructure the wizard-provided options into a "
109
109
 
110
110
  ## brief candidate ordering
111
111
 
112
- The brief selection for entry phases (`requirements-discovery`, `error-analysis`, `improvement-discovery`) is handled by the wizard.
112
+ The brief selection is handled by the wizard. A new task is asked for its brief right after task-group and **before** the task-type; an existing task is asked only on an entry phase (`requirements-discovery`, `error-analysis`, `improvement-discovery`, `project-analysis`, `feature-analysis`, `change-impact-analysis`).
113
113
 
114
114
  - task-group candidates are shown newest-first by combining recent task-catalog use with the recent brief creation/modification times under `.okstra/briefs/<group>/`.
115
115
  - brief file candidates are chosen from within the selected group's `.okstra/briefs/<task-group>/**/*.md`.
116
116
  - The brief-file sort key is `max(file created/modified time, task-catalog updatedAt of the task that used this brief)`.
117
117
  - direct input is always last.
118
+ - for a new task the following task-type pick offers entry phases only, and its recommended slot is the selected brief's `Recommended next phase:` line (fallback `requirements-discovery`).
118
119
 
119
120
  ## confirm step
120
121
 
@@ -124,7 +125,7 @@ When `next.step == "confirm"`, first fetch the confirmation summary.
124
125
  okstra wizard confirmation --state-file /tmp/okstra-wizard/state.json
125
126
  ```
126
127
 
127
- Show `text` to the user, then render the Proceed/Edit/Abort picker. `Edit` rewinds the wizard to an earlier step.
128
+ Show `text` to the user, then render the Proceed/Edit/Abort picker as the final output of that turn — the rendered question is the last thing you emit in that turn, and text emitted after the call renders below the picker. `Edit` rewinds the wizard to an earlier step.
128
129
 
129
130
  ## outcome and render-bundle
130
131
 
@@ -26,7 +26,7 @@ The legacy `list` and `show` JSON commands remain for automation compatibility.
26
26
  ## Flow
27
27
 
28
28
  1. Run `okstra preflight --runtime <host-runtime>` for the current harness. On `Okstra preflight: failed`, show `Reason` and `Recovery`, then stop. On `Okstra preflight: ready`, carry `Project root`, `Project ID`, `Runtime`, and `Relay contract`, then run `okstra paths --field home`.
29
- 2. Read the relay `Wizard interaction relay` JSON. When `native-single` is available and the option count fits `nativeLimits`, call `interactions.native-single.function` (`AskUserQuestion` / `ask_user_question` / `request_user_input` from that field). Do not print a numbered list in chat while the native tool is available. Otherwise render a numbered Markdown list. Do not substitute one host function name for another. Copy the view's `Picker:` `- Label:` / `Description:` pairs into that function in that order. Do not rebuild labels from the `Options:` dump. `--option-number` is the 1-based `Option N:` index, which is the same order as `Picker:`. The HTML report's `<select>` uses the same `option.answer` values. Pass only the `list-view` `Picker:` rows, the report `Picker:` rows, or the two confirmation labels. Do not append `Enter directly`. Claude Other, Grok `z`, and Codex's free-form row are `Enters an answer`; on a numbered list, so is a next message that is not a listed label or its 1-based number. Do not ask a second question for the custom value.
29
+ 2. Read the relay `Wizard interaction relay` JSON. When `native-single` is available and the option count fits `nativeLimits`, call `interactions.native-single.function` (`AskUserQuestion` / `ask_user_question` / `request_user_input` from that field). Do not print a numbered list in chat while the native tool is available. Emit the question as the last thing in that turn; text emitted after the call renders below the question. Otherwise render a numbered Markdown list. Do not substitute one host function name for another. Copy the view's `Picker:` `- Label:` / `Description:` pairs into that function in that order. Do not rebuild labels from the `Options:` dump. `--option-number` is the 1-based `Option N:` index, which is the same order as `Picker:`. The HTML report's `<select>` uses the same `option.answer` values. Pass only the `list-view` `Picker:` rows, the report `Picker:` rows, or the two confirmation labels. Do not append `Enter directly`. Claude Other, Grok `z`, and Codex's free-form row are `Enters an answer`; on a numbered list, so is a next message that is not a listed label or its 1-based number. Do not ask a second question for the custom value.
30
30
  3. Select a task from `list-view` through that host picker. A host free-text row or unmatched next message is the report path or task key.
31
31
  4. Read only `show-view --report <reportPath> --project-root <projectRoot>` for report facts. The view also prints `Why asked`, `Linked plan items`, and `Cited artifacts`.
32
32
  5. Read every cited `path:line` under the project root and every linked plan-item definition before asking. Do not search beyond that list. Investigation explains; it never changes `options[]`.
@@ -202,7 +202,7 @@ The Module column below is where the command's behaviour lives — a `src/` modu
202
202
  | `spawn-followups`, `error-log` | `scripts/okstra-spawn-followups.py`, `scripts/okstra-error-log.py` | Follow-up task bundle creation and run error-log append helpers |
203
203
  | `memory` | `src/commands/memory/memory.mts` | Store/find global conversation memory under `~/.okstra/memory-book` |
204
204
  | `pr` | `src/commands/pr/pr.mts` | `okstra pr <template\|branches\|gen>` — PR body template store under `~/.okstra/template/pr/` (bundled fallback `src/commands/pr/default.md`), base-branch recommendation, and a fixed-text generation bundle for the okstra-pr-gen skill. `--json` preserves the template + `<base>..HEAD` commits + `<base>...HEAD` diffstat machine contract. Git-only; no project registration required |
205
- | `recap` | `scripts/okstra_ctl/recap.py` | `okstra recap <assemble\|record\|note>` Node wrapper backing the okstra-inspect `recap` facet — `assemble` is a read-only phase-transition summary, `record` appends one line to `recap/recap-log.jsonl`, and `note` writes an agent-authored note under `notes/` and prints the `--clarification-response` argument for a follow-up run |
205
+ | `recap` | `scripts/okstra_ctl/recap.py` | `okstra recap <assemble\|record\|note>` Node wrapper backing the okstra-inspect `recap` facet — `assemble` is a read-only phase-transition summary for a task or, with `--task-group`, the group's start order plus each task's latest conclusion; `record` appends one line to `recap/recap-log.jsonl` (task) or `.okstra/tasks/<group>/.recap/recap-log.jsonl` (`--task-group`); `note` writes an agent-authored note under `notes/` and prints the `--clarification-response` argument for a follow-up run |
206
206
  | `stage-map` | `scripts/okstra_ctl/stage_map_cli.py` | `okstra stage-map <task-key>` — exposes a task's implementation-planning Stage Map as JSON (`stages[].{stage_number,title,depends_on,step_count}` + consumer-state-based `doneStages[]`). If there is no Stage Map, `stages: []`. The read-side basis from which `okstra-schedule-gen` derives stage units and dependency closure |
207
207
  | `design-prep` | `scripts/okstra_ctl/design_prep.py` | `okstra design-prep <list\|show\|write>` thin shim into `scripts/okstra_ctl/design_prep.py` — queries (`list`/`show`) the design items that implementation-planning pre-authored with AI, and records the user-confirmed responses as an append-only sidecar under `design-prep-inputs/` (`write`, `--confirmed` required). It never modifies the report snapshot |
208
208
  | `rollup` | `scripts/okstra_ctl/rollup.py` | Read-only roll-up; `--text` is the fixed model projection and machine mode remains JSON |
@@ -262,7 +262,7 @@ Important modules:
262
262
  | `consumers.py` | Append-only `consumers.jsonl` writer + reader — records which `implementation` runs consumed which `implementation-planning` stage |
263
263
  | `implementation_outcome.py` | Artifact-derived reconstruction of the implementation phase outcome — reads `runs/implementation/carry/stage-<N>.json` + `consumers.jsonl` + the approved Stage Map to derive `phaseOutcome.implementation`, and when every stage has pass-grade carry evidence it raises `workflow.nextRecommendedPhase.status` to `ready` (keeping the `contract-violated` audit information). It never picks the phase — `phase` is left as the last stage's report routing settled it, and the status is raised only while `phase` is non-empty |
264
264
  | `paths.py` | Path/sequence computation for task/run artifacts (including recap directory/log paths) |
265
- | `recap.py` | deterministic backend for the okstra-inspect `recap` facet — `assemble` builds the cross-run phase transitions from the timeline overlaid with each run-manifest's current facts (`timeline_runs.py`), `record` append-only writes a summary/Q&A to `<task-root>/recap/recap-log.jsonl` (other task artifacts unchanged) |
265
+ | `recap.py` | deterministic backend for the okstra-inspect `recap` facet — `assemble` builds the cross-run phase transitions from the timeline overlaid with each run-manifest's current facts (`timeline_runs.py`); `assemble_group_recap` joins a task-group's briefs (start order, `group_context.group_queue`), catalog task-manifests (status, run count, next phase, report), and the group document's Task Memory (each task's conclusion); `record` append-only writes a summary/Q&A to `<task-root>/recap/recap-log.jsonl` or `.okstra/tasks/<group>/.recap/recap-log.jsonl` (other artifacts unchanged) |
266
266
  | `timeline_runs.py` | read-side overlay of a `history/timeline.json` entry with its run-manifest's current facts (`current_run_facts`) — the entry is a prepare-time snapshot (`status`, `workflowSnapshot`, reserved `reportRecordPath`) and `validate-run` writes the end state to the run-manifest only; a run whose `validation.status` is `not-run` projects no report path. Shared by `recap.py` and the `history-input` / overview projections in `model_io/renderers.py` |
267
267
  | `render.py` | task manifest, run manifest, timeline, task index, discovery, team-state, prompt/template render |
268
268
  | `group_context.py` | task-group context document (`.okstra/briefs/<task-group>/group-context.md`): the skeleton writer behind `okstra group-context init` (template `templates/reports/group-context.template.md`), `validate_group_context` (four required sections, no template placeholder left, directory slug matches the frontmatter `task-group`) that `validators/validate-brief.py` dispatches to on frontmatter `type: group-context`, and the path helpers `run.py` uses to validate the file at preflight and copy it to `instruction-set/task-group-context.md` for the analysis packet's `## Task-Group Context` section |
@@ -287,7 +287,19 @@ Important modules:
287
287
  | `design_snapshot.py` | Builds the design-surface-detector-owned snapshot from the report narrative — reproducible design surfaces plus conservative `PREP-NNN` preparation items (delegates surface detection to `design_surfaces.py`) |
288
288
  | `report_markdown.py` | Schema-ordered Markdown serialisation of a data.json subtree for the full reading copy — headings, tables for uniform row sets, prose for narrative fields; field order read from the schema, not from the mapping |
289
289
  | `final_report_paths.py`, `report_view_artifacts.py` | Path-helper SSOT for the final-report markdown/data.json pair and the generated view artifacts (HTML view, user-responses directory) |
290
- | `wizard.py` | `okstra-run` prompt state machine; user-facing Korean strings live in `prompts/wizard/prompts.ko.json` |
290
+ | `wizard/` | `okstra-run` prompt state machine as a package; user-facing Korean strings live in `prompts/wizard/prompts.ko.json`. Modules import only the modules listed before them (`tests/contract/test_no_import_cycles.py`): |
291
+ | `wizard/ids.py` | constants, `S_*` step ids, pick tokens, multi-tab prompt groups |
292
+ | `wizard/state.py` | `WizardState` / `Prompt` / `Option` / `Step` dataclasses, v1 provider-selection → v2 conversion, state predicates |
293
+ | `wizard/prompts.py` | `prompts.ko.json` loader and placeholder interpolation (`_p`, `_msg`, `_static_options`) |
294
+ | `wizard/sources.py` | helpers that read `.okstra` history, reports, profiles and git worktrees to suggest values |
295
+ | `wizard/roles.py` | role-instance selection loop (`next_role_prompt`) and its validation / rewind |
296
+ | `wizard/statefile.py` | `load_state_file` / `save_state_file` and the v2 companion-file lookup |
297
+ | `wizard/steps_identity.py`, `steps_analysis.py`, `steps_plan.py`, `steps_options.py`, `steps_roles.py` | build/submit pairs per step cluster: task identity + brief + base ref; analysis inputs + design prep; approved plan + stage + handoff + reverify scope; directive / related tasks / clarification / pr template ("optional cached pick" seam); executor / critic / workers / per-role model picks |
298
+ | `wizard/confirmation.py` | `confirmation_block` and the confirm step |
299
+ | `wizard/registry.py` | the ordered `STEPS` literal (order is question order), `STEP_BY_ID`, `_reset_from`, and the steps that rewind the registry (edit target, brief carry) |
300
+ | `wizard/engine.py` | public API — `init_state`, `next_prompt`, `submit`, progress / simulation, host interaction payloads |
301
+ | `wizard/render.py` | `render_args`, `render_role_args`, `wizard_outcome` |
302
+ | `wizard/cli.py`, `wizard/__main__.py` | `okstra wizard` argparse entrypoint (`main`); `python3 -m okstra_ctl.wizard` |
291
303
  | `wizard_stage_intent.py` | stage-related intent projection of the `okstra-run` wizard output — normalizes whole-task (`__whole_task__`) vs single/multi stage selection into render-args (`resolve_wizard_stage_intent`) |
292
304
  | `index.py`, `jsonl.py`, `reconcile.py`, `listing.py`, `backfill.py` | `~/.okstra` run index and history operations — `record_start` (index.py) writes a run's start; the end is closed either by `settle_run_row` (reconcile.py, records a verdict the caller already knows — used by `validate-run.py`) or by `reconcile_home` (infers one from disk — used by `run._reconcile_prior_runs` as the backstop for runs that died before validation) |
293
305
  | `run_index_row.py` | single reference point for creating / slimming / hydrating a `~/.okstra` run-index row — runId SSOT, preserves projectId raw |
@@ -346,7 +358,7 @@ Important modules:
346
358
  | `plan_derivations.py` | the supersession sweep `_common-contract.md` requires an author to do by hand — extracts the symbols, paths, and ids an answered clarification names and reports every plan string that mentions one. Advisory: it locates candidates and never judges which are now false |
347
359
  | `scope_provenance.py` | single source of truth for the scope-provenance grammar every phase-emitted requirement must declare, shared by `validators/validate-run.py` and `validators/validate_fanout.py` so the planning report and fan-out packets cannot drift |
348
360
  | `worker_artifact_paths.py` | canonical worker artifact path derivation (e.g. `audit_sidecar_rel` inserts `-audit-` after the first `-worker-` token), so dispatch and validation agree on non-canonical-path rejection |
349
- | `report_finalize.py` | Phase 7 post-report sequence **SSOT** — runs `check-source` → `token-usage` → `render-views` → `spawn-followups` → `validate-run` in that load-bearing order. A non-zero exit still runs every later check through `validate-run` and names the earliest failure; `teardown-stages` is skipped when any earlier step failed. Both lead paths converge here: the Codex adapter calls it in-process (`codex_dispatch`), a Claude-led run reaches it through `okstra report-finalize`. Neither reimplements the sequence |
361
+ | `report_finalize.py` | Phase 7 post-report sequence **SSOT** — runs `check-source` → `token-usage` → `render-views` → `spawn-followups` → `validate-run` → `record-group-memory` → `teardown-stages` in that load-bearing order. A non-zero exit still runs every later check through `validate-run` and names the earliest failure; `record-group-memory` (this run's conclusion into the task-group's `group-context.md`, plus `nextInGroup` for the closeout) and `teardown-stages` are skipped when any earlier step failed. Both lead paths converge here: the Codex adapter calls it in-process (`codex_dispatch`), a Claude-led run reaches it through `okstra report-finalize`. Neither reimplements the sequence |
350
362
  | `wrapper_status.py` | worker wrapper status sidecar reader — the host-side reader of the sidecar `worker_runner.py` writes. `is_terminal` is the one question it answers for the dispatch record and the pane reclaim: does `stage` read `exited` |
351
363
  | `worker_runner.py` | runs one worker CLI and records what happened — shared by every provider entrypoint. Owns the `selectors` pump over the child's streams, the stream-arrival idle watchdog (`killpg` on breach), the run-wide progress cap on the log copy, and the status sidecar's whole life. A run that dies after launch still closes its sidecar, so `worker_liveness` never reads a dead worker as running |
352
364
  | `session_transcript.py` | worker session transcript — one line per event (time, speaker, body) with a run-wide progress-line cap (`LOG_LINE_CAP`, elision notice) so a single-file dispatch's tool echo cannot dominate the project's `.okstra/` bytes; the fixed shape lets a later lead write share the same file |
@@ -358,7 +370,7 @@ Important modules:
358
370
  | `task_target.py` | shared helper resolving `task-key → (task_root, project_root)` (`resolve_task_root`) |
359
371
  | `contract_graph.py`, `contract_graph_cli.py` | runtime-contract graph loader + cross-reference/dependency-closure validator and its `okstra contract-check --root <dir> (--profile\|--operation)` CLI boundary. Loads the agent contract schemas (`common`/`role`/`duty`/`profile`/`operation`), validates known role capabilities, and reports the dependency closure with per-file `path`/`schemaVersion`/`sha256`; an invalid contract raises `ContractGraphError` |
360
372
  | `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 |
361
- | `fixed_text.py` | shared scalar-line format for the model-facing fixed-text projections — `scalar` neutralises complex values and control characters, `line` renders one static-labelled Markdown list row, and `value_lines` losslessly flattens a JSON-shaped value into fixed name/order/value rows |
373
+ | `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 |
362
374
  | `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 |
363
375
 
364
376
  > `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.
@@ -53,7 +53,7 @@ Launch selection is role slots and model refs, not a provider roster. The wizard
53
53
  | Concern | Source of truth |
54
54
  |---|---|
55
55
  | okstra-run skill procedure | [`skills/okstra-run/SKILL.md`](../../skills/okstra-run/SKILL.md) |
56
- | wizard state machine | [`scripts/okstra_ctl/wizard.py`](../../scripts/okstra_ctl/wizard.py) |
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
58
  | render-bundle Node shim | [`src/commands/execute/render-bundle.mjs`](../../src/commands/execute/render-bundle.mjs) |
59
59
  | single entrypoint for bundle creation | [`scripts/okstra_ctl/run.py`](../../scripts/okstra_ctl/run.py) |
@@ -37,7 +37,7 @@ Launch selection uses role slots and model refs only: current-session lead is th
37
37
  ```mermaid
38
38
  sequenceDiagram
39
39
  participant Skill as okstra-run
40
- participant Wizard as wizard.py
40
+ participant Wizard as okstra_ctl.wizard
41
41
  participant Run as prepare_task_bundle
42
42
  participant WT as worktree/provision.py
43
43
  participant Art as artifacts
@@ -99,5 +99,5 @@ What is prohibited is source edit, refactor, fix attempt, implementation design
99
99
  - [`prompts/profiles/error-analysis.md`](../../prompts/profiles/error-analysis.md)
100
100
  - [`templates/reports/error-analysis-input.template.md`](../../templates/reports/error-analysis-input.template.md)
101
101
  - [`scripts/okstra_ctl/workflow.py`](../../scripts/okstra_ctl/workflow.py)
102
- - [`scripts/okstra_ctl/wizard.py`](../../scripts/okstra_ctl/wizard.py)
102
+ - [`scripts/okstra_ctl/wizard/`](../../scripts/okstra_ctl/wizard/)
103
103
  - [`prompts/lead/okstra-lead-contract.md`](../../prompts/lead/okstra-lead-contract.md)
@@ -172,7 +172,7 @@ The stage merge of whole-task mode is a runtime-owned integration step that prep
172
172
 
173
173
  - [`prompts/profiles/final-verification.md`](../../prompts/profiles/final-verification.md)
174
174
  - [`templates/reports/final-verification-input.template.md`](../../templates/reports/final-verification-input.template.md)
175
- - [`scripts/okstra_ctl/wizard.py`](../../scripts/okstra_ctl/wizard.py)
175
+ - [`scripts/okstra_ctl/wizard/`](../../scripts/okstra_ctl/wizard/)
176
176
  - [`scripts/okstra_ctl/run.py`](../../scripts/okstra_ctl/run.py)
177
177
  - [`scripts/okstra_ctl/workflow.py`](../../scripts/okstra_ctl/workflow.py)
178
178
  - [`scripts/okstra_ctl/render.py`](../../scripts/okstra_ctl/render.py)
@@ -220,7 +220,7 @@ This phase does not declare final acceptance. It says only ready for final-verif
220
220
  - [`prompts/profiles/implementation.md`](../../prompts/profiles/implementation.md)
221
221
  - [`templates/reports/implementation-input.template.md`](../../templates/reports/implementation-input.template.md)
222
222
  - [`scripts/okstra_ctl/run.py`](../../scripts/okstra_ctl/run.py)
223
- - [`scripts/okstra_ctl/wizard.py`](../../scripts/okstra_ctl/wizard.py)
223
+ - [`scripts/okstra_ctl/wizard/`](../../scripts/okstra_ctl/wizard/)
224
224
  - [`validators/validate-implementation-plan-stages.py`](../../validators/validate-implementation-plan-stages.py)
225
225
  - [`scripts/okstra_ctl/qa_commands.py`](../../scripts/okstra_ctl/qa_commands.py)
226
226
  - [`prompts/lead/okstra-lead-contract.md`](../../prompts/lead/okstra-lead-contract.md)
@@ -14,7 +14,7 @@
14
14
 
15
15
  ## 1. Purpose
16
16
 
17
- `release-handoff` is the terminal phase that pushes an already-committed implementation result with an `accepted` 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 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`.
18
18
 
19
19
  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
20
 
@@ -89,13 +89,15 @@ flowchart TD
89
89
  Before asking the user whether to push/PR, the lead confirms the following.
90
90
 
91
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 cited report must be `verificationScope=whole-task` and `Verdict Token = accepted`.
93
- - In stage-group mode, each cited single-stage report must be `Verdict Token = accepted`, and prepare / `okstra handoff assemble` re-enforce the Stage Lifecycle Snapshot-based eligibility and dependency closure.
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.
94
94
  - The working tree is clean.
95
95
  - The current branch is not a base branch such as `main`, `master`, `prod`, `preprod`, `staging`, or `dev`.
96
96
  - The `<base>..HEAD` commit range is non-empty.
97
97
 
98
- `conditional-accept`, `blocked`, and vague-sentence verdicts are all immediate-termination targets.
98
+ `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
+
100
+ Verification targets are preserved per execution under the run's state directory. Old records without provable task/stage/commit evidence require re-verification; they are not rewritten. The checks are enforced by `okstra_ctl.handoff_verification`, `consumers.verified_accepted_stages`, and the handoff regression tests.
99
101
 
100
102
  ## 5. lead-only execution flow
101
103
 
@@ -139,7 +141,7 @@ In stage-group mode, `local checkout` is not offered. After choosing `push + PR`
139
141
  ```mermaid
140
142
  flowchart TD
141
143
  PushPR[push + PR selected] --> Fetch[git fetch origin chosen-base]
142
- Fetch --> MergeTree[git merge-tree --write-tree --merge-base<br/>origin/base HEAD origin/base]
144
+ Fetch --> MergeTree[git merge-tree --write-tree<br/>handoff-branch origin/base]
143
145
  MergeTree --> Conflict{conflict?}
144
146
  Conflict -->|no| Draft[show PR draft]
145
147
  Conflict -->|yes| Ask[ask proceed/change base/cancel]
@@ -214,7 +216,7 @@ A failed `git push` must not be retried with weaker safeguards. When a failure s
214
216
  - [`prompts/profiles/release-handoff.md`](../../prompts/profiles/release-handoff.md)
215
217
  - [`templates/reports/release-handoff-input.template.md`](../../templates/reports/release-handoff-input.template.md)
216
218
  - [`skills/okstra-run/SKILL.md`](../../skills/okstra-run/SKILL.md)
217
- - [`scripts/okstra_ctl/wizard.py`](../../scripts/okstra_ctl/wizard.py)
219
+ - [`scripts/okstra_ctl/wizard/`](../../scripts/okstra_ctl/wizard/)
218
220
  - [`scripts/okstra_ctl/run.py`](../../scripts/okstra_ctl/run.py)
219
221
  - [`scripts/okstra_ctl/pr_template.py`](../../scripts/okstra_ctl/pr_template.py)
220
222
  - [`src/commands/lifecycle/config.mjs`](../../src/commands/lifecycle/config.mjs)
@@ -106,7 +106,7 @@ Non-goals are source edit, plan authoring, build, and deployment.
106
106
  ## 6. Code reviewed
107
107
 
108
108
  - [`skills/okstra-run/SKILL.md`](../../skills/okstra-run/SKILL.md)
109
- - [`scripts/okstra_ctl/wizard.py`](../../scripts/okstra_ctl/wizard.py)
109
+ - [`scripts/okstra_ctl/wizard/`](../../scripts/okstra_ctl/wizard/)
110
110
  - [`scripts/okstra_ctl/run.py`](../../scripts/okstra_ctl/run.py)
111
111
  - [`scripts/okstra_ctl/workflow.py`](../../scripts/okstra_ctl/workflow.py)
112
112
  - [`prompts/profiles/requirements-discovery.md`](../../prompts/profiles/requirements-discovery.md)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "okstra",
3
- "version": "0.189.3",
3
+ "version": "0.190.0",
4
4
  "description": "Host-aware multi-provider cross-verification orchestrator runtime and agent skills.",
5
5
  "license": "MIT",
6
6
  "author": "devonshin",
@@ -1,5 +1,5 @@
1
1
  {
2
- "package": "0.189.3",
3
- "builtAt": "2026-09-05T22:53:00.281Z",
2
+ "package": "0.190.0",
3
+ "builtAt": "2026-09-08T19:21:43.911Z",
4
4
  "repoRoot": "/home/runner/work/okstra/okstra"
5
5
  }
@@ -88,6 +88,8 @@ After your `Write` to the assigned worker-results file (path provided by Lead as
88
88
  3. Do NOT rewrite the worker-results file with `Write` more than once. If a correction is genuinely required, perform a single `Edit` and then return immediately.
89
89
  4. The only exception is recording a `tool-failure` with the typed error-log command when a post-Write failure is itself the failure being reported — return immediately after that command.
90
90
 
91
+ **Enforced:** `validators/validate-run.py` `validate_team_state` fails a run whose worker carries a terminal status with no saved result file at its assigned Result Path (and no saved prompt history at its assigned prompt path).
92
+
91
93
  If you find yourself thinking "let me double-check section 3" or "I should read one more file to be safer" after the Write succeeded — stop. Convergence (Phase 5.5) and the Report writer worker (Phase 6) will reconcile gaps across all three workers; over-investing in single-worker depth at the expense of returning quickly is a net loss for the run.
92
94
 
93
95
  ## Error reporting
@@ -122,3 +124,5 @@ When this run's `task_type` is `implementation` and you are acting as the **Exec
122
124
  Emit this as a fenced ```json``` block in your worker result under the heading `### Stage Carry Evidence`. The host-native Okstra lead is responsible for persisting the block as `runs/<impl-task-key>/carry/stage-<N>.json` — you do not write the file yourself.
123
125
 
124
126
  This applies only when `task_type` is `implementation`. For other task types, skip this block entirely.
127
+
128
+ **Enforced:** `scripts/okstra_ctl/implementation_outcome.py` `_load_carry` / `_carry_passed` read the persisted `carry/stage-<N>.json`; a stage with no carry block never reaches `done`, and `validators/validate_session_conformance.py` `_check_progress_checkpoints` requires the `phase-5-stage-complete` line the lead can only write by parsing this block.
@@ -50,7 +50,7 @@ from okstra_ctl.json_boundary import ( # noqa: E402
50
50
  load_owned_object_snapshot,
51
51
  write_owned_object_atomic,
52
52
  )
53
- from okstra_ctl.fixed_text import line, scalar # noqa: E402
53
+ from okstra_ctl.fixed_text import block, line # noqa: E402
54
54
  from okstra_ctl.convergence import ( # noqa: E402
55
55
  ConvergenceContractError,
56
56
  RunArtifactAuthority,
@@ -189,10 +189,16 @@ def cmd_source(args: argparse.Namespace) -> int:
189
189
  print(line("Source digest", payload["sourceDataSha256"]), end="")
190
190
  print(line("String count", len(strings)), end="")
191
191
  for index, source in enumerate(strings.values(), 1):
192
- print(f"\n## T-{index:03d}\n{scalar(source)}")
192
+ print(f"\n## T-{index:03d}\n{block(source)}")
193
193
  return 0
194
194
 
195
195
 
196
+ def _translation_block(rows: list[str]) -> str:
197
+ # Markdown 의 `\`` 는 백틱 리터럴이고, 이전 `source` 출력이 본문 백틱을 그렇게
198
+ # 내보냈다. 렌더러는 Markdown 이스케이프를 모르므로 여기서 백틱으로 되돌린다.
199
+ return "\n".join(rows).strip().replace("\\`", "`")
200
+
201
+
196
202
  def _translation_blocks(path: Path) -> list[str]:
197
203
  text = path.read_text(encoding="utf-8")
198
204
  blocks: list[str] = []
@@ -200,7 +206,7 @@ def _translation_blocks(path: Path) -> list[str]:
200
206
  for row in text.splitlines():
201
207
  if row.startswith("## T-"):
202
208
  if current is not None:
203
- blocks.append("\n".join(current).strip())
209
+ blocks.append(_translation_block(current))
204
210
  expected = f"## T-{len(blocks) + 1:03d}"
205
211
  if row != expected:
206
212
  raise SystemExit(f"error: expected translation heading {expected}")
@@ -208,7 +214,7 @@ def _translation_blocks(path: Path) -> list[str]:
208
214
  elif current is not None:
209
215
  current.append(row)
210
216
  if current is not None:
211
- blocks.append("\n".join(current).strip())
217
+ blocks.append(_translation_block(current))
212
218
  return blocks
213
219
 
214
220
 
@@ -7,7 +7,7 @@
7
7
 
8
8
  **Enforced:** `validators/validate_session_conformance.py` reads the selected adapter's evidence within the run window and reports a missing checkpoint. Missing lines are advisories, not failures — by the time the validator runs the session that would have emitted the line has ended, so the finding records that the run is hard to follow, not that its work is wrong.
9
9
 
10
- Emit one `PROGRESS: <phase-id> <verb-phrase>` line as plain user-facing text at every checkpoint enumerated in the lifecycle core contract (`{{OKSTRA_LEAD_CONTRACT_PATH}}` "Progress reporting (BLOCKING)") — phase-1-intake start/complete, phase-2-prompts, phase-3-team-create, phase-4-dispatch (per worker), phase-5-collect (per worker), phase-5.5-convergence (per round), phase-6-synthesis, phase-7-persist, and final `complete`. One line per checkpoint, never batched, never replaced with prose. This is the only signal the user has during multi-minute silent windows.
10
+ Emit one `PROGRESS: <phase-id> <verb-phrase>` line as plain user-facing text at every checkpoint enumerated in the lifecycle core contract (`{{OKSTRA_LEAD_CONTRACT_PATH}}` "Progress reporting (BLOCKING)") — phase-1-intake start/complete, phase-2-prompts, phase-3-team-create, phase-4-dispatch (per worker), phase-5-collect (per worker), phase-5.5-convergence (per round), phase-6-synthesis, phase-7-persist, and final `complete`. One line per checkpoint, never batched, never replaced with prose. This is the only signal the user has during multi-minute silent windows. Record each one with `okstra lead-progress append --project-root <dir> --run-manifest <path> --phase <phase-id>` and emit the `progressLine` it prints — that call is what puts the checkpoint where the validator reads it.
11
11
 
12
12
  When the run manifest declares `activityContractVersion: 1`, call `okstra agent-activity append` before each required activity boundary. Only after the structured append succeeds, emit the matching `PROGRESS:` line and the immediately following `ACTIVITY:` projection from the same fields. If the structured append fails, do not mark that boundary completed. Never reconstruct structured activity by parsing `ACTIVITY:` conversation text.
13
13
 
@@ -60,6 +60,10 @@ For every other task type:
60
60
  - Phase 7 `validate-run` failed → one line naming the blocking cause, then `/okstra-run` to re-run this phase. Only a failure matching the blocking allowlist (`okstra_ctl.blocking_checks`) reaches this row; every other finding was demoted to an advisory, printed as `validate-run: advisory — <finding>`, and the run passed. Name those advisories in one line and take the command from the matching pointer row above — an advisory is not a reason to re-run.
61
61
  - Otherwise → `/okstra-inspect status` for this task.
62
62
 
63
+ Name every file in this reply as a markdown link — `[<what it is>](<path>)`, path inside the parentheses — so the user can open it. `reportPaths.markdown` in the `report-finalize` result already carries this run's report, report record, and team state that way. Commands stay in backticks.
64
+
65
+ **Enforced:** `scripts/okstra_ctl/report_finalize.py` `closeout_command` applies this table to the run and returns the selected row as the result's `nextCommand`; the close is read from that value, not re-derived.
66
+
63
67
  Do not end the turn after the validator result. Task-qualified report paths and the same table live in the lifecycle core contract (`{{OKSTRA_LEAD_CONTRACT_PATH}}` "After persistence").
64
68
 
65
69
  {{TEAM_CREATION_GATE}}
@@ -106,7 +110,7 @@ Do not end the turn after the validator result. Task-qualified report paths and
106
110
  - Branch: `{{EXECUTOR_WORKTREE_BRANCH}}`
107
111
  - Base ref: `{{EXECUTOR_WORKTREE_BASE_REF}}`
108
112
  - Note: `{{EXECUTOR_WORKTREE_NOTE}}`
109
- - For any task-type with status `created` or `reused`, every role (lead, executor, verifier) MUST anchor reads and writes to the working tree path above — phase N inherits the working-tree state phase N-1 left behind. Verifiers read from the SAME path so they observe the exact diff produced by the Executor.
113
+ - For any task-type with status `created` or `reused`, every role (lead, executor, verifier) MUST anchor reads and writes to the working tree path above — phase N inherits the working-tree state phase N-1 left behind. Verifiers read from the SAME path so they observe the exact diff produced by the Executor. Workers receive this path as the `**Worktree:**` anchor their own prompt carries; you do not restate it in a dispatch instruction, and you do not stop a dispatch over a prompt that lacks it. **Enforced:** `okstra_ctl.initial_prompt_materialization._worktree_anchor_lines` renders that anchor into every initial worker prompt whose run has a provisioned worktree, and `_anchor_predates_this_contract` republishes an older prompt that predates it the next time the run is dispatched.
110
114
  - Branch and path are globally reserved per task-key via `~/.okstra/worktrees/registry.json`; concurrent okstra runs on this machine cannot collide.
111
115
  - The worktree is preserved after every run (no automatic cleanup) and is reused by every subsequent phase of the same task-key. Manual cleanup when fully done: `git worktree remove <path>` → `git branch -D <branch>` + remove the task-key entry from the registry.
112
116
  - For status `skipped-in-worktree` or `skipped-not-git`, the run operates directly in `{{PROJECT_ROOT}}` and this section is informational only.
@@ -137,7 +141,7 @@ Do not end the turn after the validator result. Task-qualified report paths and
137
141
 
138
142
  ### Incremental re-verification (implementation-planning clarification re-runs only)
139
143
 
140
- The **default is full re-verification**. Narrow this re-run to the impacted stages only when the deterministic `okstra incremental-scope` CLI returns `mode == "incremental"`. When the wizard pin is `auto` and the CLI returns `mode == "incremental"`, do not upgrade to full — the CLI already applied the base-ref check, the dependency closure, and the cutoff. This procedure fires ONLY when this run's task-type is `implementation-planning` AND a prior final report exists for this task-key (its data.json at `runs/implementation-planning/reports/final-report-implementation-planning-<prev-seq>.data.json`, where `<prev-seq>` is the most recent prior implementation-planning run's seq). For every other task-type, ignore this block and re-verify normally. This branches on the CLI's `mode` output only — it does NOT re-implement the safety logic in the prompt.
144
+ The **default is full re-verification**. Narrow this re-run to the impacted stages only when the deterministic `okstra incremental-scope` CLI returns `mode == "incremental"`. When the wizard pin is `auto` and the CLI returns `mode == "incremental"`, do not upgrade to full — the CLI already applied the base-ref check, the dependency closure, and the cutoff. This procedure fires ONLY when this run's task-type is `implementation-planning` AND a prior final report exists for this task-key (its data.json at `{{RUN_REPORTS_RELATIVE_PATH}}/final-report-implementation-planning-<prev-seq>.data.json`, where `<prev-seq>` is the most recent prior implementation-planning run's seq). For every other task-type, ignore this block and re-verify normally. This branches on the CLI's `mode` output only — it does NOT re-implement the safety logic in the prompt.
141
145
 
142
146
  0. **Honour the scope the user already pinned (not a judgement — an instruction).** The wizard asks for a re-verification scope whenever this re-run is narrowable or an answered id traces to no stage, and the answer arrives as two tokens: mode `{{REVERIFY_SCOPE_MODE}}`, stages `{{REVERIFY_SCOPE_STAGES}}`. Apply it before you form your own view:
143
147
  - `auto` — the user left the decision to this procedure. Run steps 1–7 exactly as written; nothing is pinned. If the CLI returns `mode == "incremental"`, keep it; do not upgrade to full.
@@ -154,7 +158,7 @@ The **default is full re-verification**. Narrow this re-run to the impacted stag
154
158
  3. **Call the CLI** (it is pure — same inputs always yield the same decision):
155
159
  ```
156
160
  okstra incremental-scope \
157
- --prev-data runs/implementation-planning/reports/final-report-implementation-planning-<prev-seq>.data.json \
161
+ --prev-data {{RUN_REPORTS_RELATIVE_PATH}}/final-report-implementation-planning-<prev-seq>.data.json \
158
162
  --run-manifest {{RUN_MANIFEST_RELATIVE_PATH}} \
159
163
  --cur-base-sha {{EXECUTOR_WORKTREE_BASE_REF}} \
160
164
  --prev-base-sha <prior baseRef from step 2> \
@@ -170,7 +174,7 @@ The **default is full re-verification**. Narrow this re-run to the impacted stag
170
174
  7. **Merge carried-forward verdicts.** In `incremental` mode the report writer receives the carried stage rows as a packet source and is told, in its own authoring contract, to copy them unchanged — you do not repeat that instruction to it. After `okstra plan-items seed --narrative ... --state ...`, the lead runs:
171
175
  ```
172
176
  okstra incremental-carry \
173
- --prev-data runs/implementation-planning/reports/final-report-implementation-planning-<prev-seq>.data.json \
177
+ --prev-data {{RUN_REPORTS_RELATIVE_PATH}}/final-report-implementation-planning-<prev-seq>.data.json \
174
178
  --cur-narrative <this run's report-writer narrative> \
175
179
  --state <this run's plan-body-verification state> \
176
180
  --prev-seq <prev-seq> \
@@ -180,3 +184,5 @@ The **default is full re-verification**. Narrow this re-run to the impacted stag
180
184
  A non-zero exit means the writer changed or omitted a carried stage, the item set drifted, or the stage scopes conflict. Fall back to **full** and re-verify every stage. The command writes only the convergence-owned plan state. It never patches the writer narrative or final `data.json`. `verdictCard` / `finalVerdict` are never carried.
181
185
 
182
186
  **Carry completeness (BLOCKING).** In incremental mode, this run's `planItems` MUST contain every plan-item id from the re-verified stages, each carried forward with its updated verdict. If re-verification concludes a plan item should be REMOVED, that is a signal the answer's blast radius is NOT local — abandon incremental and re-route to a FULL re-verification. The carry merge only ever ADDS prior items whose id is absent from this run; it cannot distinguish a legitimate deletion from an untouched carry, so it would resurrect a stale verdict.
187
+
188
+ **Enforced:** `scripts/okstra_ctl/incremental_carry.py` `_merge_stage_aware` performs the carry and exits non-zero when a re-verified stage's item set drifted from the prior run's `planItems`.
@@ -14,7 +14,7 @@ It overrides only the worker-dispatch portion of the selected host relay, not th
14
14
  | `leadRoleLabel` | `Okstra lead` |
15
15
  | `userPromptMode` | `host-text` |
16
16
  | `workerDispatchBackend` | `cmux-pane` |
17
- | `initialPromptDeliveryMode` | `lazy-path-reference` |
17
+ | `initialPromptDeliveryMode` | `eager-include` |
18
18
  | `sessionAccounting` | unchanged — keep your own runtime's accounting |
19
19
  | `resumeMode` | `artifact-checkpoint` |
20
20
  | `teardownMode` | `pane-teardown` |
@@ -31,7 +31,7 @@ It overrides only the worker-dispatch portion of the selected host relay, not th
31
31
  | `await_workers` | Run `okstra team await --project-root <root> --run-manifest <path>` through the host's asynchronous shell facility. |
32
32
  | `redispatch_worker` | Create the core-specified fresh jobs file and dispatch it with a new `dispatchKind`; never reuse a live worker conversation. |
33
33
  | `shutdown_workers` | Run `okstra team teardown --project-root <root> --run-manifest <path>` only after the user-approved cleanup gate. |
34
- | `record_lead_event` | Append progress and activity records to the manifest-provided `leadEventsPath`. Emit the matching `PROGRESS:` line and, when an activity record is required, the immediately following `ACTIVITY:` line from the same structured fields. |
34
+ | `record_lead_event` | Append progress and activity records to the manifest-provided `leadEventsPath`. Use `okstra lead-progress append --phase <phase-id>` for a checkpoint and `okstra agent-activity append --kind <kind>` for an activity record; both resolve the ledger path from the run manifest. Emit the matching `PROGRESS:` line — the command prints it as `progressLine` — and, when an activity record is required, the immediately following `ACTIVITY:` line from the same structured fields. |
35
35
  | `collect_usage` | Collect artifact/CLI-log-backed usage through the existing Okstra token-usage path; never substitute another runtime's session log. |
36
36
 
37
37
  An `implementation` run calls `dispatch_worker` twice: once for the Executor, then — after `await_workers` settles it — once for the verifiers. That second call's `--workers` list must omit the Executor's worker ID: it is materialized as the Executor on every dispatch, so a batch still carrying it is refused again. A verifier started beside the Executor observes base HEAD instead of the stage diff, so a single batch holding both is refused by `scripts/okstra_ctl/dispatch_core.py` `_validate_implementation_phase_order`, `--dry-run` included.
@@ -59,10 +59,7 @@ Use the screen to tell "still working" from "stuck", and to see at a glance whic
59
59
  - Worker completion is valid only from `workerDispatches[]`, terminal status sidecars, and required Result Paths. Pane creation alone is not completion.
60
60
  - Reverify uses a fresh jobs file at `runs/<task-type>/state/reverify-jobs-r<N>-<task-type>-<seq>.json`, sets `dispatchKind: "reverify-r<N>"`, and dispatches with `okstra team dispatch --project-root <root> --run-manifest <path> --dispatch-kind reverify-r<N> --jobs-file <jobs-file>`.
61
61
  - Report-writer uses a fresh one-job jobs file with `dispatchKind: "report-writer"` and the same schema, then dispatches through `okstra team dispatch --project-root <root> --run-manifest <path> --jobs-file <jobs-file>`.
62
- - A jobs file is `{"dispatchKind": "<kind>", "workers": [ … ]}` — the array key is `workers`, not `jobs`. Each entry follows the run manifest's identity version, and `scripts/okstra_ctl/dispatch_state.py` `worker_execution_identity` is the contract:
63
- - **v2 entry** (`schemaVersion: "2.0"`, `executionIdentityVersion: 2`): carries `participantRef`, `roleExecutionRef`, `assignmentRef`, `executionLabel`, `dutyId`, `invocationRef`, a positive integer `attempt`, `provider`, `modelExecutionValue`, `role`, `promptPath`, `workerResultPath`, `invocationId`, `audience`, `promptMetadataPath`, `enforcementMode: "core-pre-dispatch"`, and a `digests` object holding `catalogDigest`, `assignmentDigest`, `dutyDigest`, `instructionDigest`, and `promptDigest`. Copy every identity, assignment and digest value from the prompt's `.meta.json` that the prompt materialization step wrote: its `roleExecutionRef` is the dispatched role's own execution (a reverify's `role-exec-verifier-<N>`), not the analyser's `sourceRoleExecutionRef` from the round plan. **Do not include `workerId`** — a v2 entry that carries it is refused as mixing v1 and v2 identity; the worker key is projected from `assignmentRef`. A missing required field is reported together with every other missing field of that entry (`_missing_required_strings` in `scripts/okstra_ctl/dispatch_state.py`).
64
- - **v1 entry**: carries `workerId`, `provider`, `modelExecutionValue`, `role`, `promptPath`, and `workerResultPath`, and must carry none of the v2 identity fields.
65
- - `resultPath` and `completionPaths` are advisory in both: dispatch derives them from the same rules the roster path uses, so a jobs file cannot disagree with a roster dispatch about which artifact is the result.
62
+ - Generate v2 jobs files with `okstra agent-prompt jobs --project-root <root> --run-manifest <path> --dispatch-kind <kind> --metadata <prompt-meta.json> [--metadata <prompt-meta.json>] --out <jobs-file>`. Pass only the metadata paths for the core-planned batch. The command derives the `workers` array, canonical role execution, result headers, and five digests, and verifies them through the same consumer used at dispatch. Do not transcribe those fields. Identical output is reused; differing output is preserved and requires a new `--out` path. Existing v1 files remain readable by dispatch.
66
63
  - `workerResultPath` is the path the prompt tells the worker to write: the prompt's `**Result Path:**`, or `**Worker Result Path:**` for the report writer. `okstra team dispatch` refuses an entry whose value differs from that anchor, because the collector waits on `workerResultPath` while the worker writes where the anchor says. A reverify result is named `<worker-id>-worker-reverify-r<N>-<task-type>-<seq>.md`: the `-worker-` token is what the audit sidecar name inserts `-audit-` after (a name without it is refused with `worker result path has no canonical -worker- token`), and the round label is what keeps one round's file apart from the next. The report writer's `workerResultPath` is the roster's `resultPath` for `report-writer` and its `**Result Path:**` is the run manifest's `reportNarrativePath` — the report-writer materialization ([report-writer](../report-writer.md)) refuses any other pair. **Enforced:** `_validate_jobs_file_prompt_anchors` in `scripts/okstra_ctl/dispatch_state.py`, `_validate_report_writer_paths` in `scripts/okstra_ctl/agent/prompt_cli/materialize.py`.
67
64
  - `role` names the role execution's own role — `verifier` for reverify, `report-writer` for the report writer. It is not a per-round label: `dispatch_state.py` requires the entry's `role` to equal both the role execution's `role` and the duty's role, so a value like `worker-reverify-r<N>` is refused as `jobs file v2 identity does not match role execution authority`. The round lives in `dispatchKind` and in `invocationRef`. The report-writer completion paths include its narrative Markdown, worker-result pointer, and audit sidecar; they do not include the Phase 7 report record.
68
65
  - After either dispatch, run `okstra team await --project-root <root> --run-manifest <path>` before evaluating terminal status or completion paths.
@@ -70,5 +67,5 @@ Use the screen to tell "still working" from "stuck", and to see at a glance whic
70
67
  ## Completion, cleanup, and resume
71
68
 
72
69
  - Await through `okstra team await`; raw Result Path polling is forbidden for this backend.
73
- - Reclaim each round's panes at the round boundary through `okstra team teardown`, before the next round's dispatch. Finished workers leave their panes behind on purpose — the screen survives the process so you can still read a failure — so an unreclaimed round keeps shrinking the space the next one gets.
70
+ - Reclaim terminal panes after each batch through `okstra team reclaim --project-root <root> --run-manifest <path>` before dispatching the next batch. Reserve `teardown` for run completion.
74
71
  - Resume from run artifacts and lead-events checkpoints. After usage collection, persistence, and the core user-approval gate, run `okstra team teardown --project-root <root> --run-manifest <path>` and tear down only Okstra-owned panes recorded for the run.
@@ -37,6 +37,8 @@ After reading `task-brief.md`, extract the frontmatter `reporter-confirmations`
37
37
 
38
38
  On `pending`, emit `REPORTER_CONFIRMATION_PENDING` and stop. Do not invoke `team-contract` or an analyser, and do not write a final report. Regenerate the brief with `okstra-brief-gen` Step 6.5 and prepare a fresh run. A missing field is a legacy brief and proceeds with the matrix's carried flags. Current-format invalid values are rejected during preparation.
39
39
 
40
+ **Enforced:** `scripts/okstra_ctl/render.py` `_reporter_confirmation_status` reads the field at prepare time and carries the status into the rendered launch prompt; `validators/validate-brief.py` rejects an invalid value.
41
+
40
42
  ## Step 3: Use Run Input as the Run-State View
41
43
 
42
44
  Run Input is the only Phase 1 source for task identity, work category, workflow state, selected workers, model assignments, worker prompt paths, result paths, validator path, resume command, and configuration references.