okstra 0.189.4 → 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.
- package/README.md +1 -1
- package/dist/cli-registry.mjs +9 -0
- package/dist/cli-registry.mjs.map +1 -1
- package/dist/commands/chat/chat.mjs +54 -4
- package/dist/commands/chat/chat.mjs.map +1 -1
- package/dist/commands/lifecycle/install.mjs +12 -5
- package/dist/commands/lifecycle/install.mjs.map +1 -1
- package/dist/commands/lifecycle/uninstall.mjs +2 -1
- package/dist/commands/lifecycle/uninstall.mjs.map +1 -1
- package/dist/lib/host-config.d.mts +5 -3
- package/dist/lib/host-config.mjs +89 -31
- package/dist/lib/host-config.mjs.map +1 -1
- package/docs/architecture/storage-model.md +4 -1
- package/docs/architecture.md +2 -2
- package/docs/cli.md +10 -8
- package/docs/for-ai/skills/okstra-brief-gen.md +1 -1
- package/docs/for-ai/skills/okstra-chat.md +3 -3
- package/docs/for-ai/skills/okstra-inspect.md +11 -1
- package/docs/for-ai/skills/okstra-rollup.md +1 -0
- package/docs/for-ai/skills/okstra-run.md +5 -4
- package/docs/for-ai/skills/okstra-user-response.md +1 -1
- package/docs/project-structure-overview.md +17 -5
- package/docs/task-process/README.md +1 -1
- package/docs/task-process/error-analysis.md +2 -2
- package/docs/task-process/final-verification.md +1 -1
- package/docs/task-process/implementation.md +1 -1
- package/docs/task-process/release-handoff.md +8 -6
- package/docs/task-process/requirements-discovery.md +1 -1
- package/package.json +1 -1
- package/runtime/BUILD.json +2 -2
- package/runtime/agents/workers/claude-worker.md +4 -0
- package/runtime/bin/okstra-report-translate.py +10 -4
- package/runtime/prompts/launch.template.md +11 -5
- package/runtime/prompts/lead/adapters/cmux.md +4 -7
- package/runtime/prompts/lead/context-loader.md +2 -0
- package/runtime/prompts/lead/convergence.md +20 -83
- package/runtime/prompts/lead/okstra-lead-contract.md +24 -6
- package/runtime/prompts/lead/plan-body-verification.md +10 -3
- package/runtime/prompts/lead/report-writer.md +7 -4
- package/runtime/prompts/lead/team-contract.md +15 -9
- package/runtime/prompts/profiles/_common-contract.md +1 -0
- package/runtime/prompts/profiles/_implementation-deliverable.md +2 -0
- package/runtime/prompts/profiles/_implementation-diff-review.md +4 -0
- package/runtime/prompts/profiles/_implementation-executor.md +9 -5
- package/runtime/prompts/profiles/_implementation-self-check.md +2 -0
- package/runtime/prompts/profiles/_implementation-verifier.md +3 -4
- package/runtime/prompts/profiles/_stage-discipline.md +12 -5
- package/runtime/prompts/profiles/final-verification.md +1 -1
- package/runtime/prompts/profiles/implementation.md +2 -0
- package/runtime/prompts/profiles/release-handoff.md +4 -3
- package/runtime/prompts/wizard/prompts.ko.json +2 -1
- package/runtime/python/okstra_ctl/adapters/dispatch/cmux.py +6 -0
- package/runtime/python/okstra_ctl/adapters/hosts/antigravity/adapter.py +1 -0
- package/runtime/python/okstra_ctl/adapters/hosts/antigravity/relay.md +2 -2
- package/runtime/python/okstra_ctl/adapters/hosts/capability_adapter.py +9 -0
- package/runtime/python/okstra_ctl/adapters/hosts/claude-code/adapter.py +1 -0
- package/runtime/python/okstra_ctl/adapters/hosts/claude-code/relay.md +3 -3
- package/runtime/python/okstra_ctl/adapters/hosts/codex/adapter.py +1 -0
- package/runtime/python/okstra_ctl/adapters/hosts/codex/relay.md +17 -3
- package/runtime/python/okstra_ctl/adapters/hosts/external/adapter.py +1 -0
- package/runtime/python/okstra_ctl/adapters/hosts/external/relay.md +3 -3
- package/runtime/python/okstra_ctl/adapters/hosts/grok/adapter.py +1 -0
- package/runtime/python/okstra_ctl/adapters/hosts/grok/relay.md +2 -2
- package/runtime/python/okstra_ctl/adapters/hosts/kimi/adapter.py +1 -0
- package/runtime/python/okstra_ctl/adapters/hosts/kimi/relay.md +2 -2
- package/runtime/python/okstra_ctl/adapters/providers/codex/adapter.py +3 -3
- package/runtime/python/okstra_ctl/agent/invocation.py +107 -5
- package/runtime/python/okstra_ctl/agent/prompt_cli/cli.py +16 -0
- package/runtime/python/okstra_ctl/agent/prompt_cli/dynamic_verifier.py +3 -2
- package/runtime/python/okstra_ctl/agent/prompt_cli/jobs.py +87 -0
- package/runtime/python/okstra_ctl/agent/prompt_cli/materialize.py +72 -3
- package/runtime/python/okstra_ctl/analysis_packet.py +47 -6
- package/runtime/python/okstra_ctl/cmux.py +34 -13
- package/runtime/python/okstra_ctl/consumers.py +30 -7
- package/runtime/python/okstra_ctl/convergence.py +110 -21
- package/runtime/python/okstra_ctl/convergence_provenance.py +83 -0
- package/runtime/python/okstra_ctl/dispatch_core.py +127 -5
- package/runtime/python/okstra_ctl/dispatch_state.py +17 -9
- package/runtime/python/okstra_ctl/domain/host.py +5 -0
- package/runtime/python/okstra_ctl/domain/wizard/interaction.py +1 -0
- package/runtime/python/okstra_ctl/error_log_write.py +44 -4
- package/runtime/python/okstra_ctl/execution_mutation_audit.py +84 -7
- package/runtime/python/okstra_ctl/fixed_text.py +25 -7
- package/runtime/python/okstra_ctl/group_context.py +475 -10
- package/runtime/python/okstra_ctl/handoff.py +109 -32
- package/runtime/python/okstra_ctl/handoff_verification.py +80 -0
- package/runtime/python/okstra_ctl/initial_prompt_materialization.py +52 -10
- package/runtime/python/okstra_ctl/lead_progress.py +291 -0
- package/runtime/python/okstra_ctl/model_io/renderers.py +60 -1
- package/runtime/python/okstra_ctl/model_io_cli.py +6 -1
- package/runtime/python/okstra_ctl/ports/worker_dispatch.py +4 -0
- package/runtime/python/okstra_ctl/recap.py +179 -17
- package/runtime/python/okstra_ctl/reconcile.py +55 -4
- package/runtime/python/okstra_ctl/render.py +10 -1
- package/runtime/python/okstra_ctl/report_assembly.py +7 -6
- package/runtime/python/okstra_ctl/report_finalize.py +204 -11
- package/runtime/python/okstra_ctl/report_html/render.py +15 -4
- package/runtime/python/okstra_ctl/run.py +48 -14
- package/runtime/python/okstra_ctl/stage_targets.py +66 -0
- package/runtime/python/okstra_ctl/verdict_blocks.py +39 -12
- package/runtime/python/okstra_ctl/wizard/__init__.py +148 -0
- package/runtime/python/okstra_ctl/wizard/__main__.py +13 -0
- package/runtime/python/okstra_ctl/wizard/cli.py +176 -0
- package/runtime/python/okstra_ctl/wizard/confirmation.py +331 -0
- package/runtime/python/okstra_ctl/wizard/engine.py +363 -0
- package/runtime/python/okstra_ctl/wizard/ids.py +411 -0
- package/runtime/python/okstra_ctl/wizard/prompts.py +202 -0
- package/runtime/python/okstra_ctl/wizard/registry.py +836 -0
- package/runtime/python/okstra_ctl/wizard/render.py +189 -0
- package/runtime/python/okstra_ctl/wizard/roles.py +737 -0
- package/runtime/python/okstra_ctl/wizard/sources.py +703 -0
- package/runtime/python/okstra_ctl/wizard/state.py +689 -0
- package/runtime/python/okstra_ctl/wizard/statefile.py +145 -0
- package/runtime/python/okstra_ctl/wizard/steps_analysis.py +558 -0
- package/runtime/python/okstra_ctl/wizard/steps_identity.py +828 -0
- package/runtime/python/okstra_ctl/wizard/steps_options.py +340 -0
- package/runtime/python/okstra_ctl/wizard/steps_plan.py +959 -0
- package/runtime/python/okstra_ctl/wizard/steps_roles.py +672 -0
- package/runtime/python/okstra_ctl/worker_prompt_contract.py +43 -3
- package/runtime/python/okstra_ctl/worker_prompt_headers.py +14 -0
- package/runtime/python/okstra_ctl/workflow.py +2 -2
- package/runtime/python/okstra_ctl/worktree/__init__.py +2 -0
- package/runtime/python/okstra_ctl/worktree/cleanliness.py +7 -4
- package/runtime/python/okstra_ctl/worktree/git_ops.py +7 -0
- package/runtime/python/okstra_ctl/worktree/naming.py +15 -6
- package/runtime/python/okstra_ctl/worktree/provision.py +2 -1
- package/runtime/python/okstra_ctl/worktree_registry.py +27 -0
- package/runtime/python/okstra_ctl/wrapper_status.py +4 -0
- package/runtime/skills/okstra-brief-gen/SKILL.md +22 -3
- package/runtime/skills/okstra-chat/SKILL.md +8 -6
- package/runtime/skills/okstra-inspect/SKILL.md +2 -2
- package/runtime/skills/okstra-inspect/facets/recap.md +52 -4
- package/runtime/skills/okstra-rollup/SKILL.md +1 -1
- package/runtime/skills/okstra-run/SKILL.md +17 -7
- package/runtime/skills/okstra-schedule-gen/SKILL.md +2 -0
- package/runtime/skills/okstra-user-response/SKILL.md +1 -1
- package/runtime/templates/reports/brief.template.md +15 -7
- package/runtime/templates/reports/final-verification-input.template.md +2 -0
- package/runtime/templates/reports/group-context.template.md +7 -0
- package/runtime/templates/reports/html/tasks/release-handoff.template.html +2 -2
- package/runtime/templates/reports/implementation-planning-input.template.md +3 -0
- package/runtime/templates/reports/improvement-discovery-input.template.md +3 -0
- package/runtime/templates/reports/release-handoff-input.template.md +5 -3
- package/runtime/templates/reports/schedule.template.md +13 -4
- package/runtime/templates/reports/task-brief.template.md +1 -1
- package/runtime/templates/reverify-output-contract.md +5 -0
- package/runtime/templates/worker-error-contract.md +2 -0
- package/runtime/templates/worker-prompt-preamble.md +1 -1
- package/runtime/validators/validate-run.py +81 -22
- package/runtime/validators/validate_session_conformance.py +102 -2
- package/runtime/python/okstra_ctl/wizard.py +0 -7168
|
@@ -14,6 +14,8 @@ until Phase 5 ends, then drop from active context for Phase 6/7.
|
|
|
14
14
|
- **How to set the working directory**: every command and native edit MUST target `{{EXECUTOR_WORKTREE_PATH}}`, never the lead session's original project directory. The selected runtime adapter owns the exact native command syntax. Provider CLI wrappers inject the worktree at the CLI layer. For tools that accept an explicit working-directory flag (`git -C <path>`, `cargo --manifest-path`, `pytest --rootdir`), prefer that form.
|
|
15
15
|
- **Synced okstra state directory.** At provision time Okstra may symlink `.project-docs/` from the repo's **main worktree** into the task worktree. This is NOT an independent copy — writes through it land in the main worktree. Inside this run the executor MUST confine okstra artifact writes to its own task scope (i.e. `.okstra/tasks/<this-task-id>/...`). Other synced directories, if present due to local configuration, are not implicit okstra context; read them only when the brief explicitly cites them as source material.
|
|
16
16
|
|
|
17
|
+
**Enforced:** the worktree path reaches this worker as the `**Worktree:**` anchor (`scripts/okstra_ctl/worker_prompt_policy.py` `IMPLEMENTATION_HEADERS`), the CLI wrapper is started with that path as cwd by `scripts/okstra_ctl/dispatch_core.py`, and `scripts/okstra_ctl/execution_mutation_audit.py` `_source_changes` reports a mutation that landed outside the attempt's `writePolicy` roots.
|
|
18
|
+
|
|
17
19
|
## Pre-implementation context exploration (executor before first edit)
|
|
18
20
|
|
|
19
21
|
- **Three BLOCKING gates bind this run, and their bodies travel with this prompt** — inlined under their own headings, or named by path under `## Required prompt resources`. Follow the delivered body verbatim; a gate re-typed from memory is a skipped gate. Each gate's own body owns its rule list, so nothing here restates it:
|
|
@@ -27,11 +29,13 @@ Gate delivery (lead / maintainer — stripped before this body reaches a worker)
|
|
|
27
29
|
persisted executor prompt in that order under EAGER_INCLUDE, and lists their
|
|
28
30
|
paths under `## Required prompt resources` under LAZY_PATH_REFERENCE; a CLI
|
|
29
31
|
executor cannot read the profiles directory, so the file reference alone never
|
|
30
|
-
reaches it. Enforcement:
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
`
|
|
32
|
+
reaches it. Enforcement: `_required_resource_path_candidates` names the three
|
|
33
|
+
bodies for the `implementation-executor` audience, so composing the prompt is
|
|
34
|
+
what puts them there — there is no separate dispatch-time heading check, and a
|
|
35
|
+
missing heading means the composer did not run, not that a worker dropped it.
|
|
36
|
+
The `<SENTINEL_PREFIX>_PREFLIGHT_MISSING` /
|
|
37
|
+
`<SENTINEL_PREFIX>_POSTWRITE_GATE_MISSING` sentinels were the CLI-wrapper
|
|
38
|
+
template's check; that template is gone.
|
|
35
39
|
-->
|
|
36
40
|
- **Stage discipline (when a preceding stage is `done`):** its code is behavior-frozen — you may call, extend, or compose with it, never change what it already does. The rule body travels with this prompt the same way the gates do (`prompts/profiles/_stage-discipline.md`); only its `implementation` bullet binds you, the `implementation-planning` one binds the planner. Declaration-level — no wrapper sentinel.
|
|
37
41
|
- **Non-interactive auto-execution (BLOCKING for `runner=cli-wrapper`).** A CLI-wrapper executor runs head-less — there is no human at the keyboard. Skills loaded during the run (tdd, coding-preflight, and others) contain "get user approval", "state your plan to the user and wait", or "ask before proceeding" gates written for interactive sessions; in this run those gates are **already satisfied** by the upstream `implementation-planning` approval (the plan this stage executes was human-approved). The executor MUST NOT stop to request approval, MUST NOT end its turn after only producing a plan, and MUST carry the stage through end-to-end — RED → GREEN → refactor → per-cycle commit → `### Stage Carry Evidence`. The ONLY skill step to skip is the interactive user-approval prompt itself; every other skill rule (TDD discipline, conventions, real-IO isolation) still binds. Stopping early for approval in a head-less run is the observed empty-exit failure (exit 0, no diff): treat it as `contract-violated`.
|
|
@@ -26,3 +26,5 @@ fails, fix it or surface the violation — do not claim done on a failing item.
|
|
|
26
26
|
|
|
27
27
|
Close with a `Self-check coverage:` line naming the files you verified the
|
|
28
28
|
per-file items against, so the Coverage footer above and this gate reconcile.
|
|
29
|
+
|
|
30
|
+
**Enforced:** `scripts/okstra_ctl/initial_prompt_materialization.py` `_required_resource_path_candidates` names this body for the `implementation-executor` audience, so it is appended to every executor prompt rather than left to a file reference the CLI executor cannot open; `agents/workers/claude-worker.md` carries the same obligation for the in-process worker, which has no wrapper in front of it.
|
|
@@ -212,10 +212,7 @@ the command re-run does not:
|
|
|
212
212
|
the fix diff also forces `FAIL`. Files untouched since `<prev-head>` are
|
|
213
213
|
out of static-sweep scope — they already passed the previous full sweep.
|
|
214
214
|
|
|
215
|
-
|
|
216
|
-
(Phase 5.5 convergence consumes it); a fix-run verifier result that cites no
|
|
217
|
-
carried findings is a contract violation the lead records via
|
|
218
|
-
`okstra error-log append-observed --error-type contract-violation`.
|
|
215
|
+
**Enforced:** the fix run's carried findings come from the open cycle's ledger — `scripts/okstra_ctl/fix_cycles.py` `open_cycle` / `packet_summary` put them in this run's packet, so the verifier is given the set it must re-check rather than recalling it. The re-check itself lands in the verifier result file that Phase 5.5 convergence consumes; a fix-run verifier result citing no carried finding is a contract violation the lead records via `okstra error-log append-observed --error-type contract-violation`.
|
|
219
216
|
|
|
220
217
|
### DB / IO / SQL change — real-execution gate (mock-only acceptance forbidden)
|
|
221
218
|
|
|
@@ -233,6 +230,8 @@ A mocked unit test cannot observe the SQL a query builder actually emits — `co
|
|
|
233
230
|
|
|
234
231
|
If every verifier present in the resolved roster ends with a non-result terminal status (`timeout`, `error`, `not-run`) — i.e. zero independent verdicts were produced — the run MUST end with status `blocked` and route to a follow-up `error-analysis` run. The Okstra lead MUST NOT substitute its own verdict in place of the missing verifier outputs; synthesis requires at least one independent verifier's verdict. If one or more verifiers fail but at least one returns a verdict, the run proceeds with the surviving verdict(s) and the final report MUST explicitly notate which verifiers were unavailable, with the captured error / timeout evidence per failed verifier. Record such a verifier's `verifierResults[].verdict` as `not-run`, never as `FAIL`: `FAIL` is a rejection of the diff and it drives two gates — it blocks a passing verdict and it opens a stage fix cycle — so spending it on a verifier that produced no verdict manufactures a defect that does not exist.
|
|
235
232
|
|
|
233
|
+
**Enforced:** `validators/validate-run.py` `_validate_verifier_fail_blocks_verdict` fails a report whose `verifierResults[].verdict` is `FAIL` while `finalVerdict.verdictToken` passes, so a `FAIL` spent on a non-result cannot be quietly absorbed at synthesis; `validate_team_state` requires the terminal status and reason this policy branches on for every roster verifier.
|
|
234
|
+
|
|
236
235
|
## Verifier-specific forbidden actions (any occurrence → terminal status `contract-violated`)
|
|
237
236
|
|
|
238
237
|
- running lint / formatter auto-fix modes during a verifier's re-run — `eslint --fix`, `prettier --write`, `ruff check --fix`, `rustfmt` (writes by default; verifiers MUST use `cargo fmt --check` or `rustfmt --check`), `gofmt -w`, `black .` (use `black --check`), `isort .` (use `isort --check-only`), or any equivalent rewrite mode
|
|
@@ -11,24 +11,31 @@ resolver matches it anywhere and would recurse on this file itself.
|
|
|
11
11
|
|
|
12
12
|
## Stage discipline — preceding stages are behavior-frozen
|
|
13
13
|
|
|
14
|
-
A stage that is already `done` — a `depends-on` predecessor whose work is merged into this run's base — is **behavior-frozen**: code it added or modified keeps its existing behavior. Later stages
|
|
15
|
-
|
|
16
|
-
invariant — a completed, conformance-passed stage
|
|
14
|
+
A stage that is already `done` — a `depends-on` predecessor whose work is merged into this run's base — is **behavior-frozen**: code it added or modified keeps its existing behavior. Later stages call, extend, or compose with that code
|
|
15
|
+
without changing what it already does. This preserves the verified-stays-verified
|
|
16
|
+
invariant — a completed, conformance-passed stage should not silently regress when
|
|
17
17
|
a later stage runs.
|
|
18
18
|
|
|
19
|
+
No code compares this stage's diff against the file set a preceding stage
|
|
20
|
+
touched, so this rule reaches the run as an instruction, not as a gate. What is
|
|
21
|
+
checked is narrower: the verifier's rejection survives synthesis
|
|
22
|
+
(`validators/validate-run.py` `_validate_verifier_fail_blocks_verdict`) and a
|
|
23
|
+
mutation outside the attempt's write policy is reported
|
|
24
|
+
(`scripts/okstra_ctl/execution_mutation_audit.py` `_source_changes`).
|
|
25
|
+
|
|
19
26
|
- **implementation-planning** — decompose stages forward-only. No stage's scope
|
|
20
27
|
may require altering an earlier stage's behavior; each stage builds additively
|
|
21
28
|
on its predecessors' Stage Exit Contracts. If delivering an increment would
|
|
22
29
|
force changing an earlier stage's behavior, that earlier stage was mis-scoped —
|
|
23
30
|
fold the change into that stage or re-partition; do not plan a later stage that
|
|
24
31
|
rewrites it.
|
|
25
|
-
- **implementation** — the executor
|
|
32
|
+
- **implementation** — the executor does not alter the behavior of any file added
|
|
26
33
|
or modified by a preceding done stage. Touching such a file to *extend* it (a
|
|
27
34
|
new branch, a new caller, an additive field) is allowed; changing its existing
|
|
28
35
|
behavior is not. If a plan step appears to require a behavior change to
|
|
29
36
|
prior-stage code, treat it as a planning defect. Do two things and only these: record the finding, then route
|
|
30
37
|
to a new `implementation-planning` run. Never silently rewrite the prior-stage code.
|
|
31
38
|
- **Report evidence (declaration-level).** When this stage modifies a file that
|
|
32
|
-
a preceding stage added or modified, the final report
|
|
39
|
+
a preceding stage added or modified, the final report records three facts in the deliverable's edits / Validation Evidence section: which file,
|
|
33
40
|
why it was touched, and how the prior stage's behavior was preserved. Absent that
|
|
34
41
|
note, a reviewer treats a prior-stage edit as an unverified regression risk.
|
|
@@ -85,7 +85,7 @@ roles:
|
|
|
85
85
|
- **Read-only command log**: any pre-existing test/validation command touched during this run MUST be listed with its exact command line and one honest status — `executed` (ran; carries its exit code) / `advisory` (external Tier 3 did not PASS; carries observed/expected results and remains user-owned) / `env-unavailable` (should run but cannot in this environment — missing replica DB, container, or service; carries the reason, never a faked pass) / `not-configured` (no such qa-command tier) / `rejected` (a mutating/denied token — skipped, carries the denied token). A check that could not run locally is recorded as `env-unavailable` or `advisory` according to the external QA policy — never silently dropped and never reported as `executed` with an invented exit code. Mutating-command prohibition is the shared read-only boundary (see Non-goals); it is not restated per row.
|
|
86
86
|
- **Could-not-verify roll-up (§5.8.9)**: the template mechanically aggregates every not-confirmed check into one scannable list — `gap` requirement-coverage rows, `advisory` / `not-configured` / `env-unavailable` / `rejected` command rows, and `blocked` manual tests. You do not hand-author it, but you MUST give those rows their honest status so nothing unverified hides across sections: a check silently recorded as `executed`/`covered` will not surface in the roll-up. This is okstra's answer to "say what could not be verified this run."
|
|
87
87
|
- **Routing recommendation**: `finalVerification.routingRecommendation` is an **object** with exactly two fields — `target`, one value of the enum below, and `rationale`, the sentence tying that choice to the verdict and the blocker list. Free routing prose is not the field; a target named only in the prose does not route the task, because Phase 7 projects `workflow.nextRecommendedPhase` from `target` alone. The seven allowed targets are `release-handoff`, `release-handoff(stage-group)`, `error-analysis`, `implementation-option-selection`, `implementation-planning`, `implementation`, and `done`. Both `release-handoff` forms are allowed ONLY when the verdict is release-ready — `accepted`, or `conditional-accept` with every condition declaring `blocksReleaseHandoff: false`. Plain `release-handoff` is additionally allowed ONLY when the verification scope (the `Verification scope:` line of the injected `VERIFICATION_TARGET` block, recorded as the report's `verificationScope` field) is `whole-task`; a release-ready `single-stage` run routes to `release-handoff(stage-group)` (or `implementation` / `done`) instead. `done` ends the lifecycle here. Enforcement: `schemas/final-report-v2.0.schema.json` rejects a `target` outside the enum, a missing `rationale`, and a string in place of the object; `validators/validate-run.py` rejects a missing `target`, a verdict that is not release-ready routed to either `release-handoff` form (naming the condition ids that block it), and a `single-stage` report whose routing cites plain `release-handoff`.
|
|
88
|
-
- **Verified-row recording** (single-stage scope only): when the verdict is release-ready, the lead MUST run `okstra handoff record-verified --plan-run-root <plan-run-root> --stage <N> --report-path <final-report.md path> --data-json <final-report data.json path>` and quote the command + exit code in the report. The helper
|
|
88
|
+
- **Verified-row recording** (single-stage scope only): when the verdict is release-ready, the lead MUST run `okstra handoff record-verified --plan-run-root <plan-run-root> --stage <N> --report-path <final-report.md path> --data-json <final-report data.json path>` and quote the command + exit code in the report. The helper checks the latest verification manifest, task/stage identity, report pointer, prepared target, and recorded implementation commit. It records the captured commit and original verdict, including conditional acceptance conditions. A missing target or mismatched commit requires re-verification. Recording happens before final validation; eligibility is granted only after that verification passes validation. **Enforced:** `okstra_ctl.handoff_verification` validates the evidence, and `validators/validate-run.py` `_validate_verified_row_recorded` requires a `verified` row matching this report, captured commit, and verdict.
|
|
89
89
|
- Clarification request policy (phase-specific addendum — shared policy is in `_common-contract.md`):
|
|
90
90
|
- populate `## 1. Clarification Items` only when a blocker hinges on information only the user can supply (deployment intent, intended target environment, business-rule interpretation); use `Blocks=next-phase` for items that gate continuing to release-handoff
|
|
91
91
|
- Self-review pass before finalising the report (the Okstra lead runs this; do not delegate it):
|
|
@@ -72,3 +72,5 @@ The bulk of this profile's body is split into three sidecars so the lead's Phase
|
|
|
72
72
|
| `prompts/profiles/_implementation-deliverable.md` | Start of Phase 6 (after Phase 5.5 convergence completes, before report-writer dispatch prompt construction) | Required deliverable shape, Validation / TDD evidence rules, Verifier results structure, Self-review pass, Lead post-stage persistence |
|
|
73
73
|
|
|
74
74
|
**Entering Phase 5 / 6 while the relevant sidecar is not in the lead's context is BLOCKING — the phase entry is refused.** After reading a sidecar, the lead must continue into the phase's follow-up action within a single turn (i.e. the sidecar's rules take effect starting from the very turn it is read).
|
|
75
|
+
|
|
76
|
+
**Enforced:** `validators/validate_session_conformance.py` `_check_entry_guard_reads` requires each sidecar's read inside the run window and before that sidecar's phase checkpoint — `_ENTRY_GUARD_READS` carries the same table, so a lead that entered the phase without loading one is named in the run's findings.
|
|
@@ -25,6 +25,7 @@ roles: []
|
|
|
25
25
|
- the lead MUST capture `git status --short` and confirm the working tree is clean. Dirty state aborts the run; release-handoff packages the commits produced by `implementation`, it does not stage or commit changes.
|
|
26
26
|
- the lead MUST capture `git rev-parse --abbrev-ref HEAD` and record it as the **feature branch**. If the current branch is itself `main`, `master`, `prod`, `preprod`, `staging`, or `dev`, the run MUST end immediately — release-handoff never operates on a base branch.
|
|
27
27
|
- the lead MUST confirm `git log --oneline <base>..HEAD` contains at least one implementation commit. If it is empty, the run MUST end with status `blocked` and route back to `implementation`.
|
|
28
|
+
- In whole-task mode, compare `git rev-parse <handoff-branch>` with `finalVerification.sourceImplementationReport.capturedHeadSha` in the cited latest verification report, both at entry and immediately before pushing. Any mismatch stops delivery and requires final-verification again. In stage-group mode, run `okstra handoff eligible` again before pushing and confirm each selected stage is still eligible; assemble already checks the recorded verified commits. Record the compared commits and eligibility output in Executed Commands. These pre-push comparisons are lead instructions; the automated entry and assembly checks are enforced by `okstra_ctl.handoff_verification` and the handoff tests.
|
|
28
29
|
- User interaction protocol (Okstra lead — performed in order, using the selected runtime adapter's interactive prompt):
|
|
29
30
|
1. **Action selection** — present three choices and capture exactly one:
|
|
30
31
|
- `local checkout` — bring a verified branch into the MAIN worktree for local testing (no push, no PR). Two targets: the whole-task branch (whole-task mode only), or a single stage's stack branch (`--stage N`, available in both modes since stage branches survive verification). See step 1c. When `HANDOFF_MODE` is `stage-group`, offer only the per-stage target.
|
|
@@ -33,7 +34,7 @@ roles: []
|
|
|
33
34
|
If the user picks `skip`, route directly to the final-report self-review pass.
|
|
34
35
|
1c. **Local checkout execution** (only when the user picked `local checkout`) — first ask which target — when `HANDOFF_MODE` is `whole-task`, offer both the whole-task branch and one stage's stack branch; when it is `stage-group`, offer only the per-stage target — listing the selectable stage numbers (from the approved plan's Stage Map, since the run input document carries no Stage Map). Then confirm with the user that okstra will remove the corresponding okstra worktree (when it still exists) and `git checkout <branch>` in the MAIN worktree, and that the base branch is never modified. On confirmation run:
|
|
35
36
|
`okstra handoff local-checkout --project-root <project root> --project-id <id> --task-group <g> --task-id <t>` — append `--stage <N>` for the per-stage target.
|
|
36
|
-
Exit 1 means a precondition failed (MAIN worktree dirty, registry entry missing, or checkout failed): show the error verbatim and re-ask the action selection. On success the okstra worktree for that target no longer exists — if the lead's cwd was inside it, EVERY subsequent step (final-report authoring included) MUST use absolute paths or run from the MAIN worktree. Then route to the final-report self-review pass.
|
|
37
|
+
Exit 1 means a precondition failed (MAIN worktree dirty, registry entry missing, another run of this task still `in-progress`, the target branch already deleted, or checkout failed): show the error verbatim and re-ask the action selection. On success the okstra worktree for that target no longer exists — if the lead's cwd was inside it, EVERY subsequent step (final-report authoring included) MUST use absolute paths or run from the MAIN worktree. Then route to the final-report self-review pass.
|
|
37
38
|
- **stage-group mode step order** (overrides the default Q1→Q3 sequence): after Q1 picks `push + PR`, run (1) base-branch selection first — identical to Q2 below, because the dependency-closure check needs `origin/<base>`; (2) G2 stage confirmation (step 1g); (3) assemble (step 2g); then Q2b and Q3 as usual, with the collector branch as the PR head.
|
|
38
39
|
1g. **G2 — stage confirmation**: the stage selection already happened before the run (wizard `handoff_stage_pick`, or the CLI `--stages` flag) and is fixed in `HANDOFF_STAGES`. Display it as a one-line confirmation (`PR target stage: <csv> — proceeding`) and proceed; do NOT re-ask the multi-select. Only if `HANDOFF_MODE` is `stage-group` but `HANDOFF_STAGES` is empty (defensive, should not happen) run `okstra handoff eligible --plan-run-root <plan-run-root> --approved-plan <approved plan path>` and ask the user to pick from the eligible stages.
|
|
39
40
|
2g. **assemble**: run `okstra handoff assemble --plan-run-root <...> --approved-plan <...> --project-root <project root> --project-id <id> --task-group <g> --task-id <t> --work-category <c> --stages <csv> --base <chosen-base>`. Exit 2 means a stage-vs-stage merge conflict: show the `conflicts` paths and stop (route: reshape the group or resolve manually). Exit 1 means an eligibility/closure violation: show the error verbatim and re-ask G2. On success the returned `branch` is the PR head branch for every subsequent step.
|
|
@@ -44,7 +45,7 @@ roles: []
|
|
|
44
45
|
The chosen base MUST NOT equal the feature branch. If it does, re-ask.
|
|
45
46
|
2b. **Pre-merge conflict probe** (only when the user picked `push + PR`) — before the push/PR step, the lead MUST refresh the base ref and probe for merge conflicts against it:
|
|
46
47
|
- run `git fetch origin <chosen-base>` (read-only on the local working tree).
|
|
47
|
-
- run `git merge-tree --write-tree
|
|
48
|
+
- run `git merge-tree --write-tree <handoff-branch> origin/<chosen-base>`. Use the verified task branch in whole-task mode or the branch returned by assemble in stage-group mode, regardless of the current directory's HEAD. Exit 0 means clean. Exit 1 with a result-tree object ID on the first stdout line means a merge conflict. A missing result tree, or any other exit code, is an execution error: stop and report it, without offering permission to proceed as if it were a content conflict. An invalid ref can also return exit 1, so the exit code alone is insufficient.
|
|
48
49
|
- If no conflict is detected, proceed silently to Q3 (do NOT add a confirmation prompt — keep the happy path frictionless).
|
|
49
50
|
- If a conflict IS detected, present the conflicting paths (parsed from the `merge-tree` output) and capture exactly one:
|
|
50
51
|
- `proceed anyway` — continue to Q3; the PR will be opened with conflicts and the final report MUST flag this in `Merge Conflict Probe`.
|
|
@@ -64,7 +65,7 @@ roles: []
|
|
|
64
65
|
- **Filled-body self-check (runs on the drafted body, before Q3 shows it).** "Fill in the placeholders" is only observable if someone checks that they were filled, so scan the drafted body for these and carry the result into Q3: a residual HTML comment or template marker (`<!-- … -->`, `_Describe your changes…_`, a bare `TODO` / `FIXME` the diff did not introduce), an unchecked `- [ ]` box with no inline N/A justification, a section heading whose body is empty, and a whole body short enough to carry no substance. Each hit is reported to the user with its line — never silently left in, and never auto-filled with invented content. The user remains free to accept it; the point is that they see it before choosing `use as-is`.
|
|
65
66
|
- Allowed actions during the run (Okstra lead only):
|
|
66
67
|
- read-only inspection: `git status`, `git status --short`, `git diff`, `git log`, `git rev-parse`, `git ls-remote --heads origin <name>`, `gh pr list --head <branch>`, `gh pr view <url>`.
|
|
67
|
-
- merge-conflict probe (only when the user picked `push + PR`): `git fetch origin <chosen-base>` and `git merge-tree
|
|
68
|
+
- merge-conflict probe (only when the user picked `push + PR`): `git fetch origin <chosen-base>` and the exact `git merge-tree` command from step 2b. Both preserve the working tree and branch tips.
|
|
68
69
|
- feature-branch push (only when the user picked `push + PR`): `git push -u origin <current-branch>`. The pushed ref MUST be the feature branch — never the chosen base branch. (stage-group mode: the collector branch returned by assemble)
|
|
69
70
|
- PR creation (only when the user picked `push + PR` AND no PR with the same head already exists on origin): `gh pr create --base <chosen-base> --head <current-branch> --title "<title>" --body "<body>"`. The title and body are the user-confirmed PR draft.
|
|
70
71
|
- PR reuse: if `gh pr list --head <branch> --state open --json url --jq '.[0].url'` returns a URL, treat that PR as already existing — record the URL in the final report and SKIP `gh pr create`.
|
|
@@ -81,6 +81,7 @@
|
|
|
81
81
|
"echo_template": "task-type: {value}",
|
|
82
82
|
"options": {
|
|
83
83
|
"_RECOMMENDED_SUFFIX": " (recommended)",
|
|
84
|
+
"_BRIEF_SUFFIX": " (recommended · brief 가 지목한 진입 단계)",
|
|
84
85
|
"_APPROVE_SUFFIX": " (recommended · 계획 승인 후 구현)",
|
|
85
86
|
"_RERUN_SUFFIX": " (현재 phase 재실행)",
|
|
86
87
|
"_BLOCKED_RERUN_SUFFIX": " (현재 phase 재실행 — 열린 명료화에 답한 뒤)",
|
|
@@ -648,7 +649,7 @@
|
|
|
648
649
|
"worktree_not_git": " worktree : git 저장소 아님 — `{path}` 에서 직접 진행",
|
|
649
650
|
"worktree_impl_new": " worktree : stage {stage} 새 worktree `{path}` (브랜치 `{branch}`, base 는 run 준비 시 해소)",
|
|
650
651
|
"worktree_impl_reuse": " worktree : 기존 stage {stage} worktree `{path}` (브랜치 `{branch}`)",
|
|
651
|
-
"worktree_impl_auto": " worktree : stage 자동 선택 — `{path}`
|
|
652
|
+
"worktree_impl_auto": " worktree : stage 자동 선택 — `{path}` 옆에 `…--stage-<N>` worktree 생성/재사용",
|
|
652
653
|
"clarification_sidecars_empty": " user-responses: 없음 — final-report 만 첨부됩니다",
|
|
653
654
|
"clarification_sidecars_attached": " user-responses: 사이드카 {files}개 · 답변 {count}개 함께 첨부 — {ids}",
|
|
654
655
|
"clarification_sidecars_none_parsed": "답변으로 셀 항목 없음 (reframe 등)",
|
|
@@ -15,6 +15,11 @@ from .cli_wrapper import CliWrapperDispatchPort
|
|
|
15
15
|
|
|
16
16
|
CMUX_ADAPTER_NAME = "cmux"
|
|
17
17
|
CMUX_RELAY_CONTRACT = "lead/adapters/cmux.md"
|
|
18
|
+
# pane 워커는 프롬프트 파일을 그대로 읽는 CLI 프로세스라, 본문을 실어 보내는
|
|
19
|
+
# 쪽과 경로만 주는 쪽 중 어느 것도 강제하지 않는다. 실려 보내는 쪽을 선언하는
|
|
20
|
+
# 이유는 `lazy-path-reference` 가 명료화 답변과 fix carry 블록을 프롬프트에서
|
|
21
|
+
# 통째로 빼기 때문이다 — 그 두 블록은 리소스 목록에 경로로도 실리지 않는다.
|
|
22
|
+
CMUX_INITIAL_PROMPT_DELIVERY_MODE = "eager-include"
|
|
18
23
|
|
|
19
24
|
|
|
20
25
|
class CmuxDispatchPort:
|
|
@@ -49,6 +54,7 @@ class CmuxDispatchPort:
|
|
|
49
54
|
adapter_name=CMUX_ADAPTER_NAME,
|
|
50
55
|
dispatch_mode="team",
|
|
51
56
|
relay_contract=CMUX_RELAY_CONTRACT,
|
|
57
|
+
initial_prompt_delivery_mode=CMUX_INITIAL_PROMPT_DELIVERY_MODE,
|
|
52
58
|
)
|
|
53
59
|
|
|
54
60
|
def worker_write_capability(self) -> WorkerWriteCapability:
|
|
@@ -76,12 +76,12 @@ Render every numbered item as its option label followed by its description verba
|
|
|
76
76
|
|---|---|
|
|
77
77
|
| `read_artifacts` | Read the manifest-provided paths through the current Antigravity host file interface. |
|
|
78
78
|
| `write_artifact` | Write only core-authorized `.okstra/` artifacts and preserve their schemas. |
|
|
79
|
-
| `prompt_user` | Ask through the current host text/question interface and stop at approval gates until an explicit answer arrives. |
|
|
79
|
+
| `prompt_user` | Ask through the current host text/question interface and stop at approval gates until an explicit answer arrives. Emit the question as the last thing in that turn: assistant text emitted after the call renders below the question and separates it from the user's answer. |
|
|
80
80
|
| `dispatch_worker` | Verify each materialized invocation first. Dispatch `runner=native-session` through the current host with the returned `promptPath` and `hostModelValue`. Dispatch `runner=cli-wrapper` through `okstra worker-dispatch`, which consumes `modelExecutionValue`. **Not in a cmux run:** when `terminalBackend` is `cmux-pane`, the cmux adapter overrides this row. |
|
|
81
81
|
| `await_workers` | Await native host workers through the host primitive and CLI workers through their status sidecars, then verify terminal state and Result Paths. |
|
|
82
82
|
| `redispatch_worker` | Materialize and verify a fresh invocation, then start a fresh native worker or deterministic `worker-dispatch` attempt according to the persisted runner. |
|
|
83
83
|
| `shutdown_workers` | Perform host or process cleanup only for resources owned by this run. |
|
|
84
|
-
| `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. |
|
|
84
|
+
| `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. |
|
|
85
85
|
| `collect_usage` | Collect host- or artifact-backed usage through the existing Okstra token-usage path; do not substitute another runtime's session log. |
|
|
86
86
|
|
|
87
87
|
## Antigravity dispatch details
|
|
@@ -142,6 +142,15 @@ class CapabilityInteractionPort:
|
|
|
142
142
|
kind = "numbered-multi" if prompt.multi else "numbered-single"
|
|
143
143
|
return InteractionPlan(kind, AnswerProtocol("numbered", multi=prompt.multi))
|
|
144
144
|
|
|
145
|
+
@property
|
|
146
|
+
def native_option_limit(self) -> int:
|
|
147
|
+
"""이 호스트의 네이티브 단일선택기가 한 화면에 받는 옵션 수.
|
|
148
|
+
|
|
149
|
+
추천 목록을 만드는 쪽이 이 수를 넘기지 않아야 `plan` 이
|
|
150
|
+
`numbered-single` 로 내리지 않는다.
|
|
151
|
+
"""
|
|
152
|
+
return self._limits.max_options
|
|
153
|
+
|
|
145
154
|
def _native_options_fit(self, prompt: WizardPrompt) -> bool:
|
|
146
155
|
labels = tuple(option.label for option in prompt.options)
|
|
147
156
|
return (
|
|
@@ -12,7 +12,7 @@ This adapter maps the neutral Okstra lead operations to Claude Code host primiti
|
|
|
12
12
|
| `leadRoleLabel` | `Claude lead` |
|
|
13
13
|
| `userPromptMode` | `native-question` |
|
|
14
14
|
| `workerDispatchBackend` | `mixed` |
|
|
15
|
-
| `initialPromptDeliveryMode` | `
|
|
15
|
+
| `initialPromptDeliveryMode` | `eager-include` |
|
|
16
16
|
| `sessionAccounting` | `claude-jsonl` |
|
|
17
17
|
| `resumeMode` | `session-id` |
|
|
18
18
|
| `teardownMode` | `teammate-shutdown` |
|
|
@@ -140,12 +140,12 @@ For a `host-text` mapping, render each numbered item as its option label followe
|
|
|
140
140
|
|---|---|
|
|
141
141
|
| `read_artifacts` | Use the host file-read primitive and preserve the core contract's read order. |
|
|
142
142
|
| `write_artifact` | Use the host file-write primitive only for paths authorized by the active lifecycle phase. |
|
|
143
|
-
| `prompt_user` | Use `AskUserQuestion` for approvals and clarifications that fit `nativeLimits`. Do not print a numbered list in chat while that tool is available. Do not infer an answer from silence. |
|
|
143
|
+
| `prompt_user` | Use `AskUserQuestion` for approvals and clarifications that fit `nativeLimits`. Do not print a numbered list in chat while that tool is available. Emit the question as the last thing in that turn: assistant text emitted after the call renders below the question and separates it from the user's answer. Do not infer an answer from silence. |
|
|
144
144
|
| `dispatch_worker` | First verify the materialized invocation metadata. Dispatch `runner=native-session` through `Agent(name: "<role>", run_in_background: true)` without `team_name`, with `hostModelValue` and a summon message only — never the prompt body. The summon is exactly: `Your complete dispatch instructions are the document at <absolute promptPath>. Read that document in full before doing anything else — every line, continuing with offset until end of file — then execute it exactly. Do not act on this message alone.` The verified `promptPath` is already persisted and metadata-verified; inlining its body into the `Agent` call duplicates it in the lead context and lets the two copies drift. Dispatch `runner=cli-wrapper` with the deterministic shell command `okstra worker-dispatch --project-root <root> --run-manifest <path> --workers <ids>`; never wrap that process in another `Agent(...)` call. **Not in a cmux run:** when the run manifest's `terminalBackend` is `cmux-pane`, `prompts/lead/adapters/cmux.md` overrides this row. |
|
|
145
145
|
| `await_workers` | Arm one background shell poll for the pending Result Paths; the spawn acknowledgement is not completion. |
|
|
146
146
|
| `redispatch_worker` | Materialize and verify a fresh invocation, then use a fresh native `Agent(...)` session or `okstra worker-dispatch` attempt according to the persisted runner. |
|
|
147
147
|
| `shutdown_workers` | For each confirmed-complete worker selected for cleanup, send `SendMessage(to: <name>, message: { type: "shutdown_request" })` to idle the roster member **and** call `TaskStop(task_id: "<name>")` to stop its background task. Both are required; neither subsumes the other. |
|
|
148
|
-
| `record_lead_event` | Append progress and activity records to the manifest-provided `leadEventsPath`, including activity-contract-v1 records. Emit the matching `PROGRESS:` line and, when an activity record is required, the immediately following `ACTIVITY:` line from the same structured fields. |
|
|
148
|
+
| `record_lead_event` | Append progress and activity records to the manifest-provided `leadEventsPath`, including activity-contract-v1 records. 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. |
|
|
149
149
|
| `collect_usage` | Run `okstra token-usage` against the team-state; it reads the run-scoped `~/.claude/projects` session JSONL evidence. |
|
|
150
150
|
|
|
151
151
|
## Dispatch variants
|
|
@@ -110,23 +110,37 @@ Read this contract when `okstra preflight` returns this file as `runtimeReadines
|
|
|
110
110
|
}
|
|
111
111
|
```
|
|
112
112
|
|
|
113
|
-
For `request_user_input`, send one to three questions. Each question carries `id` (`prompt.step` or `questions[].step`), a header of at most 12 characters (`Q1`…`Q3`), the rendered question text including the progress suffix, and every wizard option as `{label, description}` in original order — the tool has no option `value` field. Do not
|
|
113
|
+
For `request_user_input`, send one to three questions. Each question carries `id` (`prompt.step` or `questions[].step`), a header of at most 12 characters (`Q1`…`Q3`), the rendered question text including the progress suffix, and every wizard option as `{label, description}` in original order — the tool has no option `value` field. **Send the wizard's free-input option (`__free_input__`) as the last row like any other choice**; it is the row that routes the answer into the wizard's own text step, and dropping it leaves the user with no way to answer anything the options do not cover. Do not invent an extra `Other` row of your own — the client already adds its own free-form row beside the options. Native plans are emitted only when the prompt fits `nativeLimits` (unique labels, two or three options, one to three questions) and no grouped question is multi-select. Other prompts use the text mapping so no option is dropped. Look up each answer by question `id`. The selected strings are in `answers[id].answers`. Match those strings to option labels, emit their `value` fields in original option order, and join with `,` when more than one is present. If the user typed into the client's own free-form row and the text matches no option label, do not submit that text to a `pick` step — it accepts option values only. Submit `__free_input__` when the step offers it, then submit the typed text unchanged as the answer to the text step the wizard asks next. Submit the text unchanged directly only when the step has no free-input option.
|
|
114
114
|
|
|
115
115
|
For a `host-text` mapping, render each numbered item as its option label followed by its description verbatim; preserve every item and its order. The next user message is the raw answer: do not translate a number such as `1`, a CSV reply such as `1, 3`, an option label, or an option value before `okstra wizard step`. For `sequential-group`, collect one raw reply per question in order and build one compact JSON object keyed by the corresponding `questions[].step`; the wizard owns all normalization.
|
|
116
116
|
|
|
117
117
|
|
|
118
|
+
### Client-aware question tool selection
|
|
119
|
+
|
|
120
|
+
Before intersecting `semanticFunctions` with live capabilities, prefer `request_user_input` when the current session permits that call. Use its live restrictions rather than assuming it is always Plan-only: Codex CLI can enable it in Default mode with `default_mode_request_user_input`. The JSON mapping above remains the terminal picker contract.
|
|
121
|
+
|
|
122
|
+
Use `request_user_input_async` only when the current client explicitly supports interactive asynchronous question cards, such as the Codex desktop app, and the synchronous tool is unavailable. Callable does not mean selectable: the Codex terminal (`codex-tui`, session source `cli`) can accept an asynchronous question but render it as a plain bulleted agent message. Do not count that terminal delivery as `native_single_select` or `native_question_group`. For a supported desktop client, replace the `function` of both native entries above with `request_user_input_async` and use the mapping below. Keep the conservative `nativeLimits` and the numbered mapping for multi-selection.
|
|
123
|
+
|
|
124
|
+
If the user requested a selectable interface in the terminal and `request_user_input` is unavailable, keep the current wizard step pending instead of printing its options. `okstra install` enables `features.default_mode_request_user_input` when a Codex home exists, through `ensureCodexQuestionPicker` in `src/lib/host-config.mts`. Restart or resume the Codex session after installation and reread this relay. Changing the feature does not replace the current session's tool catalog. Preserve the existing wizard state-file path and call `okstra wizard step --state-file <existing-path> --no-submit` after resuming; do not initialize a replacement wizard or submit a guessed answer. If installation reports a configuration shape it cannot safely edit, its recovery command is `codex features enable default_mode_request_user_input`. Apply a configuration change only when authorized by the user, otherwise present the recovery command. The feature's availability is reported by `codex features list`; older clients without it need a client update or a mode in which the synchronous tool is permitted.
|
|
125
|
+
|
|
126
|
+
For each asynchronous question send `{title, options}`. Put the question label, progress suffix, recommendation context, and option descriptions in `title`; put every original option label in the `options` string array in original order. Preserve the wizard's free-input option and do not add an extra Other option. Keep the correspondence between question position, wizard step, option label, and option value for this call. Send a group in one call.
|
|
127
|
+
|
|
128
|
+
The immediate `{accepted: true}` response acknowledges delivery; it is not a user answer. Keep the call pending until the user's asynchronous reply arrives. Read each reply's `answer` and map its question position to the stored step. Map the selected label to the original option value; apply the synchronous free-form routing rule above for unmatched text. Submit one option value for a single question or one compact step-to-value JSON object for a group.
|
|
129
|
+
|
|
130
|
+
Display the question only through the selected tool. Do not print it or its options again in commentary or final text. Do not call a second question tool, re-emit the same wizard step, or resubmit a question while its answer is pending. A preselected option is not an answer. Re-prompt only after an explicit answer fails wizard validation or the user requests a change. These are lead relay instructions; the runtime does not observe host UI emissions.
|
|
131
|
+
|
|
118
132
|
## Semantic operation mapping
|
|
119
133
|
|
|
120
134
|
| Operation | Mapping |
|
|
121
135
|
|---|---|
|
|
122
136
|
| `read_artifacts` | Read the manifest-provided paths through the current host's file interface. |
|
|
123
137
|
| `write_artifact` | Write only core-authorized `.okstra/` artifacts and preserve their schemas. |
|
|
124
|
-
| `prompt_user` | Use
|
|
138
|
+
| `prompt_user` | Use the client-appropriate, mode-available question tool selected above for clarifications that fit `nativeLimits`. Show the question once through that tool and wait for the actual answer. Emit the question as the last thing in that turn: assistant text emitted after the call renders below the question and separates it from the user's answer. Follow the host's separate restrictions for permission requests. Use host text for unsupported interactions only when the user has not required a selectable interface; otherwise preserve the pending step and follow the recovery above. |
|
|
125
139
|
| `dispatch_worker` | Verify each materialized invocation first. Dispatch `runner=native-session` with the current Codex host's primitive, the returned `promptPath`, and `hostModelValue`. Pass `runner=cli-wrapper` assignments to `okstra worker-dispatch --project-root <root> --run-manifest <path> --workers <ids>`; use `--dry-run` first when required. **Not in a cmux run:** when `terminalBackend` is `cmux-pane`, the cmux adapter overrides this row. |
|
|
126
140
|
| `await_workers` | Await native host workers through the host primitive and CLI workers through synchronous dispatch, then verify team-state terminal records and Result Paths for both. |
|
|
127
141
|
| `redispatch_worker` | Materialize and verify a fresh invocation, then start a fresh native worker or `okstra worker-dispatch` attempt according to the persisted runner. |
|
|
128
142
|
| `shutdown_workers` | Perform process cleanup when a wrapper remains live; otherwise this operation is a no-op recorded in state. |
|
|
129
|
-
| `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. |
|
|
143
|
+
| `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. |
|
|
130
144
|
| `collect_usage` | Collect artifact/rollout-backed usage through the existing Okstra token-usage path; never read Claude session JSONL as a substitute. |
|
|
131
145
|
|
|
132
146
|
## Codex dispatch details
|
|
@@ -76,12 +76,12 @@ Render every numbered item as its option label followed by its description verba
|
|
|
76
76
|
|---|---|
|
|
77
77
|
| `read_artifacts` | Read the manifest-provided paths through the current host's file or shell interface. |
|
|
78
78
|
| `write_artifact` | Write only core-authorized `.okstra/` artifacts and preserve their schemas. |
|
|
79
|
-
| `prompt_user` | Ask through the host text/question interface and require an explicit approval or clarification response. |
|
|
79
|
+
| `prompt_user` | Ask through the host text/question interface and require an explicit approval or clarification response. Emit the question as the last thing in that turn: assistant text emitted after the call renders below the question and separates it from the user's answer. |
|
|
80
80
|
| `dispatch_worker` | Verify each materialized invocation, then run deterministic `okstra worker-dispatch --project-root <root> --run-manifest <path>` for CLI assignments. Use `okstra team dispatch` only when the selected pane backend owns visible panes. |
|
|
81
81
|
| `await_workers` | Run `okstra team await --project-root <root> --run-manifest <path>` through the host's asynchronous shell facility. |
|
|
82
82
|
| `redispatch_worker` | Create the core-specified fresh jobs file and dispatch it with a new `dispatchKind`; never reuse a live worker conversation. |
|
|
83
83
|
| `shutdown_workers` | Run `okstra team teardown --project-root <root> --run-manifest <path>` only after the user-approved cleanup gate. |
|
|
84
|
-
| `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. |
|
|
84
|
+
| `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. |
|
|
85
85
|
| `collect_usage` | Collect artifact/CLI-log-backed usage through the existing Okstra token-usage path; never substitute another runtime's session log. |
|
|
86
86
|
|
|
87
87
|
## External dispatch details
|
|
@@ -91,7 +91,7 @@ Render every numbered item as its option label followed by its description verba
|
|
|
91
91
|
- Worker completion is valid only from `workerDispatches[]`, terminal status sidecars, and required Result Paths. Pane creation alone is not completion.
|
|
92
92
|
- 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>`.
|
|
93
93
|
- 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>`.
|
|
94
|
-
-
|
|
94
|
+
- Generate v2 reverify and report-writer 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>`. It verifies the inputs and derives canonical identity, role, result paths, and all five digests. Reverify uses role `verifier`; its round belongs to `dispatchKind`. Do not transcribe metadata fields or add `workerId` to v2 files. Existing v1 jobs-file consumers remain available. Report-writer completion uses the narrative and worker-result pointer; Phase 7 later assembles `data.json`.
|
|
95
95
|
- After either dispatch, run `okstra team await --project-root <root> --run-manifest <path>` before evaluating terminal status or completion paths.
|
|
96
96
|
|
|
97
97
|
## Completion, cleanup, and resume
|
|
@@ -136,12 +136,12 @@ For a `host-text` mapping, render each numbered item as its option label followe
|
|
|
136
136
|
|---|---|
|
|
137
137
|
| `read_artifacts` | Read the manifest-provided paths through the current Grok host file interface. |
|
|
138
138
|
| `write_artifact` | Write only core-authorized `.okstra/` artifacts and preserve their schemas. |
|
|
139
|
-
| `prompt_user` | Use `ask_user_question` for approvals and clarifications that fit `nativeLimits`. Do not print a numbered list in chat while that tool is available. Do not infer an answer from silence. |
|
|
139
|
+
| `prompt_user` | Use `ask_user_question` for approvals and clarifications that fit `nativeLimits`. Do not print a numbered list in chat while that tool is available. Emit the question as the last thing in that turn: assistant text emitted after the call renders below the question and separates it from the user's answer. Do not infer an answer from silence. |
|
|
140
140
|
| `dispatch_worker` | Verify the materialized invocation. Use the host primitive with `promptPath` and `hostModelValue` for `native-session`; use deterministic `okstra worker-dispatch` with `modelExecutionValue` for `cli-wrapper`. **Not in a cmux run:** the cmux adapter overrides this row. |
|
|
141
141
|
| `await_workers` | Await through the selected common dispatch backend, then verify terminal state and Result Paths. |
|
|
142
142
|
| `redispatch_worker` | Start a fresh attempt from the persisted assignment and record the supplied dispatch kind. |
|
|
143
143
|
| `shutdown_workers` | Clean up only host or process resources owned by this run. |
|
|
144
|
-
| `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. |
|
|
144
|
+
| `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. |
|
|
145
145
|
| `collect_usage` | Return explicit unavailable lead usage until Grok registers a session transcript or CLI usage artifact contract. |
|
|
146
146
|
|
|
147
147
|
## Completion, cleanup, and resume
|
|
@@ -75,12 +75,12 @@ Render every numbered item as its option label followed by its description verba
|
|
|
75
75
|
|---|---|
|
|
76
76
|
| `read_artifacts` | Read the manifest-provided paths through the current Kimi host file interface. |
|
|
77
77
|
| `write_artifact` | Write only core-authorized `.okstra/` artifacts and preserve their schemas. |
|
|
78
|
-
| `prompt_user` | Ask through the current host text interface and wait for an explicit answer. |
|
|
78
|
+
| `prompt_user` | Ask through the current host text interface and wait for an explicit answer. Emit the question as the last thing in that turn: assistant text emitted after the call renders below the question and separates it from the user's answer. |
|
|
79
79
|
| `dispatch_worker` | Verify the materialized invocation. Use the host primitive with `promptPath` and `hostModelValue` for `native-session`; use deterministic `okstra worker-dispatch` with `modelExecutionValue` for `cli-wrapper`. **Not in a cmux run:** the cmux adapter overrides this row. |
|
|
80
80
|
| `await_workers` | Await through the selected common dispatch backend, then verify terminal state and Result Paths. |
|
|
81
81
|
| `redispatch_worker` | Start a fresh attempt from the persisted assignment and record the supplied dispatch kind. |
|
|
82
82
|
| `shutdown_workers` | Clean up only host or process resources owned by this run. |
|
|
83
|
-
| `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. |
|
|
83
|
+
| `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. |
|
|
84
84
|
| `collect_usage` | Return explicit unavailable lead usage until Kimi registers a session transcript or CLI usage artifact contract. |
|
|
85
85
|
|
|
86
86
|
## Completion, cleanup, and resume
|
|
@@ -16,13 +16,13 @@ from okstra_ctl.domain.worker_presentation import SplitText
|
|
|
16
16
|
import okstra_ctl.model_discovery as model_discovery
|
|
17
17
|
|
|
18
18
|
|
|
19
|
-
#
|
|
20
|
-
#
|
|
21
|
-
# luna are the three visible 5.6 entries, in the priority the provider assigns.
|
|
19
|
+
# 모델 식별자와 순서는 Codex의 `~/.codex/models_cache.json`을 따른다
|
|
20
|
+
# (2026-09-07 확인, 클라이언트 0.153.4): astra / sol / terra / luna.
|
|
22
21
|
# `gpt-5.6` is not a slug that catalog offers at all, so it is gone from here;
|
|
23
22
|
# its rate moved to `_LEGACY_CODEX_PRICING` so past runs still price.
|
|
24
23
|
CODEX = {
|
|
25
24
|
# ChatGPT-account hosts serve these models without per-token billing.
|
|
25
|
+
"gpt-6-astra": ModelSpec("gpt-6-astra", "gpt-6-astra", "gpt-6-astra"),
|
|
26
26
|
"gpt-5.6-sol": ModelSpec("gpt-5.6-sol", "gpt-5.6-sol", "gpt-5.6-sol"),
|
|
27
27
|
"gpt-5.6-terra": ModelSpec("gpt-5.6-terra", "gpt-5.6-terra", "gpt-5.6-terra"),
|
|
28
28
|
"gpt-5.6-luna": ModelSpec("gpt-5.6-luna", "gpt-5.6-luna", "gpt-5.6-luna"),
|