okstra 0.144.0 → 0.146.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 +4 -1
- package/docs/architecture.md +22 -4
- package/docs/cli.md +53 -6
- package/docs/project-structure-overview.md +19 -9
- package/package.json +1 -1
- package/runtime/BUILD.json +2 -2
- package/runtime/agents/workers/report-writer-worker.md +5 -6
- package/runtime/bin/okstra-trace-cleanup.sh +28 -2
- package/runtime/prompts/lead/adapters/claude-code.md +3 -3
- package/runtime/prompts/lead/convergence.md +30 -5
- package/runtime/prompts/lead/okstra-lead-contract.md +9 -3
- package/runtime/prompts/lead/report-writer.md +20 -14
- package/runtime/prompts/lead/team-contract.md +3 -3
- package/runtime/prompts/profiles/_common-contract.md +1 -1
- package/runtime/prompts/profiles/change-impact-analysis.md +24 -0
- package/runtime/prompts/profiles/feature-analysis.md +24 -0
- package/runtime/prompts/profiles/forbidden-actions.json +18 -0
- package/runtime/prompts/profiles/project-analysis.md +24 -0
- package/runtime/prompts/wizard/prompts.ko.json +44 -1
- package/runtime/python/okstra_ctl/analysis_inputs.py +369 -0
- package/runtime/python/okstra_ctl/analysis_packet.py +4 -10
- package/runtime/python/okstra_ctl/clarification_items.py +74 -1
- package/runtime/python/okstra_ctl/codex_dispatch.py +117 -58
- package/runtime/python/okstra_ctl/convergence_engine.py +3 -1
- package/runtime/python/okstra_ctl/dispatch_core.py +19 -56
- package/runtime/python/okstra_ctl/dispatch_state.py +167 -3
- package/runtime/python/okstra_ctl/path_hints.py +6 -0
- package/runtime/python/okstra_ctl/paths.py +7 -44
- package/runtime/python/okstra_ctl/render.py +79 -4
- package/runtime/python/okstra_ctl/render_final_report.py +13 -4
- package/runtime/python/okstra_ctl/report_views.py +134 -3
- package/runtime/python/okstra_ctl/run.py +118 -0
- package/runtime/python/okstra_ctl/run_context.py +34 -2
- package/runtime/python/okstra_ctl/schema_excerpt.py +12 -4
- package/runtime/python/okstra_ctl/user_response.py +309 -3
- package/runtime/python/okstra_ctl/wizard.py +579 -32
- package/runtime/python/okstra_ctl/worker_liveness.py +84 -21
- package/runtime/python/okstra_ctl/worker_prompt_body.py +24 -4
- package/runtime/python/okstra_ctl/worker_prompt_contract.py +57 -0
- package/runtime/python/okstra_ctl/worker_prompt_policy.py +3 -0
- package/runtime/python/okstra_ctl/worker_state.py +65 -0
- package/runtime/python/okstra_ctl/workflow.py +22 -0
- package/runtime/python/okstra_token_usage/antigravity.py +3 -0
- package/runtime/python/okstra_token_usage/codex.py +54 -23
- package/runtime/python/okstra_token_usage/collect.py +141 -33
- package/runtime/python/okstra_token_usage/paths.py +27 -0
- package/runtime/python/okstra_vendor/__init__.py +15 -2
- package/runtime/schemas/convergence-groups-v1.0.schema.json +0 -1
- package/runtime/schemas/final-report-v1.0.schema.json +849 -3
- package/runtime/skills/okstra-run/SKILL.md +27 -5
- package/runtime/skills/okstra-setup/references/project-config.md +13 -4
- package/runtime/templates/reports/change-impact-analysis-input.template.md +58 -0
- package/runtime/templates/reports/feature-analysis-input.template.md +59 -0
- package/runtime/templates/reports/final-report.template.md +220 -0
- package/runtime/templates/reports/i18n/en.json +8 -0
- package/runtime/templates/reports/i18n/ko.json +8 -0
- package/runtime/templates/reports/project-analysis-input.template.md +58 -0
- package/runtime/templates/reports/report.js +84 -5
- package/runtime/templates/reports/user-response.template.md +19 -1
- package/runtime/validators/lib/fixtures.sh +1 -1
- package/runtime/validators/validate-report-views.py +61 -7
- package/runtime/validators/validate-run.py +94 -1
- package/runtime/validators/validate_analysis_report.py +895 -0
- package/src/cli-registry.mjs +7 -10
- package/src/commands/execute/render-bundle.mjs +3 -0
- package/src/commands/execute/worker-state.mjs +29 -0
- package/src/commands/inspect/worker-liveness.mjs +5 -3
- package/src/commands/lifecycle/preflight.mjs +13 -3
- package/src/lib/runtime-readiness.mjs +90 -0
- package/runtime/python/okstra_ctl/phase_cleanup.py +0 -235
- package/src/commands/execute/phase-cleanup.mjs +0 -38
package/README.md
CHANGED
|
@@ -190,11 +190,13 @@ To start a task outside a Claude Code session:
|
|
|
190
190
|
--project-id <id> \
|
|
191
191
|
--task-group <group> \
|
|
192
192
|
--task-id <id> \
|
|
193
|
-
--task-type <requirements-discovery|improvement-discovery|error-analysis|implementation-planning|implementation|final-verification|release-handoff> \
|
|
193
|
+
--task-type <requirements-discovery|improvement-discovery|project-analysis|change-impact-analysis|error-analysis|implementation-planning|implementation|final-verification|release-handoff> \
|
|
194
194
|
--base-ref <branch|tag|sha> \
|
|
195
195
|
--task-brief ./brief.md
|
|
196
196
|
```
|
|
197
197
|
|
|
198
|
+
`feature-analysis` is intentionally omitted from the standalone shell example. Start it with `/okstra-run`: the wizard collects its required feature target and passes that value through the internal Node render boundary. Standalone `okstra.sh` accepts neither `--analysis-target` nor `--evidence-inputs`.
|
|
199
|
+
|
|
198
200
|
This starts a new `claude` process in the lead role. For the complete argument list, see `okstra.sh --help` or [`docs/cli.md`](docs/cli.md).
|
|
199
201
|
|
|
200
202
|
Notable flags added in 0.7.0 / 0.8.0:
|
|
@@ -217,6 +219,7 @@ Major workflow changes added to `main` after 0.8.0:
|
|
|
217
219
|
- **Artifact-home rule (`.okstra/`)** — `<project>/.okstra/` is the only project artifact root owned by okstra. Anything outside this root is not okstra memory and may be read only when explicitly cited in Source Material or Reporter Confirmations. Writing outside the root requires the same explicit requested path. Internal equivalents are `glossary.md` for terminology and `decisions/<NNNN>-<slug>.md` for decision records, evaluated during `implementation-planning`.
|
|
218
220
|
- **Self-contained HTML final-report view** — After Phase 7 writes `final-report-<task-type>-<seq>.md`, `okstra render-views` automatically creates a sibling self-contained HTML view in the same `reports/` directory, with inline CSS/JavaScript and no external URLs. Its `Export user response` button serializes `## 1. Clarification Items` responses to `runs/<task-type>/user-responses/user-response-<task-type>-<seq>.md` for the next phase. View generation never changes the source Markdown.
|
|
219
221
|
- **`improvement-discovery` task type (sidetrack entry point)** — Within a codebase scope and priority-lens allowlist, multi-worker consensus produces N improvement candidates, with a default of eight and a hard cap of 12. This is a sidetrack entry point outside `PHASE_SEQUENCE`; the user selects candidates and starts each under a new task ID with `requirements-discovery`, `implementation-planning`, or `error-analysis`. Lens enum SSOT: [`scripts/okstra_ctl/improvement_lenses.py`](scripts/okstra_ctl/improvement_lenses.py). Output section: `## 5.9 Improvement Candidates` (11-column table). Validator: [`validators/validate_improvement_report.py`](validators/validate_improvement_report.py).
|
|
222
|
+
- **Read-only analysis task types (independent sidetracks)** — `project-analysis` maps the current project's components, dependencies, entry points, data stores, external systems, and feature index. `feature-analysis` traces one existing feature through flows, domain rules, state changes, integrations, and test coverage. `change-impact-analysis` maps the blast radius of a proposed change across preserved behavior, dependencies, tests, and operations. These are independent sidetracks outside `PHASE_SEQUENCE`, not lifecycle phases. No edits, tests, builds, migrations, or deployments are allowed against the target project. Start analysis runs through `/okstra-run`; its wizard owns target and evidence collection before calling the internal Node render command. The final report remains immutable: the HTML `Analysis Review` records accept, revision, or reject in a user-response sidecar. A revision request prioritizes a same-task, same-type full rerun; that rerun reanalyzes the whole confirmed scope and resolves every affected report ID instead of patching only the disputed rows. Input details: [`docs/cli.md`](docs/cli.md#analysis-sidetrack-task-types).
|
|
220
223
|
|
|
221
224
|
<a id="ops-commands"></a>
|
|
222
225
|
### 3.5 Operations commands
|
package/docs/architecture.md
CHANGED
|
@@ -134,7 +134,7 @@ Runtime entry points are consolidated in Python packages. Bash and skills only c
|
|
|
134
134
|
### Runtime assets (templates + lead resources)
|
|
135
135
|
|
|
136
136
|
- `prompts/launch.template.md` — lead prompt template.
|
|
137
|
-
- `prompts/profiles/*.md` —
|
|
137
|
+
- `prompts/profiles/*.md` — ten task-type profiles: the six lifecycle profiles (`requirements-discovery`, `error-analysis`, `implementation-planning`, `implementation`, `final-verification`, `release-handoff`) plus `improvement-discovery`, `project-analysis`, `feature-analysis`, and `change-impact-analysis` sidetracks.
|
|
138
138
|
- `templates/project-docs/task-index.template.md` · `templates/reports/final-report.template.md` · `templates/reports/settings.template.json` — runtime render inputs.
|
|
139
139
|
- `<PROJECT_ROOT>/.okstra/project.json` — project self-registration. Created/verified automatically on the first okstra.sh run; when `--project-root` is omitted, PROJECT_ROOT is resolved through ancestors / `git toplevel`.
|
|
140
140
|
|
|
@@ -302,6 +302,7 @@ The standard `okstra` workflow applies the following team contract consistently
|
|
|
302
302
|
- Because `Antigravity worker` is optional, it is attempted only in runs where it is explicitly included.
|
|
303
303
|
- Before the final judgment, each required role in the current run's worker roster must have either a result or an explicit terminal status (`completed`, `timeout`, `error`, `not-run`).
|
|
304
304
|
- Every attempted worker (`completed`, `timeout`, `error`) must have an assigned worker prompt history file under the current run's `prompts/` directory.
|
|
305
|
+
- Worker timing begins at the atomic transition to `in-progress`, which records `workers[].startedAt` in `team-state.json`; prompt creation time is not a dispatch proxy. `okstra worker-state transition` and both dispatch adapters share `dispatch_state.transition_worker_status`, while `okstra worker-liveness --team-state ... --worker ...` reads that timestamp as the launch-grace authority.
|
|
305
306
|
- An unnamed generic parallel worker is not accepted as a substitute for a required role.
|
|
306
307
|
|
|
307
308
|
### Cross-task worker prompt policy and final-verification boundaries
|
|
@@ -328,7 +329,7 @@ The complete artifact lifecycle is: worker results → Round 0 grouping → redu
|
|
|
328
329
|
|
|
329
330
|
Cross-verification does not mean that worker A reviews worker B's entire result. Round 0 records multi-source agreement immediately, and the reducer asks independent analyser instances to vote only on single-source or still-unresolved findings selected in the persisted queue. The report writer is never a voter. It organizes the validated result, while the later plan-body round verifies the consolidated `P-*` plan items rather than reopening the `F-*` finding queue.
|
|
330
331
|
|
|
331
|
-
The lead writes the grouped input, then advances it through the internal admin CLI operations `okstra convergence seed`, `plan-round`, `apply-round`, optional `apply-critic-gaps`, `finalize`, and `validate`. For worker W, each generated dispatch excludes findings originating from W; resolved findings leave the queue permanently. Lightweight reverify receives only its current persisted batch and embedded evidence, not the original analysis packet, profile, brief, or instruction set. Terminal worker non-results and completed per-finding `UNVERIFIABLE` responses become `verification-error`; the engine never fabricates a `DISAGREE` vote. The report writer does not vote and consumes
|
|
332
|
+
The lead writes the grouped input, then advances it through the internal admin CLI operations `okstra convergence seed`, `plan-round`, `apply-round`, optional `apply-critic-gaps`, `finalize`, and `validate`. For worker W, each generated dispatch excludes findings originating from W; resolved findings leave the queue permanently. Lightweight reverify receives only its current persisted batch and embedded evidence, not the original analysis packet, profile, brief, or instruction set. Its prompt carries an exact task type and active-phase forbidden-actions block; dispatch validates those phase anchors, and the run validator rejects a recorded phase-boundary violation. Terminal worker non-results and completed per-finding `UNVERIFIABLE` responses become `verification-error`; the engine never fabricates a `DISAGREE` vote. The report writer does not vote and consumes the validated terminal convergence state as a named input alongside every analysis-worker result. It completes three artifacts—the final-report data.json, its rendered Markdown sibling, and a worker-result pointer that lists those two outputs plus the convergence state—while the heartbeat/read-confirmation audit remains separate. Newly finalized convergence output is schema v1.3; under the compatibility path, valid historical final schema versions v1.0, v1.1, or v1.2 are reused and consumed without rewrite.
|
|
332
333
|
|
|
333
334
|
Coverage critic and plan-body verification remain separate from finding convergence. The critic audits the integrated Round 0 analysis, while implementation-planning's plan-body gate validates the later report draft through its own `P-*` queue and state file. Neither path changes the engine's `F-*` queue.
|
|
334
335
|
|
|
@@ -428,6 +429,9 @@ Each task type enforces phase-specific allowed and forbidden actions. A run crea
|
|
|
428
429
|
| `implementation` | Modify source code according to the approved `implementation-planning` final report. **One run executes exactly one stage** (selected with `--stage <auto\|N>`) | commit list, diff summary, out-of-plan edits block, validation/TDD evidence, rollback verification, verifier results (Antigravity/Codex/Claude), `carry/stage-<N>.json` evidence sidecar | `final-verification` | Yes (limited to the approved plan's file list; `git push`/publish/deploy/real migration prohibited) |
|
|
429
430
|
| `final-verification` | Check completed work for residual defects and regression risk, then make a release judgment | acceptance verdict, residual risk, follow-up routing (`error-analysis`/`implementation-planning`/`release-handoff`) | `pending-release-handoff` (enters `release-handoff` only when the verdict is `accepted`; otherwise reroutes to `error-analysis` or `implementation-planning`) | No (read-only tests only) |
|
|
430
431
|
| `release-handoff` | Deliver `accepted` changes as a commit, push, or PR according to the user's chosen method | user menu responses (H1 action / H2 PR base / H3 message handling), executed git/gh command log, commit SHA list, PR URL | `done-or-follow-up` | Yes—but execute **only the mutating commands selected by the user in the menu**. `git push --force*`, direct push to the base branch, `--no-verify`, `gh release`, and publish/deploy are prohibited. The source code itself must not be changed; package the existing `implementation` diff unchanged. |
|
|
432
|
+
| `project-analysis` | Map the current project structure and feature index | components, dependencies, entry points, data stores, external systems, feature index | `pending-routing-decision` | No (strictly read-only; tests are also prohibited) |
|
|
433
|
+
| `feature-analysis` | Trace one confirmed existing feature | flows, domain rules, state changes, external interactions, test coverage | `pending-routing-decision` | No (strictly read-only; tests are also prohibited) |
|
|
434
|
+
| `change-impact-analysis` | Map the impact of one proposed change | preserved behavior, impact items, dependency blast radius, test and operational impact | `pending-routing-decision` | No (strictly read-only; tests are also prohibited) |
|
|
431
435
|
|
|
432
436
|
Common constraints:
|
|
433
437
|
|
|
@@ -485,6 +489,16 @@ The stage-group interaction order is: **G1 select base → G2 confirm stages (se
|
|
|
485
489
|
|
|
486
490
|
A sidetrack entry point that is not a formal member of `PHASE_SEQUENCE`. It supports codebase-discovery scenarios without breaking the one-way lifecycle. The lens allowlist and candidate cap are consolidated in the single source of truth `scripts/okstra_ctl/improvement_lenses.py`. `validators/validate_improvement_report.py` checks eleven contract items against the final report; one of them is the shape of the `## 5.9 Improvement Candidates` table, whose eleven columns run from `Cand ID` through `Evidence` (the two counts are independent and happen to coincide). Two bidirectional grilling points—an enhanced budget of 8 in `okstra-brief-gen` Step 4 and the lead's Phase 1.5 reflect-back budget of 12—align the user's and AI's understanding.
|
|
487
491
|
|
|
492
|
+
### Read-only analysis sidetracks
|
|
493
|
+
|
|
494
|
+
`project-analysis`, `feature-analysis`, and `change-impact-analysis` are independent entry points outside `PHASE_SEQUENCE`. They share the normal task identity and report pipeline but never route into one another automatically. All three are read-only with respect to the target project: workers may inspect the confirmed scope but may not edit files, run tests or builds, execute migrations, or deploy.
|
|
495
|
+
|
|
496
|
+
`analysis_inputs.py` is the shared resolution boundary for both the wizard and `prepare_task_bundle()` (`scripts/okstra_ctl/analysis_inputs.py`). It owns the three-type allowlist, the permitted evidence relationships, report identity checks, review eligibility, source-commit freshness, and `PF-NNN` feature-index target resolution. Prepare freezes the result in `run-manifest.evidenceInputs` and `run-manifest.analysisTarget`; `validators/validate_analysis_report.py` requires the report's `analysisCommon.evidenceInputs` and resolved scope to match those snapshots exactly. The stored freshness value is `exact` when the evidence source commit is current and `stale` otherwise.
|
|
497
|
+
|
|
498
|
+
The self-contained report view presents an `Analysis Review` control. The browser's Export action downloads the Markdown sidecar; it cannot write into the project filesystem. The user must save or move that download into the canonical `runs/<task-type>/user-responses/user-response-<task-type>-<seq>.md` location before a later run can consume it. The downloaded sidecar contains a block named `ANALYSIS REVIEW` (Markdown heading `## ANALYSIS REVIEW`) without mutating the original report. It records `accepted`, `revision-requested`, or `rejected`; only accepted reports are offered automatically as later evidence. An explicitly selected unreviewed report is marked `user-unverified`, while revision-requested and rejected reports are refused as evidence.
|
|
499
|
+
|
|
500
|
+
A revision request supplies affected report IDs and a reason. The wizard prioritizes the same task type on the same task, and carries that report into a full rerun. The rerun reanalyzes the whole confirmed scope rather than only the disputed rows, then writes `analysisReviewResolution` under `analysisCommon` for every affected ID. `validators/validate_analysis_report.py` checks the source report identity, task type, run sequence, exact affected-ID coverage, and each resolution outcome. Report verdict (`analysis-complete`, `analysis-partial`, or `blocked`), review status, evidence freshness, and direct user verification (`user-unverified`) remain separate axes.
|
|
501
|
+
|
|
488
502
|
### requirements-discovery fan-out
|
|
489
503
|
|
|
490
504
|
For mixed or multi-item requests, requirements-discovery splits the request into packets by domain (the five-value work-category enum) and publishes them to `runs/requirements-discovery/fan-out/unit-*.md`. Each packet becomes a new task key through `okstra-run --task-brief <path>`. The dependency topological order is recorded in `index.md`, and okstra-schedule-gen owns the integrated schedule after task creation. okstra-brief-gen is not involved in this path. Validation: `validators/validate_fanout.py` (validate-run hook).
|
|
@@ -504,7 +518,7 @@ The complete specification for `okstra`'s three storage areas (stable task root
|
|
|
504
518
|
|
|
505
519
|
`okstra` is brief-first. The brief is the canonical source material that preserves external input and okstra augmentations. Any additional material workers need—reports, code snippets, logs, and so on—must be included inline or by path in the brief's `Evidence and Source Materials` section.
|
|
506
520
|
|
|
507
|
-
Briefs are accepted as direct input **only for entry phases**: users provide a brief path for `requirements-discovery`, `error-analysis`, and `
|
|
521
|
+
Briefs are accepted as direct input **only for entry phases**: users provide a brief path for `requirements-discovery`, `error-analysis`, `improvement-discovery`, `project-analysis`, `feature-analysis`, and `change-impact-analysis`. Downstream phases (implementation-planning / implementation / final-verification) automatically carry in the task manifest's `taskBriefPath` (the okstra-run wizard does not ask for it; if it is unregistered, a fallback picker recommends switching to an entry phase). `release-handoff` has no brief; prepare generates an input document that cites verification reports.
|
|
508
522
|
|
|
509
523
|
A brief is a **translation layer**: it converts external input—an issue-tracker ticket, requirements document, or user message—into an okstra-readable format while preserving the original verbatim and clearly distinguishing okstra additions as labelled augmentation. The output of the `okstra-brief-gen` skill is the source of truth. For each analysis phase, `prepare_task_bundle()` extracts the necessary frontmatter, task-specific brief sections, reference expectations, carried-in clarification, and directive into `instruction-set/analysis-packet.md`. This compact packet is the analysis workers' primary input; the original brief and profile/material files are fallback evidence opened only to verify evidence or fill omissions.
|
|
510
524
|
|
|
@@ -529,6 +543,9 @@ Default templates:
|
|
|
529
543
|
- `templates/reports/quick-input.template.md`
|
|
530
544
|
- `templates/reports/task-brief.template.md`
|
|
531
545
|
- `templates/reports/error-analysis-input.template.md`
|
|
546
|
+
- `templates/reports/project-analysis-input.template.md`
|
|
547
|
+
- `templates/reports/feature-analysis-input.template.md`
|
|
548
|
+
- `templates/reports/change-impact-analysis-input.template.md`
|
|
532
549
|
- `templates/reports/implementation-planning-input.template.md`
|
|
533
550
|
- `templates/reports/implementation-input.template.md`
|
|
534
551
|
- `templates/reports/final-verification-input.template.md`
|
|
@@ -779,7 +796,7 @@ Errors that occur while workers (Claude/Codex/Antigravity worker, Report writer,
|
|
|
779
796
|
- **Per-block cap on the codex log copy** (`okstra_log_mirror` in `scripts/okstra-codex-exec.sh`): workers read their required inputs end-to-end per the Worker Preamble's *Reading rules*, so a single report read can dump 170KB+ into the log and observed sidecars reach 8MB. The mirror keeps the first `log_block_line_cap` (120) lines of each output block and replaces the remainder with a `[okstra log-mirror] N line(s) elided` marker, draining every 500 elided lines so the idle watchdog keeps seeing writes. **Only the log copy is capped** — the stdout passthrough stays byte-identical, so the dispatching subagent's `BashOutput` and Phase 5 synthesis are unaffected (`tests-js/codex-log-mirror.test.mjs` asserts that byte-identity). The marker set is codex-specific; the claude wrapper emits `--output-format=stream-json` and does not share this filter.
|
|
780
797
|
- When tmux is reachable in the lead environment, the wrapper automatically splits a sibling pane and runs `tail -F <log-path>`. The trace-pane title appends `-tail` to the caller (worker) pane title: `<cli>-<role>-<pid>-tail` (for example, `codex-worker-93421-tail`). At the same time, the caller (worker) pane title is set to `<cli>-<role>-<pid>`. `<pid>` is the wrapper's own PID, so multiple workers with the same role spawned concurrently remain distinguishable, and operators can visually map `<caller> ↔ <caller>-tail`. **Caller-pane resolution**—because the Claude Code Bash tool now removes both `$TMUX` and `$TMUX_PANE` from the environment, the wrapper does not depend on environment variables. It (1) derives `<RUN_DIR>` as `dirname(dirname(prompt_path))` from the prompt path (paths.py SSOT), and (2) reads `<RUN_DIR>/state/lead-pane.id`, written once by the lead in its foreground pane, as the split anchor. This remains reliable for background dispatches, unlike active-pane guessing, even if the user changes panes. If the file is absent or the pane is stale, it falls back to `tmux display-message -p '#{pane_id}'` (the active pane). The trace split explicitly anchors to that caller pane with `-t`. The role is the wrapper's fifth optional positional argument and defaults to `worker`. The caller pane title is captured and restored by an EXIT trap, preventing stale titles across dispatches. Focus returns to the caller pane, and the trace pane remains after CLI exit so its scrollback is available. All paths silently degrade when tmux is unreachable, splitting fails, or tmux is outdated.
|
|
781
798
|
- **Run-scoped tagging for cleanup**: A trace pane's `tail -F` is a child of the tmux shell and survives Claude's exit. The wrapper tags each spawned pane with `tmux set-option -p @okstra_trace_run=<RUN_DIR>`, and `okstra-trace-cleanup.sh` discovers panes server-wide from that tag via `tmux list-panes -a` and runs `tmux kill-pane`. It requires neither tmux environment variables nor a pane-ID registry. Because the tag is run-scoped, it does not kill trace panes from other simultaneous okstra runs. Cleanup has two entry forms: the lead invokes it with `--run-dir <RUN_DIR>` to clean traces and worker-agent panes for that run, or the `hooks.SessionEnd` entry in `templates/reports/settings.template.json` invokes it with `--reap` to clean all trace panes tagged below `$CLAUDE_PROJECT_DIR/.okstra/` when no single run directory exists at session end. Missing tmux and stale pane IDs silently degrade.
|
|
782
|
-
- **Automatic cleanup on phase transitions, including worker-agent panes**: `okstra-trace-cleanup.sh --run-dir <RUN_DIR>` closes not only tagged trace panes but also worker-agent panes occupied by dispatched subagents. These harness-owned panes cannot be tagged, so the script identifies them within the lead session (`tmux list-panes -s -t <lead-pane>`) through a title allowlist: `claude-worker` / `codex-worker` / `antigravity-worker` / `report-writer-worker`. Implementation role titles such as `claude-executor` / `codex-verifier` / `agy-executor-tail`, and FleetView teammate prefixes `✳ ` / `⠂ `, are also treated as okstra panes. Session scoping and exclusion of the lead's own pane are determined by `<RUN_DIR>/state/lead-pane.id`; the lead pane is never killed even if its title matches.
|
|
799
|
+
- **Automatic cleanup on phase transitions, including worker-agent panes**: `okstra-trace-cleanup.sh --run-dir <RUN_DIR>` closes not only tagged trace panes but also worker-agent panes occupied by dispatched subagents. These harness-owned panes cannot be tagged, so the script identifies them within the lead session (`tmux list-panes -s -t <lead-pane>`) through a title allowlist: `claude-worker` / `codex-worker` / `antigravity-worker` / `report-writer-worker`. Implementation role titles such as `claude-executor` / `codex-verifier` / `agy-executor-tail`, and FleetView teammate prefixes `✳ ` / `⠂ `, are also treated as okstra panes. Session scoping and exclusion of the lead's own pane are determined by `<RUN_DIR>/state/lead-pane.id`; the lead pane is never killed even if its title matches. At every worker round boundary — after collecting that round's results and token usage, immediately before the next dispatch and before the `PROGRESS: phase-5.5-convergence` / `phase-6-synthesis` marker — the lead calls this script with `--run-dir` to reclaim the prior round's completed panes without prompting. `--keep <substr>` (repeatable) excludes panes whose title contains the substring, which is how an in-flight `report-writer-worker` survives the boundary. The lead first runs the same command with `--list` to count the panes it is about to reclaim and reports that count as `PROGRESS: phase-batch-cleanup panes=<n>`.
|
|
783
800
|
- **User confirmation at phase end**: At the final step of the run, the lead calls `okstra-trace-cleanup.sh --list --run-dir <RUN_DIR>` to show remaining okstra panes (worker-agent + trace), then asks once whether to "close all and clean up teammates / keep them." It follows the response (see *Phase wrap-up* in `prompts/profiles/_common-contract.md`). If approved, the lead cleans the panes. For a split-pane run, it then uses `okstra-team-reconcile.sh` to mark dead-pane members inactive and sends each completed teammate a `SendMessage` shutdown_request (`TeamDelete` was removed in v2.1.178; the implicit team disappears with the session). The lead does not gate this pane step by interpreting `lead-pane.id`; it **always** invokes the script, which safely returns an empty pane list and no-ops outside tmux. The teammate step is determined by the existence of an on-disk team configuration whose `leadSessionId` matches (`~/.claude/teams/session-*/config.json`), not by `teamCreate.status`. `--list` does not kill panes and prints only `<pane_id>\t<pane_title>`, so the user can see exactly what would be closed.
|
|
784
801
|
- Disk accumulation is handled by the `okstra-inspect logs` flow, which offers a read-only inventory and suggests cleanup commands for the user to copy and paste.
|
|
785
802
|
|
|
@@ -797,6 +814,7 @@ Tokens used in each run are collected from lead/worker session transcripts and w
|
|
|
797
814
|
- Claude lead/workers: per-message `message.usage` in `~/.claude/projects/<cwd-as-dashes>/<sessionId>.jsonl` or `~/.claude/projects/<cwd-as-dashes>/<lead-session>/subagents/agent-a<worker-name>-<hash>.jsonl`. Worker names are recovered from nested-subagent filenames, and only the directory for the current run's `team-state.lead.sessionId` is counted.
|
|
798
815
|
- Codex CLI: final `total_token_usage.total_tokens` in `~/.agent/sessions/Y/M/D/rollout-*.jsonl`
|
|
799
816
|
- Antigravity CLI: per-message `tokens.total` in `~/.antigravity/tmp/*/chats/session-*.json`
|
|
817
|
+
- CLI execution evidence and token attribution are independent. A wrapper `.status.json` proves `not-started`, `started`, `exited`, `timeout`, or `failed` and supplies the worker's collection window; only a matching transcript with a final token snapshot proves attributable usage. If a wrapper exited successfully but no attributable transcript exists, the worker remains `source: "unavailable"` with `cliExecutionStatus: "exited"` and a reason instead of becoming zero usage or being described as never invoked.
|
|
800
818
|
- Records billable-equivalent token math and USD cost estimates. It applies Anthropic billing ratios (`cache_creation_5m=1.25x`, `cache_creation_1h=2.0x`, `cache_read=0.1x`, `output=5x`). When the transcript provides separate `usage.cache_creation.ephemeral_5m_input_tokens` / `ephemeral_1h_input_tokens` values, they are counted separately.
|
|
801
819
|
- Pricing is centrally managed in `scripts/okstra_token_usage/pricing.py`. Update it when model prices change. Model IDs that fail price matching are exposed to the user in `usageSummary.unmatchedModels`, preventing silent-zero incidents.
|
|
802
820
|
- Project-wide historical usage is exposed through the read-only `okstra usage-report` command (`src/commands/inspect/usage-report.mjs` → `scripts/okstra_ctl/usage_report.py`) and the `okstra-usage` skill. It defaults to the whole current project's last 30 days and returns run coverage, raw and billable-equivalent tokens, known USD cost, CPU-sum milliseconds, and wall-clock milliseconds grouped by task type. Runs without usable Phase 7 usage are excluded from resource totals and reported through unavailable reason counts rather than treated as zero usage; unmatched model names remain visible when their tokens and time are included but their cost is not. Use `okstra-inspect` for one task's elapsed/context detail and `okstra-rollup` for task-group or project status/report digests.
|
package/docs/cli.md
CHANGED
|
@@ -21,6 +21,8 @@
|
|
|
21
21
|
- [`--clarification-response`](#--clarification-response)
|
|
22
22
|
- [`--resume-clarification`](#--resume-clarification)
|
|
23
23
|
- [`--project-root`](#--project-root)
|
|
24
|
+
- [`--analysis-target`](#--analysis-target)
|
|
25
|
+
- [`--evidence-inputs`](#--evidence-inputs)
|
|
24
26
|
- [`--directive`](#--directive)
|
|
25
27
|
- [`--fix-cycle`](#--fix-cycle)
|
|
26
28
|
- [`--workers`](#--workers)
|
|
@@ -59,6 +61,8 @@ Base command for initial entry with full arguments:
|
|
|
59
61
|
scripts/okstra.sh [--render-only] [--yes] [--no-plan-verification] --task-type <task-type> [--workers worker1,worker2] [--lead-runtime claude-code|codex] [--lead-model <model>] [--claude-model <model>] [--codex-model <model>] [--antigravity-model <model>] [--report-writer-model <model>] [--executor claude|codex|antigravity] [--critic off|claude|codex|antigravity] [--related-tasks taskA,taskB] [--work-category bugfix|feature|refactor|ops|improvement|unknown] [--base-ref <branch|tag|sha>] [--clarification-response <previous-final-report>] [--approved-plan <plan-path>] [--approve] --project-id <project-id> --task-group <task-group> --task-id <task-id> --task-brief <brief-path> [--directive <directive>] [--fix-cycle <yes|no>]
|
|
60
62
|
```
|
|
61
63
|
|
|
64
|
+
Analysis input ownership is narrower than the base shell command. The `/okstra-run` wizard collects `--analysis-target` and `--evidence-inputs` values and passes them internally to `node bin/okstra render-bundle`. `scripts/okstra.sh` does not accept either flag. Because `feature-analysis` requires a target, start that task type with `/okstra-run`; the two option sections below document the internal Node render inputs, not standalone shell options.
|
|
65
|
+
|
|
62
66
|
Short form for a later phase when an existing task-manifest.json is available:
|
|
63
67
|
|
|
64
68
|
```bash
|
|
@@ -133,13 +137,46 @@ For standard values and phase-specific responsibilities, see [Task type](#--task
|
|
|
133
137
|
- Validator: `validators/validate_improvement_report.py` enforces the 11-part contract for an `improvement-discovery` final report.
|
|
134
138
|
- Because an `improvement-discovery` run is not in `PHASE_SEQUENCE`, the `--task-key` short form does not automatically populate `nextRecommendedPhase` for it.
|
|
135
139
|
|
|
140
|
+
#### Analysis sidetrack task types
|
|
141
|
+
|
|
142
|
+
The three read-only analysis types are independent sidetracks outside `PHASE_SEQUENCE`:
|
|
143
|
+
|
|
144
|
+
| task type | Purpose |
|
|
145
|
+
|---|---|
|
|
146
|
+
| `project-analysis` | Map the current project's components, dependencies, entry points, data stores, external systems, and feature index. |
|
|
147
|
+
| `feature-analysis` | Trace one existing feature through flows, domain rules, state changes, external interactions, and test coverage. |
|
|
148
|
+
| `change-impact-analysis` | Map the blast radius of a proposed change across preserved behavior, dependencies, tests, and operations. |
|
|
149
|
+
|
|
150
|
+
Each one starts from a brief and produces a report only. The target project is strictly read-only: no edits, tests, builds, migrations, or deployments. A run ends at `pending-routing-decision`; it does not advance the normal phase sequence.
|
|
151
|
+
|
|
152
|
+
### `--analysis-target`
|
|
153
|
+
|
|
154
|
+
At the `node bin/okstra render-bundle` boundary, `--analysis-target` is required only for `feature-analysis`. It accepts either a free-text feature boundary or a `PF-NNN` ID from a selected `project-analysis` feature index. A `PF-NNN` value must match exactly one feature in the selected project-context evidence. `project-analysis`, `change-impact-analysis`, and non-analysis task types reject this render input.
|
|
155
|
+
|
|
156
|
+
### `--evidence-inputs`
|
|
157
|
+
|
|
158
|
+
At the `node bin/okstra render-bundle` boundary, `--evidence-inputs` accepts a comma-separated list of prior analysis final-report paths. Relative paths resolve from the target project root, selection order is preserved, and duplicate paths are rejected. The allowed relationships are:
|
|
159
|
+
|
|
160
|
+
| Consumer and source | Stored relation |
|
|
161
|
+
|---|---|
|
|
162
|
+
| `feature-analysis` ← `project-analysis` | `project-context` |
|
|
163
|
+
| `change-impact-analysis` ← `project-analysis` | `project-context` |
|
|
164
|
+
| `change-impact-analysis` ← `feature-analysis` | `feature-baseline` |
|
|
165
|
+
|
|
166
|
+
`project-analysis` accepts no evidence inputs. `feature-analysis` and `change-impact-analysis` may omit evidence, but every supplied report must match one of the relationships above.
|
|
167
|
+
|
|
168
|
+
Only `accepted` reports appear in automatic evidence choices. An explicitly selected, otherwise valid unreviewed report is recorded as `user-unverified`; `revision-requested` and `rejected` reports are rejected as evidence. A revision request instead makes the wizard prioritize a same-task, same-type full rerun. The selection is snapshotted in `run-manifest.evidenceInputs` with source task/run identity, relation, review status, source commit, and freshness.
|
|
169
|
+
|
|
170
|
+
Analysis reports expose four independent meanings. The report verdict is `analysis-complete`, `analysis-partial`, or `blocked`. The `Analysis Review` sidecar status is `accepted`, `revision-requested`, or `rejected`. Evidence freshness is current (`exact` in the stored snapshot) or `stale`. Direct user verification of an explicitly selected unreviewed report is `user-unverified`. These are separate axes: for example, a complete report can still be rejected by its reviewer, and accepted evidence can become stale after the source commit changes.
|
|
171
|
+
|
|
136
172
|
### `--task-brief`
|
|
137
173
|
|
|
138
174
|
The path to the task brief that serves as the basis for analysis.
|
|
139
175
|
Relative paths are resolved from the target project root.
|
|
140
176
|
|
|
141
177
|
This argument does not apply to `release-handoff`: a brief is input to an entry phase
|
|
142
|
-
(requirements-discovery / error-analysis / improvement-discovery
|
|
178
|
+
(requirements-discovery / error-analysis / improvement-discovery / project-analysis /
|
|
179
|
+
feature-analysis / change-impact-analysis), while
|
|
143
180
|
release-handoff preparation automatically creates an input document that cites the verification report
|
|
144
181
|
at `<task_root>/release-handoff-input.md` and uses it in place of a brief.
|
|
145
182
|
A non-empty `--task-brief` is rejected immediately for release-handoff.
|
|
@@ -338,6 +375,16 @@ Lead runtime independence boundary:
|
|
|
338
375
|
|
|
339
376
|
The current Claude Code independence boundary covers the external lead prompt and `okstra team *` worker dispatch. non-render `okstra_ctl.run --lead-runtime external` remains blocked; a complete external lead driver remains separate future work. `--runtime external` only selects the runtime adapter. `okstra install` creates `~/.agents/skills/` by default and also installs Claude skills and agents when `~/.claude` exists. Selecting the `claude` worker still requires the local Claude CLI wrapper.
|
|
340
377
|
|
|
378
|
+
Host-runtime readiness is independent of worker selection. When `/okstra-setup`
|
|
379
|
+
creates `<PROJECT_ROOT>/.claude/settings.local.json` in an already-open Claude
|
|
380
|
+
Code session, that session may not have accepted workspace trust yet. The next
|
|
381
|
+
`/okstra-run` preflight reports `runtimeReadiness.checks[id=workspace-trust]`
|
|
382
|
+
and stops before the wizard when trust is required or cannot be verified. The
|
|
383
|
+
user reopens the project, accepts the one Claude Code workspace prompt, and
|
|
384
|
+
reruns the command. This check applies only to a `claude-code` host; `codex` and
|
|
385
|
+
`external` hosts do not inspect Claude Code state, regardless of whether the
|
|
386
|
+
worker roster contains Claude, Codex, or Antigravity.
|
|
387
|
+
|
|
341
388
|
### Runtime auto-detection (`auto`)
|
|
342
389
|
|
|
343
390
|
`okstra run` defaults to `auto`. `auto` resolves to one of `claude-code`, `codex`, or `external` based on the host through `src/lib/runtime-resolver.mjs`. Precedence: explicit runtime > the `OKSTRA_RUNTIME_HOST` environment variable > Claude Code skill handoff > external when tmux is available > fail fast otherwise. The safe fallback never silently selects a runtime different from the user's intent.
|
|
@@ -649,7 +696,7 @@ The `okstra` Node CLI (`bin/okstra`) provides both installer/admin commands and
|
|
|
649
696
|
| `okstra doctor [--runtime claude-code\|codex\|external\|all] [--phase <phase>] [--json]` | Diagnose the runtime, Python imports, and skill/agent installation. The `codex` and `external` runtimes omit Claude skill checks. `--phase` adds readiness checks for `implementation`, `final-verification`, `release-handoff`, or `improvement-discovery` |
|
|
650
697
|
| `okstra setup --project-id <id>` | Create or update `.okstra/project.json` in the current project |
|
|
651
698
|
| `okstra check-project [--json]` | Verify that the current project is registered |
|
|
652
|
-
| `okstra preflight [--runtime <name>] [--cwd <dir>] [--json]` | Single skill-preflight call combining `ensure-installed`, with silent reinstall when stale,
|
|
699
|
+
| `okstra preflight [--runtime <name>] [--cwd <dir>] [--json]` | Single skill-preflight call combining `ensure-installed`, with silent reinstall when stale, `check-project`, and host-specific `runtimeReadiness` into one JSON response. A `claude-code` host checks project workspace trust; `codex` and `external` hosts return ready without reading Claude Code state. Step 0 of every project-scoped skill converges on this command |
|
|
653
700
|
| `okstra convergence seed --groups <path> --work-state <path> --final-state <path> --migration-dir <dir> [--restart-from-round0]` | Create, resume, reuse, or explicitly recover deterministic convergence state |
|
|
654
701
|
| `okstra convergence plan-round --work-state <path> --plan <path>` | Persist the next roster-aware dispatch plan without mutating working state |
|
|
655
702
|
| `okstra convergence apply-round --work-state <path> --plan <path> --results <path>` | Validate one complete structured result set and atomically reduce it into working state |
|
|
@@ -659,13 +706,13 @@ The `okstra` Node CLI (`bin/okstra`) provides both installer/admin commands and
|
|
|
659
706
|
| `okstra convergence example --kind <groups\|round-results\|critic-results>` | Print one deterministic valid input example as JSON |
|
|
660
707
|
| `okstra plan-items extract --data <data.json> --output <items.json>` | Deterministically extract the complete implementation-planning `P-*` queue from report-writer data.json |
|
|
661
708
|
| `okstra plan-items validate --data <data.json> --items <items.json>` | Require the persisted `P-*` queue to match a fresh deterministic extraction exactly |
|
|
662
|
-
| `okstra phase-cleanup --project-root <dir> [--task-key <k>] [--run-dir <dir>] [--fallback-team <label>] [--json]` | Reclaim the resources the previous phase or worker batch finished with, so the next phase does not inherit them. It is tmux-aware: inside a tmux pane it reclaims the prior run's **completed** worker panes through `okstra-trace-cleanup.sh --reclaim-completed`, and outside tmux there are no panes, so it skips pane reclaim entirely. Either way it reconciles teammates through `okstra-team-reconcile.sh` and prints the dismissible teammate names for the lead to shut down — it names them, it never dismisses them itself. Only completed resources are touched: the lead pane and any in-flight worker are preserved. `--project-root` is required and is enough on its own for the teammate half. `--fallback-team <label>` passes the live team label (`session-<lead-session-prefix>`) that the reconcile falls back to when the live session directory is gone: Claude Code re-issues the session id on resume or compaction, and without the label the roster resolves to nothing and the dismissible-teammate list comes back empty — so every caller inside a run should pass it. The prior run is located by `--run-dir` when given, otherwise auto-discovered from `--task-key` — auto-discovery walks both flat `runs/<type>/reports/` and staged `runs/<type>/stage-N/reports/` (`implementation` / `final-verification`), so a staged prior run is found without `--run-dir`; pass `--run-dir` only to override the discovery with a specific run. Output is the `mode` / `panes-reclaimed` / `dismissible-teammates` triple, or the same values as JSON under `--json`. A cleanup failure never blocks the next phase: a missing script, a failed helper, or an undiscoverable prior run still exits 0 (only a malformed invocation exits non-zero) |
|
|
663
709
|
| `okstra config <get\|set\|unset\|show> [key] [value] [--scope project\|global\|all]` | Manage persistent settings such as `pr-template-path` with atomic JSON writes |
|
|
664
710
|
| `okstra memory <add\|list\|search\|show\|archive>` | Manage global conversation memory in `~/.okstra/memory-book`, a user-home store separate from project `.okstra/` and the CLI basis of the `save this in okstra` natural-language skill |
|
|
665
711
|
| `okstra manager <init\|discover-projects\|new\|task>` | Public CLI for grouping cross-project okstra tasks into manager-owned context. `new project`, `new task-group`, and `new task` create manager plans; `task assign`, `task note`, `task sync`, `task status`, and `task run` manage per-project assignments and snapshots. `new project --project-root` accepts only existing directories and performs setup-equivalent registration only if `.okstra/project.json` is absent. Public documentation uses the full `project-id:task-group:task-id` child task key; when child task IDs differ within the same manager task, select the exact child with `--child-task-id`. `task run` does not execute the child lead directly; it returns `prepared` launch metadata/event and a child launch-context packet as JSON |
|
|
666
712
|
| `okstra rollup [--task-group <group>] [--project-root <dir>] [--cwd <dir>]` | Read-only backend for the okstra-rollup skill. For every catalog task, or one task group, it emits JSON with per-task run counts, raw duration in ms, error counts, latest report paths, group totals, and status/category/phase distributions. Omitting `--task-group` targets the whole project catalog. The caller skill formats raw ms as HH:MM:SS and synthesizes report prose. Use the `okstra inspect` family for a single-task drill-down |
|
|
667
713
|
| `okstra usage-report [--days <positive-int>] [--project-root <dir>] [--cwd <dir>] [--json]` | Read-only backend for the okstra-usage skill. Defaults to the whole current project's last 30 days and emits task-type run coverage, raw/billable tokens, known USD cost, CPU-sum milliseconds, wall-clock milliseconds, unavailable reason counts, and unmatched pricing models |
|
|
668
|
-
| `okstra worker-
|
|
714
|
+
| `okstra worker-state transition --team-state <path> --worker <id> --status <in-progress\|completed\|timeout\|error\|not-run> [--reason <text>] [--model <execution-value>]` | Atomically update one persisted worker row. `in-progress` records the authoritative `startedAt` and clears `endedAt`; terminal states record `endedAt`; `timeout`, `error`, and `not-run` require a reason. Dispatch adapters use this same transition path, so CLI-backed and in-process orchestration share the status timestamp contract |
|
|
715
|
+
| `okstra worker-liveness [--audit <path>]… [--team-state <path> --worker <id>]… [--max-idle <seconds>] [--launch-grace <seconds>] [--json]` | Judge whether pending workers are still alive so the lead's poll ends a stalled wait early instead of paying the full deadline. Both selectors repeat and may be mixed in one call. `--audit` takes an in-process worker audit sidecar and reports `stalled` when its `- PROGRESS:` heartbeat is past the idle budget. Each `--team-state` must have a paired `--worker`; that selector resolves the worker's prompt and starts launch grace from its persisted `startedAt`, then reports `did-not-launch` when neither the wrapper `.log` nor `.status.json` appears. Healthy probes report `live`. It only judges—it never kills or re-dispatches. Exit 1 on an unhealthy verdict, so a poll loop can branch without parsing JSON. The heartbeat line shape and budget come from the `okstra_ctl.worker_heartbeat` SSOT shared with the Phase 7 audit (`validators/validate_session_conformance.py`) |
|
|
669
716
|
| `okstra log-report [--project-root <dir>] [--cwd <dir>] [--top <N>] [--json]` | Read-only inventory of wrapper transcript `.log` files and their sibling prompt `.md` files. Each ranked entry preserves `path` / `sizeBytes` for compatibility and also reports `transcriptPath`, `transcriptBytes`, `promptPath`, `promptBytes`, and `transcriptToPromptRatio`; totals distinguish prompt bytes from transcript bytes and count paired files. Ranking remains transcript-size descending |
|
|
670
717
|
| `okstra recap <assemble\|record\|note> <task-root\|task-key> …` | Backend for the okstra-inspect `recap` facet. `assemble` is read-only and prints a JSON summary of phase transitions across a task's runs. `record --kind <summary\|qa> --mode <artifact\|code> --answer <text> [--question <text>] [--citation <path:line> …]` appends one line to `<task-root>/recap/recap-log.jsonl` and never mutates other artifacts. `note --kind <verification-evidence\|decision-draft\|analysis-note> --slug <topic> --purpose <text> --scope-note <text> (--body <markdown>\|--body-file <path>)` writes an agent-authored note to `<task-root>/notes/` and prints its path plus the `--clarification-response` argument for feeding it into a later run |
|
|
671
718
|
| `okstra user-response <list\|show\|write> …` | Backend for the `/okstra-user-response` skill: answer a task's open clarification questions in-session and write the response sidecar. `list --home <dir> --project <id> [--limit <n>]` finds reports with open questions; `show --report <md>` reads one report's questions; `write --report <md> --answers <json> [--approval <json>] [--task-key <key>]` writes the sidecar. Each answer carries a `disposition` of `answer` or `reframe`; a `reframe` is carried into the next run as a re-scoped brief. JSON output; exit 0 ok / 1 error |
|
|
@@ -687,7 +734,7 @@ The `okstra` Node CLI (`bin/okstra`) provides both installer/admin commands and
|
|
|
687
734
|
| `okstra report-finalize --project-root <dir> --run-manifest <path> --report <final-report.md>` | Run the whole Phase 7 post-report sequence in its contractual order: `token-usage` → `render-views` → `spawn-followups` → `validate-run`. Stops at the first non-zero exit and names the failing step, then prints a per-step `[ok]` / `[FAIL]` / `[skip]` summary on stderr so the outcome is legible without parsing the JSON payload. Every step is idempotent, so re-running after a fix is safe — but `--only <step>` (repeatable) reruns just the named steps in contractual order, which matters because `validate-run` is the step that usually fails and retrying it otherwise repeats the three steps before it at full token and wall-clock cost. This is the same code path (`scripts/okstra_ctl/report_finalize.py`) the Codex lead adapter runs automatically after its report-writer completes, so a Claude-led and a Codex-led run finalize identically. `--workspace-root` is owned by the Node wrapper. Prefer this over invoking the four steps individually |
|
|
688
735
|
| `okstra render-views <final-report.md>` | The Phase 7 `render-views` step, runnable on its own: deterministically create a human-facing self-contained sibling `*.html` view from one final-report Markdown file after token substitution. The source Markdown is unchanged. The Node delegation wrapper calls `scripts/okstra-render-report-views.py`; `validators/validate-report-views.py` verifies form-control placement, absence of external URLs, stale source digests, and Response ID parity |
|
|
689
736
|
| `okstra design-prep <list\|show\|write>` | Review AI-prepared implementation design requests, inspect their effective confirmed response, or append a confirmed user/wizard response without editing the planning report |
|
|
690
|
-
| `okstra wizard <init\|step\|render-args\|confirmation\|outcome> --state-file <path>` | Interactive input state machine for okstra-run, implemented by `okstra_ctl.wizard`. Seed a state file with `init`, then repeatedly call `step --answer <val>` to receive the next `Prompt` JSON. `--answer` is **required**; use `--no-submit` to peek at the next prompt without submitting a response. `render-args` returns the final `render-bundle` argument map, and `confirmation` returns the user echo block. On a completed wizard, `outcome` returns `renderArgs`, `persistActions`, and `confirmationText` together; project/global release-handoff PR-template persistence appears as `persistActions[].command == "config.set"`. For an `implementation` task type, `stage_pick` follows `approved_plan_pick` and selects the stage before `executor_pick`. The brief step appears only for entry task types—requirements-discovery, error-analysis, and
|
|
737
|
+
| `okstra wizard <init\|step\|render-args\|confirmation\|outcome> --state-file <path>` | Interactive input state machine for okstra-run, implemented by `okstra_ctl.wizard`. Seed a state file with `init`, then repeatedly call `step --answer <val>` to receive the next `Prompt` JSON. `--answer` is **required**; use `--no-submit` to peek at the next prompt without submitting a response. A `pick` with more choices than the host picker can display keeps `kind: "pick"` but adds `presentation: "numbered-text"`; render every option as a numbered Markdown list and submit the user's 1-based number, exact value, or exact label. Invalid, out-of-range, and ambiguous answers re-prompt without dropping choices. `render-args` returns the final `render-bundle` argument map, and `confirmation` returns the user echo block. On a completed wizard, `outcome` returns `renderArgs`, `persistActions`, and `confirmationText` together; project/global release-handoff PR-template persistence appears as `persistActions[].command == "config.set"`. For an `implementation` task type, `stage_pick` follows `approved_plan_pick` and selects the stage before `executor_pick`. The brief step appears only for entry task types—requirements-discovery, error-analysis, improvement-discovery, project-analysis, feature-analysis, and change-impact-analysis. Analysis inputs use `feature_evidence_pick` / `feature_evidence`, `project_evidence_pick` / `project_evidence`, and `analysis_target_pick` / `analysis_target`; a revision-requested report prioritizes its same-task, same-type rerun. Downstream lifecycle phases automatically carry the manifest brief, with a three-option `brief_carry` fallback when none is registered; `release-handoff` has no brief and enters multi-select `handoff_stage_pick` for eligible stage groups or the whole task |
|
|
691
738
|
| `okstra token-usage ...` | Wrap the installed `okstra-token-usage.py` to collect and substitute run token usage. Session JSONL is incrementally scanned by default through a byte-cursor cache at `$OKSTRA_HOME/cache/token-usage/`; `--no-cache` bypasses the cache and forces a full rescan as an accuracy fallback |
|
|
692
739
|
|
|
693
740
|
The convergence state lifecycle is `groups v1.0 → work v1.0 → final v1.3`; round-plan, round-results, and optional critic-results v1.0 artifacts provide the auditable transitions between those endpoints.
|
|
@@ -734,4 +781,4 @@ Both `wait_for_input` and `replan` stop before a stage worktree is provisioned a
|
|
|
734
781
|
|
|
735
782
|
### Live-log sidecar
|
|
736
783
|
|
|
737
|
-
For every dispatch, the Codex and Antigravity wrappers create a `runs/<task-type>/prompts/<worker>-prompt-<phase>-<seq>.log` sidecar and mirror stdout and stderr into it. When the lead runs inside tmux, the wrapper automatically splits a `tail -F` pane. The trace pane title is `<cli>-<role>-<pid>-tail`, and the caller/worker pane title is `<cli>-<role>-<pid>`; the wrapper PID distinguishes concurrent dispatches with the same role. Split trace panes are tagged with the `@okstra_trace_run=<RUN_DIR>` pane user option, and tmux-pane backend worker-compute panes with `@okstra_worker_run=<RUN_DIR>`. When Claude receives `/exit`, the `SessionEnd` hook automatically cleans them up within `$CLAUDE_PROJECT_DIR/.okstra/` scope by running `okstra-trace-cleanup.sh --reap`. When the lead calls the same script with `--run-dir <RUN_DIR>`, it removes the run's trace panes, worker-compute panes, and dispatched worker-agent panes within the lead-session scope, while excluding the lead's own pane. Worker-agent titles include `claude-worker`, `codex-worker`, `antigravity-worker`, `report-writer-worker`, implementation role titles, and FleetView teammate prefixes `✳ ` / `⠂ `.
|
|
784
|
+
For every dispatch, the Codex and Antigravity wrappers create a `runs/<task-type>/prompts/<worker>-prompt-<phase>-<seq>.log` sidecar and mirror stdout and stderr into it. When the lead runs inside tmux, the wrapper automatically splits a `tail -F` pane. The trace pane title is `<cli>-<role>-<pid>-tail`, and the caller/worker pane title is `<cli>-<role>-<pid>`; the wrapper PID distinguishes concurrent dispatches with the same role. Split trace panes are tagged with the `@okstra_trace_run=<RUN_DIR>` pane user option, and tmux-pane backend worker-compute panes with `@okstra_worker_run=<RUN_DIR>`. When Claude receives `/exit`, the `SessionEnd` hook automatically cleans them up within `$CLAUDE_PROJECT_DIR/.okstra/` scope by running `okstra-trace-cleanup.sh --reap`. When the lead calls the same script with `--run-dir <RUN_DIR>`, it removes the run's trace panes, worker-compute panes, and dispatched worker-agent panes within the lead-session scope, while excluding the lead's own pane. Worker-agent titles include `claude-worker`, `codex-worker`, `antigravity-worker`, `report-writer-worker`, implementation role titles, and FleetView teammate prefixes `✳ ` / `⠂ `. The lead runs `okstra-trace-cleanup.sh --run-dir <RUN_DIR>` at every worker round boundary — after collecting that round's results and before the next dispatch, not once per phase — to reclaim the completed panes. `--keep <substr>` (repeatable) excludes panes whose title contains the substring, which is how an in-flight report writer is preserved (`--keep report-writer-worker`), and `--list` prints the same set without killing so the lead can count what it is about to reclaim.
|
|
@@ -145,7 +145,7 @@ Runtime/install asset changes follow this checklist:
|
|
|
145
145
|
|
|
146
146
|
`--link <repo>` mode is for development and symlinks installed files back to repo sources.
|
|
147
147
|
|
|
148
|
-
`src/lib/runtime-resolver.mjs` is the single reference point for runtime auto-detection. `okstra install` defaults to `--runtime auto`, records the request and any successful resolution in `installed-runtimes.json` schemaVersion 2, and still copies the shared runtime payload from the installed package `runtime/` tree even when host detection is unavailable. Skill targets always include the default Agent-compatible `~/.agents/skills` target, with `~/.claude/skills` also populated when `~/.claude` exists. Dynamic capabilities such as `tmux` and `codex` CLI availability are checked by `doctor` and `run`, not frozen into the install manifest. Claude Code skills pass explicit `--runtime claude-code` / `--lead-runtime claude-code` so they never depend on host auto-detection.
|
|
148
|
+
`src/lib/runtime-resolver.mjs` is the single reference point for runtime auto-detection. `src/lib/runtime-readiness.mjs` owns host-specific pre-dispatch readiness behind one provider-neutral result shape; its Claude Code adapter checks project workspace trust, while Codex and external hosts do not inspect Claude state. `okstra install` defaults to `--runtime auto`, records the request and any successful resolution in `installed-runtimes.json` schemaVersion 2, and still copies the shared runtime payload from the installed package `runtime/` tree even when host detection is unavailable. Skill targets always include the default Agent-compatible `~/.agents/skills` target, with `~/.claude/skills` also populated when `~/.claude` exists. Dynamic capabilities such as `tmux` and `codex` CLI availability are checked by `doctor` and `run`, not frozen into the install manifest. Claude Code skills pass explicit `--runtime claude-code` / `--lead-runtime claude-code` so they never depend on host auto-detection.
|
|
149
149
|
|
|
150
150
|
---
|
|
151
151
|
|
|
@@ -165,13 +165,12 @@ Runtime/install asset changes follow this checklist:
|
|
|
165
165
|
| `doctor` | `src/commands/lifecycle/doctor.mjs` | Diagnose runtime and Python imports |
|
|
166
166
|
| `setup` | `src/commands/lifecycle/setup.mjs` | Create/update `<PROJECT_ROOT>/.okstra/project.json` |
|
|
167
167
|
| `check-project` | `src/commands/lifecycle/check-project.mjs` | Verify project registration |
|
|
168
|
-
| `preflight` | `src/commands/lifecycle/preflight.mjs` | One-call skill preflight: ensure-installed + check-project (single JSON) |
|
|
168
|
+
| `preflight` | `src/commands/lifecycle/preflight.mjs` | One-call skill preflight: ensure-installed + check-project + host-specific runtime readiness (single JSON) |
|
|
169
169
|
| `config` | `src/commands/lifecycle/config.mjs` | Read/write project/global settings such as PR template path |
|
|
170
170
|
| `migrate` | `src/commands/lifecycle/migrate.mjs` | One-shot legacy `.project-docs/okstra` → `.okstra` migration helper |
|
|
171
171
|
| `git-reconcile` | `src/commands/execute/git-reconcile.mjs` | Reconcile stale stage SHAs after external git history changes |
|
|
172
172
|
| `handoff` | `src/commands/execute/handoff.mjs` | Stage-group release-handoff eligibility / assemble / record helpers |
|
|
173
173
|
| `integrate-stages` | `src/commands/execute/integrate-stages.mjs` | Merge verified stages into the task worktree and clean stage worktrees |
|
|
174
|
-
| `phase-cleanup` | `src/commands/execute/phase-cleanup.mjs` | Reclaim the prior phase/batch's completed panes and teammates before the next phase starts; tmux-aware, and it preserves the lead pane and in-flight workers (Python: `okstra_ctl.phase_cleanup`) |
|
|
175
174
|
| `task-list`, `task-show` | `src/commands/inspect/task-list.mjs`, `src/commands/inspect/task-show.mjs` | Task/run introspection for skills; `task-show` consumes the Python task read-side snapshot |
|
|
176
175
|
| `resolve-task-key` | `src/commands/inspect/resolve-task-key.mjs` | Resolve a bare task-id to candidate task-keys from the project catalog |
|
|
177
176
|
| `set-work-status` | `src/commands/inspect/set-work-status.mjs` | Set a task's user-managed `workStatus` in task-manifest.json (Python: `okstra_ctl.set_work_status`) |
|
|
@@ -223,7 +222,7 @@ Top-level scripts:
|
|
|
223
222
|
| `okstra-render-report-views.py` | Render self-contained HTML views from final-report Markdown |
|
|
224
223
|
| `okstra-error-log.py` | Normalize worker/lead error sidecars |
|
|
225
224
|
| `okstra-spawn-followups.py` | Follow-up spawning helper |
|
|
226
|
-
| `okstra-trace-cleanup.sh` | tmux okstra pane cleanup (worker-agent + trace, excluding the lead pane); the `--reclaim-completed` mode reclaims only trace panes whose `@okstra_status` is terminated (stage=exited) and preserves in-progress panes |
|
|
225
|
+
| `okstra-trace-cleanup.sh` | tmux okstra pane cleanup (worker-agent + trace, excluding the lead pane), called by the lead at every worker round boundary — not once per phase; `--keep <substr>` (repeatable) spares panes whose title contains the substring, which is how an in-flight `report-writer-worker` survives a boundary; `--list` prints what would be reclaimed without killing; the `--reclaim-completed` mode reclaims only trace panes whose `@okstra_status` is terminated (stage=exited) and preserves in-progress panes |
|
|
227
226
|
| `okstra-subagent-reclaim.sh` | entry that walks active runs and reclaims only completed trace panes (wired to the `SubagentStop`/`TaskCompleted` hooks) |
|
|
228
227
|
|
|
229
228
|
### 4.3 `scripts/okstra_ctl/` — Python orchestration core
|
|
@@ -269,7 +268,6 @@ Important modules:
|
|
|
269
268
|
| `run_index_row.py` | single reference point for creating / slimming / hydrating a `~/.okstra` run-index row — runId SSOT, preserves projectId raw |
|
|
270
269
|
| `error_report.py`, `error_log_core.py`, `error_zip.py` | backend for the okstra-inspect errors/error-zip facets — `error_log_core` is the read-only core that globs/parses/aggregates `errors-*.jsonl`, `error_report` renders the errors facet, and `error_zip` collects cross-project run directories, allowlist-anonymizes, aggregates clusters, and produces a zip |
|
|
271
270
|
| `worker_heartbeat.py`, `worker_liveness.py` | `worker_heartbeat` is the single definition of the `- PROGRESS:` heartbeat line shape and its 5-minute (+60s grace) cadence budget, shared by the Phase 7 audit (`validators/validate_session_conformance.py`) and the live probe; `worker_liveness` backs `okstra worker-liveness`, reporting a pending worker as `stalled` (heartbeat past the budget) or `did-not-launch` (no wrapper `.log`/`.status.json` past the launch grace) |
|
|
272
|
-
| `phase_cleanup.py` | backs `okstra phase-cleanup` — decides tmux vs in-process mode, resolves the prior run dir (explicit `--run-dir`, else the newest FLAT run for a `--task-key`), and sequences the existing `okstra-trace-cleanup.sh --reclaim-completed` and `okstra-team-reconcile.sh` primitives. It never re-implements pane kill or completion detection, and it degrades to "nothing to report" instead of propagating a helper failure, so cleanup cannot block the next phase |
|
|
273
271
|
| `log_report.py`, `time_report.py` | read-side backend for the okstra-inspect logs/time facets (`okstra log-report` pairs each wrapper transcript `.log` with its sibling prompt `.md` and reports both byte counts without changing legacy transcript-size fields; `okstra time-report` is per-task time aggregation) |
|
|
274
272
|
| `rollup.py` | read-side backend for the okstra-rollup skill — fans the catalog out per task-group (or the whole project) and deterministically aggregates each task's run count, elapsed time (raw ms), error count, and latest report path, plus group-level totals/status, category, and phase distribution. Reuses the `time_report`/`error_log_core` functions and delegates report-body synthesis to the skill |
|
|
275
273
|
| `usage_report.py` | Read-only okstra-usage backend — scans the whole current project's recent run timelines, defaults to 30 days, and returns task-type coverage, raw/billable tokens, known USD cost, CPU-sum and wall-clock milliseconds, unavailable reason counts, and unmatched pricing models |
|
|
@@ -293,6 +291,8 @@ Important modules:
|
|
|
293
291
|
| `dispatch_core.py` | Backend-neutral worker dispatch core — worker execution/collection logic shared by any lead runtime (Claude/Codex/external); gates selected initial prompts through the shared cross-task contract before launch |
|
|
294
292
|
| `codex_dispatch.py` | Codex lead CLI-worker dispatcher — the `okstra codex-dispatch` backend. Reads the run manifest to run the Codex-side supported worker subset, applies the same cross-task initial-prompt gate, and performs token-usage substitution, view render, follow-up, and validation |
|
|
295
293
|
| `analysis_packet.py` | assembles the compact analysis-worker input packet for a task run from worker-owned profile sections; report/lead procedure stays outside the packet |
|
|
294
|
+
| `analysis_inputs.py` | shared input boundary for `project-analysis`, `feature-analysis`, and `change-impact-analysis` — validates evidence-report identity and review status, enforces the type-to-type relation allowlist, computes `exact`/`stale` freshness, and resolves free-text or `PF-NNN` feature targets for both wizard and prepare paths |
|
|
295
|
+
| `user_response.py` | parses clarification/approval responses and the analysis-review sidecar; `parse_analysis_review` validates accepted, revision-requested, and rejected decisions plus their affected IDs and reason |
|
|
296
296
|
| `context_cost.py` | read-side context-cost estimator for a prepared okstra task bundle (the `okstra context-cost` backend) |
|
|
297
297
|
| `schema_excerpt.py` | generates a task-type-scoped excerpt of the final-report schema — a schema reduction to inject into the worker/lead prompt |
|
|
298
298
|
| `work_categories.py` | requirements-discovery work-category (domain) **SSOT** (`is_valid_category`) — the work-category allowlist is defined only here |
|
|
@@ -344,6 +344,7 @@ Token/cost accounting:
|
|
|
344
344
|
| `launch.template.md` | Lead prompt template rendered for each run |
|
|
345
345
|
| `profiles/_common-contract.md` | Shared phase contract |
|
|
346
346
|
| `profiles/<task-type>.md` | Phase profiles (single language — runtime always loads from `profiles/`, never a translated mirror) |
|
|
347
|
+
| `project-analysis.md`, `feature-analysis.md`, `change-impact-analysis.md` | Read-only sidetrack profiles for project mapping, one-feature behavior tracing, and proposed-change impact mapping |
|
|
347
348
|
| `wizard/prompts.ko.json` | Korean wizard prompt single source of truth |
|
|
348
349
|
|
|
349
350
|
### 4.7 `templates/`
|
|
@@ -353,6 +354,8 @@ Token/cost accounting:
|
|
|
353
354
|
| `templates/reports/final-report.template.md` | Jinja2 final-report Markdown template |
|
|
354
355
|
| `templates/reports/report.css`, `report.js` | Inline assets for self-contained HTML report view |
|
|
355
356
|
| `templates/reports/*.template.md` | Inputs, schedule, user-response, settings templates |
|
|
357
|
+
| `project-analysis-input.template.md`, `feature-analysis-input.template.md`, `change-impact-analysis-input.template.md` | Brief input templates for the three analysis sidetracks |
|
|
358
|
+
| `user-response.template.md`, `report.js` | Analysis Review sidecar block and the browser control that exports accept/revision/reject without changing the source report |
|
|
356
359
|
| `templates/project-docs/task-index.template.md` | Project task index template |
|
|
357
360
|
| `templates/worker-prompt-preamble.md` | Initial analysis audience procedure and output contract |
|
|
358
361
|
| `templates/implementation-worker-preamble.md` | Shared implementation executor/verifier procedure, including coding-preflight and worktree rules |
|
|
@@ -377,6 +380,7 @@ Optional (v1.0 backward-compatible) top-level keys:
|
|
|
377
380
|
| `validate-run.py` | Run/final-report contract validation |
|
|
378
381
|
| `validate-brief.py`, `validate-brief.sh` | Brief frontmatter/body contract validation |
|
|
379
382
|
| `validate-report-views.py` | HTML view validation (form-control placement / no external URLs / stale source digest / Response ID parity) |
|
|
383
|
+
| `validate_analysis_report.py` | Cross-field validation for the three read-only analysis reports: frozen target/evidence snapshots, current-code evidence, review-source identity, and exact affected-ID resolution coverage on revision reruns |
|
|
380
384
|
| `validate-schedule.py` | Schedule section/order/code validation |
|
|
381
385
|
| `validate-implementation-plan-stages.py` | enforces the Stage Map structure — checks the S1–S8 rules (`## 5.5 Stage Map` + `## 5.5.<i> Stage <i>` sections, ≤ 8 steps per stage, etc.) |
|
|
382
386
|
| `validate_improvement_report.py` | enforces the 11-item contract of the improvement-discovery final-report. Automatically invoked by `validate-run.py` when `task_type == "improvement-discovery"` |
|
|
@@ -455,11 +459,13 @@ they are not published user skills.
|
|
|
455
459
|
|
|
456
460
|
1. Resolve project root and verify/upsert `project.json`.
|
|
457
461
|
2. Resolve profile, required workers, model assignments, executor provider.
|
|
458
|
-
3.
|
|
462
|
+
3. Resolve task identity segments, work category, and the run sequence input needed for path allocation.
|
|
459
463
|
4. Provision or reuse the task-key worktree, or the selected implementation stage worktree for stage-isolated runs.
|
|
460
|
-
5.
|
|
461
|
-
6.
|
|
462
|
-
7.
|
|
464
|
+
5. For an analysis sidetrack, resolve the immutable source commit from the provisioned worktree's `HEAD`, then resolve evidence reports, freshness, and the feature target through `analysis_inputs.py`.
|
|
465
|
+
6. Compute task/run paths and persist run context under `runs/<task-type>/manifests/`.
|
|
466
|
+
7. Materialize `instruction-set/` files and lead prompt snapshot.
|
|
467
|
+
8. Persist run inputs, team state, task manifest, task index, run manifest, timeline, discovery pointers.
|
|
468
|
+
9. Record the run in `~/.okstra/{active,recent}.jsonl` and project index.
|
|
463
469
|
|
|
464
470
|
### 5.2 Worktree model
|
|
465
471
|
|
|
@@ -498,6 +504,8 @@ Current report pipeline:
|
|
|
498
504
|
6. Token usage substitution fills usage/cost cells.
|
|
499
505
|
7. `scripts/okstra-render-report-views.py` emits the self-contained `.html` view, and run validation checks the final artifacts.
|
|
500
506
|
|
|
507
|
+
For the three analysis sidetracks, the HTML view also exports an immutable-source `## ANALYSIS REVIEW` sidecar. A revision rerun carries that sidecar, reanalyzes the whole confirmed scope, and records one `analysisReviewResolution` row for every affected ID before `validate_analysis_report.py` accepts the result.
|
|
508
|
+
|
|
501
509
|
The Markdown is derived, not the authoring source. The schema is the contract.
|
|
502
510
|
|
|
503
511
|
---
|
|
@@ -581,6 +589,8 @@ Project-local `<PROJECT_ROOT>/.claude/settings.local.json` is provisioned as a s
|
|
|
581
589
|
| `final-verification` | Read-only acceptance verification | `release-handoff` if accepted |
|
|
582
590
|
| `release-handoff` | User-selected commit/PR handoff | done or follow-up |
|
|
583
591
|
|
|
592
|
+
The independent analysis sidetracks do not appear in this phase sequence. `project-analysis` maps the current project, `feature-analysis` traces one existing feature, and `change-impact-analysis` maps a proposed change's impact. Each returns to `pending-routing-decision` and remains read-only, including no test or build execution.
|
|
593
|
+
|
|
584
594
|
### 7.5 Report and follow-up
|
|
585
595
|
|
|
586
596
|
Final report artifacts live under `runs/<task-type>/reports/`. Human responses from the HTML view are saved as `runs/<task-type>/user-responses/user-response-<task-type>-<seq>.md` and can be carried into the next run.
|
package/package.json
CHANGED
package/runtime/BUILD.json
CHANGED
|
@@ -14,7 +14,7 @@ model: inherit
|
|
|
14
14
|
tools: ["Bash", "Read", "Write", "Edit", "Glob", "Grep", "TodoWrite", "WebFetch", "WebSearch"]
|
|
15
15
|
---
|
|
16
16
|
|
|
17
|
-
**Author the final-report data.json
|
|
17
|
+
**Author the three report completion artifacts**: the final-report data.json (the JSON SSOT) at the assigned `Result Path`, its rendered Markdown sibling, and the worker-result pointer at `Worker Result Path`. Maintain the separate heartbeat audit sidecar at `Audit sidecar path`. That is the `Report writer worker`'s sole responsibility for okstra cross-verification. You are NOT an analysis worker — you do not produce independent findings, you do not vote in convergence, and you do not re-do the workers' analysis.
|
|
18
18
|
|
|
19
19
|
- The `**Report Language:**` header in your dispatch prompt is already
|
|
20
20
|
resolved to `en` or `ko` by the lead. Copy it verbatim into
|
|
@@ -30,14 +30,13 @@ If you find yourself thinking "I'll just write the markdown directly" — stop.
|
|
|
30
30
|
|
|
31
31
|
## Worker Result File (MANDATORY)
|
|
32
32
|
|
|
33
|
-
Write the required worker-result record at the lead-registered `**Worker Result Path:**`.
|
|
33
|
+
Write the required worker-result record at the lead-registered `**Worker Result Path:**`. Both dispatch adapters include it in `WorkerJob.completion_paths` and refuse `completed` while it is absent. Schema: short YAML frontmatter (`workerId: "report-writer"`, plus the canonical fields copied verbatim from `analysis-material.md` per `team-contract`) followed by:
|
|
34
34
|
|
|
35
35
|
1. The canonical data.json path you wrote (project-relative).
|
|
36
36
|
2. The rendered markdown path produced by the renderer (project-relative).
|
|
37
|
-
3.
|
|
38
|
-
4. Any structural deviations from the `<instruction-set>/final-report-schema.json` excerpt and the reason.
|
|
37
|
+
3. The convergence-state input path from the prompt (project-relative).
|
|
39
38
|
|
|
40
|
-
|
|
39
|
+
Keep the data.json contents and analysis-worker result list out of this file: the data.json is the canonical artifact and the analysis results remain prompt inputs. This file is the dispatch-required three-path pointer record.
|
|
41
40
|
|
|
42
41
|
## Heartbeat (BLOCKING)
|
|
43
42
|
|
|
@@ -123,7 +122,7 @@ Rules (the schema enforces most of these — they are listed here so you know *w
|
|
|
123
122
|
- For `implementation-planning`, populate `implementationPlanning.variationPointAnalysis` — a `hasMultipleImplementations` judgement synthesized from the analysis workers' output, not a field filled in last. When it is `true`, write one `points[]` row per varying behavior carrying `behavior`, the two or more `implementations` that serve it, `evidence` (a `path:line`, or the sibling task / stage that already implements that behavior), and an `extractionDecision` of `extract` / `interfaceKind` / `coveredBy` (the Stage Map stage that builds the interface) / `rationale`; when it is `false`, write a non-empty `noVariationRationale` and leave `points` empty (the two branches are mutually exclusive). Do NOT pass a boilerplate rationale — `false` is the cheaper field to fill, and a `false` declaration the brief or the sibling code in the workers' evidence contradicts is a `P-Var` DISAGREE, not a saving. Also populate `implementationPlanning.recommendedOption.testSeams`: one row per boundary a test injects at and replaces, each carrying `boundary` / `injectedAs` / `replacedInTest`. An empty list is a conscious "no seam needed" claim, never a default for a field nobody filled. The schema excerpt enumerates both row shapes — author against it. (Maintainer SSOT for these two rules: the `Required deliverable shape` bullet in `prompts/profiles/implementation-planning.md` in the okstra repo; that path is not resolvable here, so it is provenance, not a file to open.) **Enforced:** `schemas/final-report-v1.0.schema.json` `$defs.VariationPointAnalysis` / `$defs.VariationPoint` (the block is in `implementationPlanning.required`) plus `testSeams` in `$defs.RecommendedOption`'s `required`; `validators/validate-run.py` `_validate_variation_point_analysis` rejects a rationale-less `false`, a `false` carrying points, a `true` with no point, an `extract: true` decision leaving `interfaceKind` or `coveredBy` empty, and a hexagonal project extracting as anything but a port; and every point becomes a `P-Var-*` plan item judged in §5.5.9.
|
|
124
123
|
- When the `Task Type` is `improvement-discovery`, populate `## 5.9 Improvement Candidates` with the 11-column schema enforced by `validators/validate_improvement_report.py`. The `Expected behavior after` cell states in one observable sentence what becomes different once the candidate is applied — it seeds the downstream brief's `EB-NNN` / `EO-NNN`, and an empty cell fails the run. Source the row IDs (`I-NNN`), lens whitelist, and Source workers patterns from `scripts/okstra_ctl/improvement_lenses.py` — do NOT introduce new lens names or worker prefixes. `improvement-discovery` is NOT in the data.json schema enum, so author its markdown directly (not via `okstra-render-final-report.py`). Immediately after writing the markdown, run (`Bash`): `okstra inject-report-index <markdown path> --report-language <en|ko>`. That adds the top-of-report Index plus `I-NNN` / `C-NNN` scroll anchors; the run validator fails the report when the Index anchor is absent.
|
|
125
124
|
|
|
126
|
-
Write the
|
|
125
|
+
Write the three completion artifacts and the separate audit sidecar with your `Write` tool — that is the canonical authoring path, and okstra ships no hook that blocks `.md` writes (its only settings hook is the `SessionEnd` trace-cleanup; the coding-preflight hook emits reminders but never blocks). A Bash heredoc is acceptable ONLY when a specific `Write` call is genuinely rejected by the host environment, and it MUST produce byte-identical content — do not reach for it pre-emptively. After writing data.json, invoke the renderer (`Bash`): `okstra render-final-report <data.json path>`, then write the Worker Result Path pointer. Confirm data.json, rendered Markdown, the pointer, and the audit sidecar exist before responding with a short status line prefixed by your model identity, per the preamble §"Return message to the lead". **Enforced:** dispatch `completionPaths` requires the first three files and `validators/validate_session_conformance.py` validates the audit sidecar.
|
|
127
126
|
|
|
128
127
|
```
|
|
129
128
|
**Model:** Report writer worker, <modelExecutionValue>
|
|
@@ -33,6 +33,10 @@
|
|
|
33
33
|
# `--list` (alias `--dry-run`) prints `<pane_id>\t<pane_title>` per pane instead
|
|
34
34
|
# of killing — only meaningful with `--run-dir`.
|
|
35
35
|
#
|
|
36
|
+
# `--keep <substr>` (repeatable) spares any pane whose current title contains
|
|
37
|
+
# <substr>, in both the kill and the list set. Used to preserve an in-flight
|
|
38
|
+
# report-writer at a round boundary.
|
|
39
|
+
#
|
|
36
40
|
# Failures are tolerated silently — a stale pane id, no tmux, or a locked tmux
|
|
37
41
|
# client must never prevent Claude from exiting cleanly.
|
|
38
42
|
|
|
@@ -57,6 +61,7 @@ MODE="kill" # kill | list
|
|
|
57
61
|
RECLAIM=0 # 1: trace pane 은 @okstra_status 가 완료(exited)일 때만 회수 (--reclaim-completed)
|
|
58
62
|
REAP=0
|
|
59
63
|
run_dir=""
|
|
64
|
+
KEEP_PATTERNS=() # --keep <substr>: panes whose title contains substr are spared from kill/list
|
|
60
65
|
while [[ $# -gt 0 ]]; do
|
|
61
66
|
case "$1" in
|
|
62
67
|
--list|--dry-run) MODE="list" ;;
|
|
@@ -64,13 +69,18 @@ while [[ $# -gt 0 ]]; do
|
|
|
64
69
|
--reap) REAP=1 ;;
|
|
65
70
|
--run-dir) shift; run_dir="${1-}" ;;
|
|
66
71
|
--run-dir=*) run_dir="${1#--run-dir=}" ;;
|
|
72
|
+
--keep) shift; KEEP_PATTERNS+=("${1-}") ;;
|
|
73
|
+
--keep=*) KEEP_PATTERNS+=("${1#--keep=}") ;;
|
|
67
74
|
-h|--help)
|
|
68
75
|
cat <<'USAGE'
|
|
69
|
-
usage: okstra-trace-cleanup.sh (--run-dir <RUN_DIR> [--list] [--reclaim-completed] | --reap)
|
|
76
|
+
usage: okstra-trace-cleanup.sh (--run-dir <RUN_DIR> [--list] [--reclaim-completed] [--keep <substr>]... | --reap)
|
|
70
77
|
|
|
71
78
|
--run-dir okstra run directory; closes that run's trace + worker-agent panes.
|
|
72
79
|
--list with --run-dir: print "<pane_id>\t<pane_title>" per pane; no kill.
|
|
73
80
|
--dry-run alias for --list.
|
|
81
|
+
--keep <substr> exclude any pane whose title contains <substr> from the
|
|
82
|
+
kill/list set (repeatable). Used to spare an in-flight
|
|
83
|
+
report-writer at a round boundary.
|
|
74
84
|
--reclaim-completed with --run-dir: restrict trace panes to those whose
|
|
75
85
|
@okstra_status sidecar is terminal (stage=exited); in-flight
|
|
76
86
|
and teammate panes are preserved. Skips the title-allowlist
|
|
@@ -149,6 +159,18 @@ _title_in_okstra_scope() {
|
|
|
149
159
|
return 1
|
|
150
160
|
}
|
|
151
161
|
|
|
162
|
+
# A collected pane whose current title contains any --keep substring is spared.
|
|
163
|
+
# Applied at the final emit so both the tag scan and the title scan honour it.
|
|
164
|
+
_keep_excluded() {
|
|
165
|
+
local pid="$1" title pat
|
|
166
|
+
(( ${#KEEP_PATTERNS[@]} )) || return 1
|
|
167
|
+
title=$(tmux display-message -p -t "$pid" '#{pane_title}' 2>/dev/null || true)
|
|
168
|
+
for pat in "${KEEP_PATTERNS[@]}"; do
|
|
169
|
+
[[ -n "$pat" && "$title" == *"$pat"* ]] && return 0
|
|
170
|
+
done
|
|
171
|
+
return 1
|
|
172
|
+
}
|
|
173
|
+
|
|
152
174
|
collect_okstra_panes() {
|
|
153
175
|
local -a panes=()
|
|
154
176
|
local pid trace_tag worker_tag status_tag title
|
|
@@ -195,8 +217,12 @@ collect_okstra_panes() {
|
|
|
195
217
|
fi
|
|
196
218
|
|
|
197
219
|
# Dedupe — a live trace pane can match both the tag scan and the title scan.
|
|
220
|
+
# Then drop any pane a --keep pattern spares (in-flight report-writer).
|
|
198
221
|
if (( ${#panes[@]} )); then
|
|
199
|
-
printf '%s\n' "${panes[@]}" | awk 'NF && !seen[$0]++'
|
|
222
|
+
printf '%s\n' "${panes[@]}" | awk 'NF && !seen[$0]++' | while IFS= read -r _pid; do
|
|
223
|
+
_keep_excluded "$_pid" && continue
|
|
224
|
+
printf '%s\n' "$_pid"
|
|
225
|
+
done
|
|
200
226
|
fi
|
|
201
227
|
}
|
|
202
228
|
|