okstra 0.163.2 → 0.165.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 +8 -6
- package/docs/architecture.md +24 -15
- package/docs/cli.md +15 -8
- package/docs/for-ai/README.md +2 -2
- package/docs/for-ai/skills/okstra-inspect.md +2 -2
- package/docs/for-ai/skills/okstra-user-response.md +2 -2
- package/docs/project-structure-overview.md +22 -14
- package/package.json +1 -1
- package/runtime/BUILD.json +2 -2
- package/runtime/agents/workers/antigravity-worker.md +9 -7
- package/runtime/agents/workers/claude-worker.md +1 -0
- package/runtime/agents/workers/codex-worker.md +9 -7
- package/runtime/agents/workers/grok-worker.md +6 -4
- package/runtime/agents/workers/kimi-worker.md +6 -4
- package/runtime/bin/lib/okstra/cli.sh +5 -0
- package/runtime/bin/lib/okstra/globals.sh +2 -0
- package/runtime/bin/lib/okstra/usage.sh +5 -5
- package/runtime/bin/okstra-antigravity-exec.sh +1 -340
- package/runtime/bin/okstra-claude-exec.sh +1 -178
- package/runtime/bin/okstra-codex-exec.sh +1 -467
- package/runtime/bin/okstra-provider-exec.py +165 -190
- package/runtime/bin/okstra-trace-cleanup.sh +14 -7
- package/runtime/bin/okstra-wrapper-status.py +26 -19
- package/runtime/bin/okstra.sh +87 -91
- package/runtime/prompts/lead/adapters/cmux.md +2 -2
- package/runtime/prompts/lead/convergence.md +36 -8
- package/runtime/prompts/lead/okstra-lead-contract.md +24 -1
- package/runtime/prompts/lead/plan-body-verification.md +9 -1
- package/runtime/prompts/lead/report-writer.md +1 -0
- package/runtime/prompts/lead/team-contract.md +3 -3
- package/runtime/prompts/profiles/_common-contract.md +9 -1
- package/runtime/prompts/profiles/_coverage-critic.md +1 -1
- package/runtime/prompts/profiles/_implementation-diff-review.md +3 -1
- package/runtime/prompts/profiles/_implementation-self-check.md +1 -1
- package/runtime/prompts/profiles/_implementation-verifier.md +3 -1
- package/runtime/prompts/profiles/implementation-planning.md +6 -4
- package/runtime/python/okstra_ctl/adapters/accounting/__init__.py +11 -0
- package/runtime/python/okstra_ctl/adapters/accounting/claude_jsonl.py +17 -0
- package/runtime/python/okstra_ctl/adapters/accounting/cli_artifact.py +17 -0
- package/runtime/python/okstra_ctl/adapters/accounting/unavailable.py +19 -0
- package/runtime/python/okstra_ctl/adapters/dispatch/__init__.py +92 -0
- package/runtime/python/okstra_ctl/adapters/dispatch/cli_wrapper.py +54 -0
- package/runtime/python/okstra_ctl/adapters/dispatch/cmux.py +68 -0
- package/runtime/python/okstra_ctl/adapters/dispatch/native_team.py +13 -0
- package/runtime/python/okstra_ctl/adapters/hosts/antigravity/adapter.py +60 -0
- package/runtime/python/okstra_ctl/adapters/hosts/antigravity/manifest.json +1 -0
- package/runtime/{prompts/lead/adapters/antigravity.md → python/okstra_ctl/adapters/hosts/antigravity/relay.md} +52 -0
- package/runtime/python/okstra_ctl/adapters/hosts/capability_adapter.py +292 -0
- package/runtime/python/okstra_ctl/adapters/hosts/claude-code/adapter.py +120 -0
- package/runtime/python/okstra_ctl/adapters/hosts/claude-code/manifest.json +1 -0
- package/runtime/{prompts/lead/adapters/claude-code.md → python/okstra_ctl/adapters/hosts/claude-code/relay.md} +112 -1
- package/runtime/python/okstra_ctl/adapters/hosts/codex/adapter.py +60 -0
- package/runtime/python/okstra_ctl/adapters/hosts/codex/manifest.json +1 -0
- package/runtime/{prompts/lead/adapters/codex.md → python/okstra_ctl/adapters/hosts/codex/relay.md} +52 -0
- package/runtime/python/okstra_ctl/adapters/hosts/external/adapter.py +72 -0
- package/runtime/python/okstra_ctl/adapters/hosts/external/manifest.json +1 -0
- package/runtime/{prompts/lead/adapters/external.md → python/okstra_ctl/adapters/hosts/external/relay.md} +53 -1
- package/runtime/python/okstra_ctl/adapters/hosts/grok/adapter.py +63 -0
- package/runtime/python/okstra_ctl/adapters/hosts/grok/manifest.json +1 -0
- package/runtime/python/okstra_ctl/adapters/hosts/grok/relay.md +90 -0
- package/runtime/python/okstra_ctl/adapters/hosts/kimi/adapter.py +63 -0
- package/runtime/python/okstra_ctl/adapters/hosts/kimi/manifest.json +1 -0
- package/runtime/python/okstra_ctl/adapters/hosts/kimi/relay.md +90 -0
- package/runtime/python/okstra_ctl/adapters/providers/antigravity/adapter.py +183 -0
- package/runtime/python/okstra_ctl/adapters/providers/antigravity/manifest.json +1 -0
- package/runtime/python/okstra_ctl/adapters/providers/claude/adapter.py +110 -0
- package/runtime/python/okstra_ctl/adapters/providers/claude/manifest.json +1 -0
- package/runtime/python/okstra_ctl/adapters/providers/codex/adapter.py +84 -0
- package/runtime/python/okstra_ctl/adapters/providers/codex/manifest.json +1 -0
- package/runtime/python/okstra_ctl/adapters/providers/grok/adapter.py +76 -0
- package/runtime/python/okstra_ctl/adapters/providers/grok/manifest.json +1 -0
- package/runtime/python/okstra_ctl/adapters/providers/kimi/adapter.py +80 -0
- package/runtime/python/okstra_ctl/adapters/providers/kimi/manifest.json +1 -0
- package/runtime/python/okstra_ctl/application/__init__.py +1 -0
- package/runtime/python/okstra_ctl/application/advance_wizard.py +25 -0
- package/runtime/python/okstra_ctl/application/collect_usage.py +15 -0
- package/runtime/python/okstra_ctl/application/dispatch_assignments.py +15 -0
- package/runtime/python/okstra_ctl/application/resolve_assignment.py +93 -0
- package/runtime/python/okstra_ctl/application/resume_run.py +21 -0
- package/runtime/python/okstra_ctl/application/start_run.py +21 -0
- package/runtime/python/okstra_ctl/codex_dispatch.py +49 -826
- package/runtime/python/okstra_ctl/dispatch_core.py +244 -29
- package/runtime/python/okstra_ctl/dispatch_state.py +27 -0
- package/runtime/python/okstra_ctl/domain/__init__.py +34 -0
- package/runtime/python/okstra_ctl/domain/host.py +100 -0
- package/runtime/python/okstra_ctl/domain/provider.py +70 -0
- package/runtime/python/okstra_ctl/domain/wizard/__init__.py +19 -0
- package/runtime/python/okstra_ctl/domain/wizard/interaction.py +140 -0
- package/runtime/python/okstra_ctl/domain/worker_exec.py +102 -0
- package/runtime/python/okstra_ctl/domain/worker_role.py +34 -0
- package/runtime/python/okstra_ctl/domain/worker_stream.py +261 -0
- package/runtime/python/okstra_ctl/entrypoints/__init__.py +1 -0
- package/runtime/python/okstra_ctl/entrypoints/hosts.py +334 -0
- package/runtime/python/okstra_ctl/incremental_scope.py +16 -4
- package/runtime/python/okstra_ctl/models.py +54 -269
- package/runtime/python/okstra_ctl/ports/__init__.py +15 -0
- package/runtime/python/okstra_ctl/ports/host.py +32 -0
- package/runtime/python/okstra_ctl/ports/interaction.py +15 -0
- package/runtime/python/okstra_ctl/ports/lead_session.py +25 -0
- package/runtime/python/okstra_ctl/ports/usage_accounting.py +23 -0
- package/runtime/python/okstra_ctl/ports/worker_dispatch.py +32 -0
- package/runtime/python/okstra_ctl/registry/__init__.py +13 -0
- package/runtime/python/okstra_ctl/registry/factory_loader.py +32 -0
- package/runtime/python/okstra_ctl/registry/host_discovery.py +124 -0
- package/runtime/python/okstra_ctl/registry/host_registry.py +365 -0
- package/runtime/python/okstra_ctl/registry/provider_registry.py +149 -0
- package/runtime/python/okstra_ctl/render.py +145 -47
- package/runtime/python/okstra_ctl/report_html/common.py +71 -25
- package/runtime/python/okstra_ctl/report_html/models.py +5 -0
- package/runtime/python/okstra_ctl/report_html/render.py +1 -1
- package/runtime/python/okstra_ctl/report_html/run_usage.py +19 -0
- package/runtime/python/okstra_ctl/report_html/view_models/implementation_planning.py +14 -0
- package/runtime/python/okstra_ctl/report_views.py +44 -16
- package/runtime/python/okstra_ctl/run.py +80 -58
- package/runtime/python/okstra_ctl/session.py +1 -1
- package/runtime/python/okstra_ctl/stage_citations.py +52 -15
- package/runtime/python/okstra_ctl/team.py +44 -32
- package/runtime/python/okstra_ctl/user_response.py +45 -29
- package/runtime/python/okstra_ctl/wizard.py +175 -73
- package/runtime/python/okstra_ctl/worker_audit_ledger.py +29 -4
- package/runtime/python/okstra_ctl/worker_prompt_policy.py +10 -3
- package/runtime/python/okstra_ctl/worker_request.py +140 -0
- package/runtime/python/okstra_ctl/worker_runner.py +622 -0
- package/runtime/python/okstra_token_usage/collect.py +42 -7
- package/runtime/python/okstra_token_usage/report.py +42 -0
- package/runtime/python/okstra_token_usage/task_totals.py +88 -0
- package/runtime/schemas/final-report-v1.0.schema.json +4040 -1066
- package/runtime/schemas/final-report-v2.0.schema.json +5673 -1412
- package/runtime/skills/okstra-inspect/SKILL.md +1 -2
- package/runtime/skills/okstra-inspect/facets/logs.md +5 -5
- package/runtime/skills/okstra-inspect/facets/run-audit.md +3 -3
- package/runtime/skills/okstra-run/SKILL.md +74 -29
- package/runtime/skills/okstra-user-response/SKILL.md +15 -5
- package/runtime/templates/implementation-worker-preamble.md +1 -1
- package/runtime/templates/report-writer-prompt-preamble.md +1 -0
- package/runtime/templates/reports/final-report.template.md +3 -3
- package/runtime/templates/reports/html/assets/base.css +8 -4
- package/runtime/templates/reports/html/base.template.html +12 -6
- package/runtime/templates/reports/html/i18n/en.json +32 -7
- package/runtime/templates/reports/html/i18n/ko.json +32 -7
- package/runtime/templates/reports/html/macros/forms.html +9 -3
- package/runtime/templates/reports/html/tasks/implementation-planning.template.html +14 -19
- package/runtime/templates/reports/report.js +59 -26
- package/runtime/templates/reports/user-response.template.md +12 -8
- package/runtime/templates/worker-prompt-preamble.md +1 -1
- package/runtime/validators/validate-implementation-plan-stages.py +17 -22
- package/runtime/validators/validate-report-views.py +0 -39
- package/runtime/validators/validate-run.py +96 -14
- package/runtime/validators/validate_session_conformance.py +69 -3
- package/src/cli-registry.mjs +0 -7
- package/src/commands/execute/render-bundle.mjs +4 -4
- package/src/commands/execute/run.mjs +8 -25
- package/src/commands/execute/wizard.mjs +33 -13
- package/src/commands/lifecycle/doctor.mjs +10 -10
- package/src/commands/lifecycle/install.mjs +53 -30
- package/src/commands/lifecycle/preflight.mjs +14 -4
- package/src/lib/host-registry-client.mjs +176 -0
- package/src/lib/runtime-manifest.mjs +6 -8
- package/runtime/bin/okstra-wrapper-agy-stream.py +0 -61
- package/runtime/python/okstra_ctl/error_issue.py +0 -640
- package/runtime/python/okstra_ctl/issue_signals.py +0 -186
- package/runtime/python/okstra_ctl/lead_runtime.py +0 -115
- package/runtime/python/okstra_ctl/runner_resolution.py +0 -103
- package/runtime/skills/okstra-inspect/facets/error-issue.md +0 -77
- package/src/commands/inspect/error-issue.mjs +0 -27
- package/src/lib/runtime-readiness.mjs +0 -90
- package/src/lib/runtime-resolver.mjs +0 -123
package/README.md
CHANGED
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
<a id="purpose"></a>
|
|
21
21
|
## 1. Purpose
|
|
22
22
|
|
|
23
|
-
`okstra` is a **host-aware, multi-provider task runner that cross-verifies work with a lead + worker model**.
|
|
23
|
+
`okstra` is a **host-aware, multi-provider task runner that cross-verifies work with a lead + worker model**. A registered host adapter supplies the lead session, while a separate provider adapter supplies models and worker execution. Claude remains the compatibility default policy, not the owner of the lifecycle.
|
|
24
24
|
|
|
25
25
|
The design rests on three principles:
|
|
26
26
|
|
|
@@ -35,10 +35,12 @@ Role assignments are persisted separately from the host runtime, but the lead pr
|
|
|
35
35
|
| Claude | Claude Code | `okstra-claude-exec.sh` | lead, analysis, implementation, report writer |
|
|
36
36
|
| Codex | Codex | `okstra-codex-exec.sh` | lead, analysis, implementation, report writer |
|
|
37
37
|
| Antigravity | Antigravity CLI | `okstra-antigravity-exec.sh` | lead, analysis, and implementation |
|
|
38
|
-
| Grok |
|
|
39
|
-
| Kimi |
|
|
38
|
+
| Grok | Grok CLI | `okstra-grok-exec.sh` | lead, read-only analyser, and critic |
|
|
39
|
+
| Kimi | Kimi CLI | `okstra-kimi-exec.sh` | lead, read-only analyser, and critic |
|
|
40
40
|
|
|
41
|
-
Grok and Kimi
|
|
41
|
+
Grok and Kimi can now lead through their registered host adapters. Their worker roles remain read-only analyser and critic; executor, verifier, and report-writer roles were not added. A real authenticated local invocation still depends on the corresponding CLI being installed and configured.
|
|
42
|
+
|
|
43
|
+
`okstra run <host-id-or-alias>` resolves the requested adapter from the host registry and checks its `spawn-process` readiness before starting it. The installed `okstra-run` skill instead uses `current-session`: it declares only the semantic functions the live harness can actually perform (`plain_text_input`, plus any available native single-select, multi-select, or grouped-question function) and reuses the current lead session. User-installed adapters are discovered only from `~/.okstra/adapters/hosts/<id>/` and `~/.okstra/adapters/providers/<id>/`; project-local executable adapter code is ignored.
|
|
42
44
|
|
|
43
45
|
The next direct-CLI candidates are Mistral Vibe and Qwen Code. DeepSeek V4, GLM-5.2, and MiniMax M2.7 remain API-adapter candidates because their current official coding-agent execution surfaces do not fit Okstra's wrapper contract as directly. Newly published provider models are exposed only after the corresponding local CLI reports them; this keeps model discovery separate from marketing availability.
|
|
44
46
|
|
|
@@ -181,7 +183,7 @@ Use these slash commands inside a Claude Code session:
|
|
|
181
183
|
| `/okstra-brief-gen` | Convert a ticket, requirements document, link, or conversation into an `okstra-run` task brief |
|
|
182
184
|
| `/okstra-run` | Start a new task or continue an existing task's next phase |
|
|
183
185
|
| `/okstra-memory` | Store, search, and archive global conversation memory in `~/.okstra/memory-book` |
|
|
184
|
-
| `/okstra-inspect` | Unified read side. Subcommands: `status` (phase/state and workStatus updates), `history` (past tasks, reruns, resumes), `report` (find/read final reports), `time` (elapsed-time breakdown), `logs` (wrapper log sidecar inventory and cleanup suggestions), `cost` (task bundle context/read cost), `errors` (aggregate run error logs into a report), `error-zip` (collect cross-project error logs into an anonymized zip and summarize clusters), `run-audit` (check every run's artifacts against progress invariants, catching runs that ended wrong without ever logging a failure),
|
|
186
|
+
| `/okstra-inspect` | Unified read side. Subcommands: `status` (phase/state and workStatus updates), `history` (past tasks, reruns, resumes), `report` (find/read final reports), `time` (elapsed-time breakdown), `logs` (wrapper log sidecar inventory and cleanup suggestions), `cost` (task bundle context/read cost), `errors` (aggregate run error logs into a report), `error-zip` (collect cross-project error logs into an anonymized zip and summarize clusters), `run-audit` (check every run's artifacts against progress invariants, catching runs that ended wrong without ever logging a failure), and `recap` (run-to-run before/after summary plus free-form Q&A over a task's `.okstra` artifacts) |
|
|
185
187
|
| `/okstra-rollup` | Aggregate every task run in a task group or project, including per-task run counts, duration, errors, group totals, and a cross-task report digest |
|
|
186
188
|
| `/okstra-usage` | Show the current project's recent run coverage, raw and billable-equivalent tokens, known USD cost, CPU time, and wall-clock time grouped by task type (default: last 30 days) |
|
|
187
189
|
| `/okstra-schedule-gen` | Invoke as `/okstra-schedule-gen [task-group]` to generate a work schedule for an entire task group. Each non-done task is resolved through the source-aware `stage-map` response; your unfinished-stage choices are captured in a temporary selection contract, and only the same draft that passes deterministic selection validation followed by independent narrative verification is published |
|
|
@@ -225,7 +227,7 @@ Major workflow changes added to `main` after 0.8.0:
|
|
|
225
227
|
- **`release-handoff` lifecycle phase** — runs immediately after `final-verification` returns `verdict=accepted`. The current Okstra lead drafts the candidate messages and PR body inline, then uses the selected host adapter's user-prompt operation for the delivery choices. Only the Git/GitHub CLI commands selected through those menus are run. Force pushes, direct pushes to the base branch, hook bypasses (`--no-verify`), and release publication (`gh release`, `npm publish`, and similar commands) are prohibited. This phase does not edit source code. Profile: [`prompts/profiles/release-handoff.md`](prompts/profiles/release-handoff.md).
|
|
226
228
|
- **Configurable PR body template** (release-handoff) — PR bodies are populated from a Markdown template selected in this order: one-time override (`--pr-template-path` or the okstra-run Step 6 prompt) → `prTemplatePath` in `<project_root>/.okstra/project.json` → `prTemplatePath` in `~/.okstra/config.json` → the skill default at `~/.claude/skills/templates/prd/pr-body.template.md`. Register a template with `okstra config set pr-template-path <path> [--scope project|global]`; project scope accepts a path relative to the project root, while global scope requires an absolute path or a path beginning with `~/`. `okstra config get pr-template-path --scope all` prints every scoped value and the effective winner. The default template contains `## Summary`, `## Changes`, `## Test plan`, and `## Linked issues`, plus HTML comment guidance that the lead removes immediately before PR creation.
|
|
227
229
|
- **Profile worker-roster validation** — `--workers <csv>` and the okstra-run Step 6 worker prompt accept only the worker IDs declared in the selected profile's `Required workers:` block. Requesting a worker absent from the profile—for example, `codex` or `antigravity` for `release-handoff`—fails with a clear error, and the interactive prompt shows only workers accepted by that profile.
|
|
228
|
-
- **Host-aware lead adapters** —
|
|
230
|
+
- **Host-aware lead adapters** — `okstra-run` resolves the current harness through the same dynamic host registry used by the terminal front door. Claude Code, Codex, Antigravity, Grok, and Kimi keep their matching provider assignment native; `external` remains the explicit all-CLI host. Host and provider are separate axes, and every non-native worker assignment uses its provider's registered CLI wrapper. `leadAssignment` and every `workerAssignments[]` row record provider, model, and `runner`. `okstra codex-run` and `okstra codex-dispatch` remain low-level artifact/dispatch commands.
|
|
229
231
|
- **Multi-stage `implementation-planning` / `implementation`** — `implementation-planning` always produces a Stage Map and N stage sections. Each stage has no more than six steps, and stages with `depends-on (none)` can be implemented concurrently in separate `implementation` runs. Each `implementation` invocation runs a single stage, selected with `--stage <auto|N>`, and creates an evidence sidecar at `carry/stage-<N>.json` for automatic carry-in to the next stage. The `implementation-planning` run directory accumulates `consumers.jsonl` reverse links that record which run consumed each stage.
|
|
230
232
|
- **AI-prepared design preparation (implementation-planning → implementation)** — `implementation-planning` detects which stages need design input (domain contract, DB/table schema, external interface, transaction/consistency, transformation mapping, lifecycle, rollout/observability, manual user test) and has the AI draft a concrete proposal first, instead of handing the user an empty design document. Each item is assessed as `ready`, `provisional`, `blocked`, or `not-applicable`; a simple task may declare `no-design-inputs`. Phase 7 materializes an Okstra-owned request under `design-prep-requests/`, and `okstra design-prep <list|show|write>` or the okstra-run wizard records the confirmed answer as an **append-only** revision under `design-prep-inputs/`—neither path ever edits the approved planning snapshot. Before creating its worktree, `implementation` resolves only the items its selected stage cites in `stageRefs`: safe `provisional` assumptions are injected into the executor prompt so work proceeds, while an unsafe open decision makes only that stage wait or replan. A markerless legacy plan continues with a `legacy-unassessed` warning. Storage authorities: [`docs/architecture/storage-model.md`](docs/architecture/storage-model.md). CLI: [`docs/cli.md#okstra-design-prep`](docs/cli.md#okstra-design-prep).
|
|
231
233
|
- **Phase 6 plan-body verification (implementation-planning only)** — Immediately after the report-writer worker drafts the final report and before the user approval gate, the lead performs one post-verification round. It extracts `P-Opt-*`, `P-Step-*`, `P-Dep-*`, `P-Val-*`, and `P-Rb-*` plan items from the synthesized `## 5.5` implementation plan deliverables and asks every analyzer worker for an `AGREE`, `DISAGREE(a-e)`, or `SUPPLEMENT` verdict. The aggregate result is `passed`, `passed-with-dissent`, `blocked-by-disagreement`, or `aborted-non-result`. The frontmatter `approved` field is always published as `false`; a blocking result keeps it false and becomes a row in `## 1. Clarification Items`. For fast iteration, opt out with `--no-plan-verification`. Contract details: the "Plan-body verification mode" section of [`prompts/lead/convergence.md`](prompts/lead/convergence.md) and [`docs/cli.md#--no-plan-verification`](docs/cli.md#--no-plan-verification).
|
package/docs/architecture.md
CHANGED
|
@@ -16,7 +16,7 @@ Its core capabilities at a glance are:
|
|
|
16
16
|
- **Profiles by task type**: Loads standard task-type profiles such as `requirements-discovery`, `error-analysis`, `implementation-planning`, `implementation`, `final-verification`, and `release-handoff` to render the instruction set.
|
|
17
17
|
- **Run lifecycle**: Non-stage runs use `runs/<task-type>/` as the run directory, while `implementation` and single-stage `final-verification` use `runs/<task-type>/stage-<N>/`. Manifests, prompts, state, reports, sessions, worker results, and logs accumulate beneath the resolved run directory, and the filename suffix `-<task-type>-<seq>` separates reruns of the same phase.
|
|
18
18
|
- **Single python authority**: All prepare wiring—resolving profiles/workers/models, computing paths, rendering, and central record_start—is concentrated in a single function, [`okstra_ctl.run.prepare_task_bundle()`](../scripts/okstra_ctl/run.py). `okstra.sh` and the `okstra-run` skill are thin callers of that same function and do not pass state through environment variables. Task identity, paths, and workflow state are recalculated from authoritative on-disk files every time.
|
|
19
|
-
- **Host-aware handoff**: Claude Code, Codex, and
|
|
19
|
+
- **Host-aware handoff**: Claude Code, Codex, Antigravity, Grok, and Kimi can keep their current native session as the lead. The standalone compatibility launcher still starts a new `claude` process by default, while the external adapter uses registered CLI wrappers. Every path consumes the same `prepare_task_bundle` outputs.
|
|
20
20
|
- **Required team contract**: The `Required workers:` block in each phase profile is authoritative for the roster. General analysis phases use Claude/Codex analysers plus a report writer by default, while Antigravity, Grok, and Kimi are included only when allowed by both the profile and `--workers`. Lead-oriented phases such as `release-handoff` have separate rosters.
|
|
21
21
|
- **User-home install + project-local task bundles**: One `npx okstra@latest install` command installs the runtime (`~/.okstra/{lib/python, bin, templates, prompts}`) and installs public skills to `~/.agents/skills/` by default. If `~/.claude` exists, it also installs Claude skills and six worker agent definitions (`~/.claude/agents/*-worker.md`). Only user entry-point skills are exposed in the skill list; lead/support operating contracts are installed as runtime resources under `~/.okstra/prompts/` and are not discoverable as skills. Global conversation memory is stored separately from projects under `~/.okstra/memory-book/`. Task bundles and discovery metadata are stored under `.okstra/` in the target project. **In addition, `<PROJECT_ROOT>/.claude/settings.local.json` is provisioned as a symlink to `~/.okstra/templates/settings.local.json`** (`okstra setup` or `okstra-ctl` prepare manages it idempotently; if a regular file already existed, it is preserved as `.bak.<timestamp>` before replacement).
|
|
22
22
|
- **Resume and clarification**: Supports resuming the same task and responding to follow-up questions from the lead through `--task-key`, `--resume-clarification`, and `--clarification-response`.
|
|
@@ -149,9 +149,9 @@ Runtime entry points are consolidated in Python packages. Bash and skills only c
|
|
|
149
149
|
- `prompts/lead/adapters/claude-code.md`, `prompts/lead/adapters/codex.md`, `prompts/lead/adapters/antigravity.md`, and `prompts/lead/adapters/external.md` map the same semantic operations to one selected host runtime. The generated launch prompt exposes the core path plus exactly one adapter path.
|
|
150
150
|
- `prompts/lead/adapters/cmux.md` is selected by environment rather than by runtime: when the run manifest's `terminalBackend` is `cmux-pane`, every lead runtime resolves to it and dispatches through `okstra team`, because okstra owns the worker panes on that path instead of the host. It overrides only the adapter and the dispatch mode; the lead's agent, role, and session accounting still come from its own runtime.
|
|
151
151
|
- Runtime metadata and role assignments are persisted separately, but the lead provider is derived from the host: Claude Code maps to Claude, Codex maps to Codex, and Antigravity CLI maps to Antigravity. New runs persist `hostRuntime`, `leadAssignment`, and `workerAssignments[]`; each assignment records its provider, model, execution value, and resolved `native-session` or `cli-wrapper` runner. `lead-execution-prompt.md` is canonical, while `claude-execution-prompt.md` is a byte-identical compatibility alias for historical consumers.
|
|
152
|
-
-
|
|
152
|
+
- Host and provider registries remain separate: the active registered host owns the native lead session, while non-native providers run through their registered CLI wrappers.
|
|
153
153
|
- [`skills/okstra-setup/SKILL.md`](../skills/okstra-setup/SKILL.md) — **first-run bootstrap**. Runs `okstra install` and creates `project.json`.
|
|
154
|
-
- [`skills/okstra-run/SKILL.md`](../skills/okstra-run/SKILL.md) — host-aware in-session entry point that starts an okstra task in the current
|
|
154
|
+
- [`skills/okstra-run/SKILL.md`](../skills/okstra-run/SKILL.md) — host-aware in-session entry point that starts an okstra task in the current registered host session and calls `prepare_task_bundle` directly.
|
|
155
155
|
- Thirteen skills are user-invocable: `skills/okstra-setup/SKILL.md`, `skills/okstra-brief-gen/SKILL.md`, `skills/okstra-run/SKILL.md`, `skills/okstra-manager/SKILL.md`, `skills/okstra-memory/SKILL.md`, `skills/okstra-inspect/SKILL.md`, `skills/okstra-rollup/SKILL.md`, `skills/okstra-usage/SKILL.md`, `skills/okstra-schedule-gen/SKILL.md`, `skills/okstra-container-build/SKILL.md`, `skills/okstra-pr-gen/SKILL.md`, `skills/okstra-user-response/SKILL.md`, and `skills/okstra-code-review/SKILL.md`. Only these are copied into the agent skill home. They cover brief authoring, phase execution, cross-project manager task coordination, global Memory Book storage/search, read-side status/history/report/time/logs/cost/errors/recap, task-group-level aggregation of run results (rollup), project-wide historical resource usage, schedule support, local container deployment, PR description generation, clarification-response submission, and census-based code review of a stage or branch diff. `okstra-manager` uses `okstra manager` CLI JSON/launch packets as the source of truth, and stores manager-owned plans, assignments, directives, snapshots, and events under `~/.okstra/managers/<manager-id>/`. `okstra-rollup` is a read-side layer that fans the single-task aggregators from `okstra-inspect` (time/errors/recap) out to a task group or the whole project catalog. The `okstra rollup` CLI owns deterministic aggregation, while the skill (LLM) writes only the synthesized report summary. `okstra-usage` is a separate read-only resource snapshot grouped by lifecycle task type; it does not replace single-task `okstra-inspect` detail or the status/report digest from `okstra-rollup`. The canonical definition of `okstra-inspect` read-side facets is the subcommand table in `skills/okstra-inspect/SKILL.md`. `okstra-inspect logs` provides a read-only inventory and cleanup guidance for the live-log sidecars that the Codex/Antigravity wrappers write on every dispatch at the resolved `<run-dir>/prompts/<worker>-prompt-<phase>-<seq>.log`; for stage executions, the stage-qualified `run_dir` includes `stage-<N>/`. `okstra-inspect cost` summarizes `okstra context-cost`; `okstra-inspect errors` collects a task's okstra-run error logs into a timestamped Markdown error report and prints a summary; and `okstra-inspect recap` answers free-form questions about `.okstra` artifacts in addition to summarizing phases before and after each task run.
|
|
156
156
|
- Internal operating contracts—`context-loader` / `team-contract` / `convergence` / `report-writer` and the lead contract—have moved to `prompts/lead/*.md`. Language-specific coding preflight for implementation/verification workers has moved to `prompts/coding-preflight/*` (overview router + clean-code + three-stage language/framework/architecture selection). All are runtime resources installed under `~/.okstra/prompts/` and are not discoverable as skills. The generated launch prompt provides the lead with absolute paths, and reinstalling prunes the legacy exact-name skill directories `okstra-context-loader` / `okstra-team-contract` / `okstra-convergence` / `okstra-report-writer` / `okstra-coding-preflight` / `okstra`.
|
|
157
157
|
- Plugin manifest: [`../../.claude-plugin/plugin.json`](../.claude-plugin/plugin.json) — referenced by the supplementary `npx skills@latest add Devonshin/okstra` channel. Use `npx okstra@latest install` for normal setup. The plugin manifest exposes only the thirteen user entry points (`okstra-setup`, `okstra-brief-gen`, `okstra-run`, `okstra-manager`, `okstra-memory`, `okstra-inspect`, `okstra-rollup`, `okstra-usage`, `okstra-schedule-gen`, `okstra-container-build`, `okstra-pr-gen`, `okstra-user-response`, `okstra-code-review`).
|
|
@@ -263,7 +263,9 @@ Other variables such as `PROJECT_ID`, `TASK_GROUP`, `RUN_*`, `FINAL_*`, and `CLA
|
|
|
263
263
|
|
|
264
264
|
## Host runtime execution behavior
|
|
265
265
|
|
|
266
|
-
|
|
266
|
+
Host adapters and model providers are independent axes. The host registry discovers bundled adapters and explicit user installs under `~/.okstra/adapters/hosts/<id>/`; the provider registry uses the parallel `~/.okstra/adapters/providers/<id>/` root. Neither registry executes adapter code found in a project repository. A host descriptor names its native provider, while every non-native worker assignment resolves through the provider's CLI wrapper.
|
|
267
|
+
|
|
268
|
+
The terminal front door accepts `okstra run <host-id-or-alias>`, resolves it through `HostAdapterRegistry`, and probes `entry_mode="spawn-process"` readiness before starting that adapter's CLI. It does not infer the host from installed provider binaries and does not fall back to another host when the selected adapter is unavailable.
|
|
267
269
|
|
|
268
270
|
The legacy standalone shell path remains Claude-specific:
|
|
269
271
|
|
|
@@ -274,10 +276,13 @@ The legacy standalone shell path remains Claude-specific:
|
|
|
274
276
|
- `okstra.sh` performs only this compatibility handoff; the launched session continues under the same Okstra lead contract. Codex-hosted runs do not pass through this shell path.
|
|
275
277
|
|
|
276
278
|
**Mode B — the `okstra-run` skill hands off within the current host session**
|
|
277
|
-
- Use this when the user is already in
|
|
278
|
-
- The skill
|
|
279
|
+
- Use this when the user is already in a registered host and wants to start a new okstra task there.
|
|
280
|
+
- The skill probes `entry_mode="current-session"`, reads the selected relay contract, and declares only the semantic functions the live harness actually exposes: `plain_text_input`, `native_single_select`, `native_multi_select`, and `native_question_group` as available. The wizard receives their intersection with the adapter contract instead of inferring capabilities from a host name.
|
|
281
|
+
- The skill relays the wizard through that semantic interaction plan and calls `prepare_task_bundle(render_only=True)` with the explicit host runtime.
|
|
279
282
|
- It does not launch another lead process. The current host-native session reads `lead-execution-prompt.md` and assumes the Okstra lead role.
|
|
280
283
|
|
|
284
|
+
Kimi and Grok implement this same lead contract. Their provider roles remain `lead`, `analyser`, and `critic`; they do not gain executor, verifier, or report-writer roles from being lead-capable hosts.
|
|
285
|
+
|
|
281
286
|
Both modes create identical artifacts (task-manifest, run-manifest, timeline, instruction set, and central-index registration), so subsequent `okstra-ctl` commands (list / show / rerun / reconcile) operate consistently without distinguishing between them.
|
|
282
287
|
- The handed-off native host acts as the Okstra lead, responsible for orchestration and final synthesis.
|
|
283
288
|
- The default worker policy remains Claude + Codex analysis and a Claude report writer. Antigravity, Grok, and Kimi are profile-gated optional assignments; Grok and Kimi are read-only analyser/critic providers.
|
|
@@ -602,7 +607,7 @@ On this standalone compatibility path, `okstra.sh` finishes the prepare stage an
|
|
|
602
607
|
|
|
603
608
|
**Option B — hand off within the current host session (`okstra-run` skill)**
|
|
604
609
|
|
|
605
|
-
|
|
610
|
+
When using an installed host adapter, the current native session assumes the Okstra lead role without launching a replacement lead process. Example triggers: `"run okstra here"`, `"start error-analysis on this project"`.
|
|
606
611
|
|
|
607
612
|
Skill flow:
|
|
608
613
|
|
|
@@ -800,22 +805,26 @@ Errors that occur while provider workers, the report writer, or the Okstra lead
|
|
|
800
805
|
- Appends records through a single entry point.
|
|
801
806
|
- Both worker-sidecar dumps (`append_observed`, guarded by schema version) and lead observations (`lead-observed`) use the same helper.
|
|
802
807
|
|
|
803
|
-
### Live
|
|
808
|
+
### Live log and worker-pane presentation (every CLI worker)
|
|
804
809
|
|
|
805
|
-
- On every dispatch, `scripts/
|
|
810
|
+
- On every dispatch, `scripts/okstra_ctl/worker_runner.py` creates a `<prompt>.log` sidecar next to the prompt path and writes the CLI's output there, truncating the file on each dispatch. All five entrypoints (`okstra-{claude,codex,antigravity,grok,kimi}-exec.sh`) are four-line shells that `exec` `scripts/okstra-provider-exec.py`, so the log contract is one implementation rather than one per provider. The runner reads the child's pipes directly with a `selectors` loop — there is no FIFO and no `tee` subprocess — and the child is spawned with `start_new_session=True`, which is what keeps it addressable as a process *group* for the idle watchdog's `killpg`.
|
|
811
|
+
- How the two streams are split depends on what the CLI speaks, and the decision lives in `_stderr_target`. A `stream-json` provider puts events on stdout and only its own error text on stderr, so the two are folded into one reader. A `text` provider (codex) splits meaning across them — the result on stdout, progress on stderr — and merging them would destroy the only way to tell the answer from the noise, so they stay apart.
|
|
812
|
+
- Idle is measured from **stream arrival**, never from the log file's mtime. The screen deliberately drops thinking events, so an mtime-based watchdog would SIGTERM a healthy worker in the middle of a long reasoning stretch. On a breach the runner `killpg`s the group (SIGTERM, then SIGKILL after a 5s grace), returns exit code 124, and marks the status sidecar `{timeout: true, idle_seconds, idle_at_ts, terminated_by: "idle-watchdog"}`.
|
|
806
813
|
- The `.log` is an execution transcript containing wrapper/CLI output, not the original prompt. `okstra log-report` pairs it with the sibling persisted `.md` prompt and reports `transcriptBytes`, `promptBytes`, and their ratio separately. The compatibility fields `path`, `sizeBytes`, and `totalBytes` continue to mean transcript data, so existing consumers and transcript-size ordering remain stable.
|
|
807
|
-
- **
|
|
808
|
-
-
|
|
809
|
-
-
|
|
810
|
-
- **
|
|
814
|
+
- **Run-wide cap on the progress copy in the log** (`_LOG_PROGRESS_LINE_CAP` in `scripts/okstra_ctl/worker_runner.py`): 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 runner archives the first 5000 progress lines of the run and replaces the rest with a `[okstra log-cap] N progress line(s) elided` marker, emitted every 500 elided lines so a reader tailing the log can see the run is still producing. The cap is run-wide rather than per-block because a block boundary is a provider's own vocabulary and the shared runner has none; the cost is that a very long run keeps its opening rather than a sample throughout, which the elision notices make visible. **Only the log copy is capped** — never the screen, and never the result stream, because a truncated tool echo costs detail while a truncated answer costs the whole post-mortem.
|
|
815
|
+
- **Progress lands in the worker's own pane, not in a sibling tail pane.** The presentation is passed to the entrypoint as `--presentation live|quiet`; `live` is claimed only by a backend that opened a pane, and the default is `quiet`. Under `live` the runner renders each event into one readable row on the caller's own streams (`→ Bash: …` for a tool call, ` ← ok (N bytes)` for its result, `!! PERMISSION DENIED — <tool>: <reason>` for a refusal); thinking events are dropped. Under `quiet` progress is withheld and only the worker's closing text is printed, which is what a `cli-wrapper` dispatch on a machine with no pane surface needs. `scripts/okstra_ctl/domain/worker_stream.py` owns all three projections (`format_live`, `format_log`, `final_text`) as pure functions over *normalised* events — `Text`, `ToolCall`, `ToolResult`, `Denial`, `Result`. Providers do not share a wire format and this layer may not name one, so each adapter supplies the function that turns its own events into those, declared on `ExecCommand.normalise` beside the stream format it belongs to. Adding a provider whose stream is shaped differently is that one function; a provider that declares `stream-json` without one is failed by `tests/contract/test_provider_execution_contract.py`, which runs the schema each provider claims through its own normaliser and requires rows out.
|
|
816
|
+
- Because the wrappers no longer split a `tail -F` sibling, **nothing spawns a trace pane anymore**, and with it two pane tags lost their only writer: `@okstra_trace_run` (which marked a trace pane with its run) and `@okstra_status` (which pointed at that run's status sidecar). The operator watches the worker pane itself instead. Two consumers are now inert rather than wrong: `okstra-trace-cleanup.sh --reclaim-completed`, which reclaimed only trace panes whose `@okstra_status` read `stage=exited`, and `okstra-subagent-reclaim.sh`, which drives that mode from the `SubagentStop` / `TaskCompleted` hooks. Both still run and both now match nothing — harmless, because the panes they closed are no longer created. The hooks stay installed on user machines, so removing this machinery is a deliberate follow-up rather than a side effect.
|
|
817
|
+
- **Run-scoped tagging for cleanup**: `@okstra_worker_run=<RUN_DIR>` is still written, by `tmux.tag_pane` for the tmux-pane backend's worker-compute panes. `okstra-trace-cleanup.sh` discovers panes server-wide from that tag via `tmux list-panes -a` and runs `tmux kill-pane`, needing neither tmux environment variables nor a pane-ID registry. Because the tag is run-scoped, it does not kill panes belonging to other simultaneous okstra runs. Cleanup has two entry forms: the lead invokes it with `--run-dir <RUN_DIR>` to clean that run's worker panes, or the `hooks.SessionEnd` entry in `templates/reports/settings.template.json` invokes it with `--reap` to clean everything tagged below `$CLAUDE_PROJECT_DIR/.okstra/` when no single run directory exists at session end. Missing tmux and stale pane IDs silently degrade.
|
|
818
|
+
- **Automatic cleanup on phase transitions, including worker-agent panes**: `okstra-trace-cleanup.sh --run-dir <RUN_DIR>` closes tagged worker-compute panes plus the worker-agent panes occupied by dispatched subagents. These harness-owned panes cannot be tagged, so the script identifies them within the lead's window (`tmux list-panes -t <lead-pane>`, no `-s`) through a title allowlist: `claude-worker` / `codex-worker` / `antigravity-worker` / `report-writer-worker`. Implementation role titles such as `claude-executor` / `codex-verifier`, and FleetView teammate prefixes `✳ ` / `⠂ `, are also treated as okstra panes. Every entry matches as a substring (`*agy-executor*`), which is how a former `agy-executor-tail` trace pane was caught even though the allowlist never named trace panes; no such pane is created now. Split-pane teammates always land in the lead's window, so window scope still catches all of this run's worker panes while leaving a second okstra lead running in another window of the same tmux session out of range. Window 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>`.
|
|
811
819
|
- **Cleanup survives compaction and precedes user gates**: A `SessionStart` hook with matcher `compact` (`okstra-compact-reminder.sh`, seeded in `settings.template.json`) fires after every `/compact` or auto-compaction. It reads `cwd` from the hook's stdin JSON, finds any in-progress okstra run for that project via `active.jsonl` (`pane_reclaim.active_run_dirs_for_project`), and, if one exists, prints a factual reminder naming the run dir and how completed panes/tasks are reclaimed — restoring the boundary/gate cleanup obligation that a compaction summary can otherwise drop. The hook never kills panes itself: a teammate pane is untagged and title-only, so a hook cannot tell an in-flight worker from a finished one; the actual `kill-pane` stays with the lead, which knows completion state. Separately, the lead runs the same completed-pane reclaim immediately before any user approval/clarification/decision gate (`PROGRESS: phase-gate-cleanup panes=<n>`), so a gate is never shown with finished worker panes still open. At every cleanup point the pane-kill (`trace-cleanup`) and the task-stop (`TaskStop`) are paired — a `TaskStop` alone idles the roster task but leaves the pane open.
|
|
812
820
|
- **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.
|
|
813
821
|
- 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.
|
|
814
822
|
|
|
815
|
-
### Linked-worktree `.git/` write permissions
|
|
823
|
+
### Linked-worktree `.git/` write permissions
|
|
816
824
|
|
|
817
825
|
- Inside a `--executor codex|antigravity` worktree, `git add` / `git commit` must write to main-repository per-worktree metadata (`<main-repo>/.git/worktrees/<name>/index`, refs, HEAD) and the shared object database (`<main-repo>/.git/objects/`). These paths are outside the worktree directory, so opening only the worktree path in the sandbox causes index.lock creation to fail with EPERM, preventing the executor from satisfying the step-commit contract and forcing it to revert edits and exit.
|
|
818
|
-
-
|
|
826
|
+
- `write_scope` in `scripts/okstra_ctl/worker_request.py` resolves the main repository's absolute `.git/` path with `git -C <worktree> rev-parse --git-common-dir` and appends it to the scope, after the project root and the stage tree. The order is contract: a strategy translates the tuple into repeated `--add-dir` positionally. Every provider is told the scope the same way — codex names the project root with `-C` and skips the repeat, and the resolution itself is shared rather than copied per wrapper.
|
|
827
|
+
- The scope is what a worker may *write*; where it *runs* is a separate answer that each strategy gives (`ExecCommand.cwd`). A dispatch that passed only the working directory would produce an argv with no `--add-dir` at all, and the worker would then fail by quietly not writing files rather than by erroring.
|
|
819
828
|
|
|
820
829
|
## Token usage and cost accounting
|
|
821
830
|
|
package/docs/cli.md
CHANGED
|
@@ -59,7 +59,7 @@
|
|
|
59
59
|
Base command for initial entry with full arguments:
|
|
60
60
|
|
|
61
61
|
```bash
|
|
62
|
-
scripts/okstra.sh [--render-only] [--yes] [--no-plan-verification] --task-type <task-type> [--workers worker1,worker2] [--lead-runtime
|
|
62
|
+
scripts/okstra.sh [--render-only] [--yes] [--no-plan-verification] --task-type <task-type> [--workers worker1,worker2] [--lead-runtime <host-id-or-alias>] [--lead-provider <provider>] [--lead-model <model>] [--worker-model provider=model,...] [--report-writer-provider <provider>] [--report-writer-model <model>] [--executor claude|codex|antigravity] [--critic off|claude|codex|antigravity|grok|kimi] [--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>]
|
|
63
63
|
```
|
|
64
64
|
|
|
65
65
|
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 the in-host skill; the two option sections below document the internal Node render inputs, not standalone shell options.
|
|
@@ -382,15 +382,18 @@ scripts/okstra.sh --task-type implementation-planning --workers claude,codex --p
|
|
|
382
382
|
|
|
383
383
|
### `--lead-runtime`
|
|
384
384
|
|
|
385
|
-
Selects
|
|
385
|
+
Selects a lead adapter by registered host ID or alias. The default is `claude-code`. Terminal `okstra run <host-id-or-alias>` requests the same registry entry and verifies its `spawn-process` readiness before launch; an unavailable selected host is never replaced silently.
|
|
386
386
|
|
|
387
387
|
Lead runtime independence boundary:
|
|
388
388
|
|
|
389
389
|
- `claude-code`: the current default execution path. Claude Code v2.1.178 removed `TeamCreate`, and the session owns an implicit team. Workers are dispatched with `Agent(name: ..., run_in_background: true)` without `team_name`. `teamName` is audit/display metadata; Claude session JSONL is used for usage accounting.
|
|
390
390
|
- `codex`: the runtime marker for the Codex lead adapter. `okstra codex-run` owns `--render-only --lead-runtime codex` to prepare a task bundle, and the prepared run manifest can be passed to `okstra codex-dispatch` for CLI-backed worker execution.
|
|
391
391
|
- `antigravity`: the runtime marker for the Antigravity CLI lead adapter. The current Antigravity session owns the native lead, keeps Antigravity assignments native, and routes every other provider through its registered CLI wrapper.
|
|
392
|
+
- `grok` and `kimi`: registered native lead adapters for their corresponding CLIs. They can lead, analyse, and criticise, but they do not add executor, verifier, or report-writer worker roles.
|
|
392
393
|
- `external`: without Claude Code Teams, `--render-only --lead-runtime external` prepares the task bundle and external lead prompt. The lead manages the tmux-pane worker lifecycle with `okstra team dispatch`, `okstra team await`, and `okstra team teardown`. This path does not use `TeamCreate` / `Agent(...)` and uses artifact-only accounting.
|
|
393
394
|
|
|
395
|
+
Host IDs and providers are separate axes. Bundled and user-installed host adapters resolve from the registry; user adapters must be installed under `~/.okstra/adapters/hosts/<id>/` or `~/.okstra/adapters/providers/<id>/`. Project-local adapter code is not discovered.
|
|
396
|
+
|
|
394
397
|
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.
|
|
395
398
|
|
|
396
399
|
Host-runtime readiness is independent of worker selection. When `/okstra-setup`
|
|
@@ -405,10 +408,10 @@ worker roster contains Claude, Codex, or Antigravity.
|
|
|
405
408
|
|
|
406
409
|
### Runtime auto-detection (`auto`)
|
|
407
410
|
|
|
408
|
-
`okstra run` defaults to `auto`. `
|
|
411
|
+
`okstra run` defaults to `auto`. `src/lib/host-registry-client.mjs` asks the Python host registry to resolve explicit IDs and aliases, the `OKSTRA_RUNTIME_HOST` environment declaration, Claude Code skill handoff, or the external tmux claim. It fails fast when no adapter claims the session. Installed CLI presence alone never selects a host.
|
|
409
412
|
|
|
410
|
-
- Inside a
|
|
411
|
-
- From a terminal, `okstra run <
|
|
413
|
+
- Inside a registered host, the installed `okstra-run` skill uses `current-session`, declares the live semantic function list, and reuses the session you are already in.
|
|
414
|
+
- From a terminal, `okstra run <host-id-or-alias>` uses `spawn-process` and starts the selected host CLI. The leading word is an alias for `--lead-runtime`.
|
|
412
415
|
- `okstra run external` does not start a lead — it orchestrates an all-CLI run through `okstra team`.
|
|
413
416
|
- Starting a lead whose CLI sandboxes itself prints what is given up and waits for a `y`; `--yes` answers it. Today only Codex asks, because a sandboxed lead can reach neither cmux nor the worker CLIs' own configuration.
|
|
414
417
|
- In a generic terminal with tmux, `okstra run` orchestrates `render-bundle --lead-runtime external` -> `okstra team dispatch` -> `okstra team await`.
|
|
@@ -494,7 +497,7 @@ Selects the provider that performs the Executor role for `--task-type implementa
|
|
|
494
497
|
- The Executor is the **only worker allowed to mutate project files** in this run. The other two providers are dispatched as strict read-only verifiers in the same run.
|
|
495
498
|
- The Executor reuses the provider's worker model flag. With `--executor codex`, its model comes from `--codex-model`, default `gpt-5.6-sol`; with `--executor antigravity`, it comes from `--antigravity-model`, default `gemini-3.1-pro`.
|
|
496
499
|
- All three Claude, Codex, and Antigravity verifiers are always dispatched regardless of the Executor provider. Even the verifier using the same provider runs in a separate CLI session with isolated context, preserving the self-review safeguard.
|
|
497
|
-
- Codex and Antigravity mutate files through each CLI's auto-edit mode, for example `codex exec --sandbox workspace-write`, without passing through Claude-side Edit/Write tools. Mutations occur in the task worktree described below.
|
|
500
|
+
- Codex and Antigravity mutate files through each CLI's auto-edit mode, for example `codex exec --sandbox workspace-write`, without passing through Claude-side Edit/Write tools. Mutations occur in the task worktree described below. Every `okstra-<provider>-exec.sh` entrypoint receives the worktree path as its fourth positional argument and adds it to the worker's write scope, which each provider is told as repeated `--add-dir` (Codex names the project root with `-C` and skips the repeat). Without it, the Codex `workspace-write` sandbox rejects worktree writes with EPERM.
|
|
498
501
|
- **Claude Executor cwd handling**: Claude's Bash tool has no per-call cwd argument and inherits the lead session cwd. To run cwd-sensitive toolchains such as `cargo`, `npm`, `pnpm`, `bun`, `pytest`, `make`, or `go` inside the worktree, prefix the invocation with `cd {{EXECUTOR_WORKTREE_PATH}} && <cmd>`. Keep `cd` as the leading token in a single Bash call so Claude Code permission auto-allow works; do not wrap it in `bash -lc "..."` or `bash -c "..."`, which hides `cd` and causes a permission prompt on every call. Prefer a tool's working-directory option—such as `git -C <path>`, `cargo --manifest-path`, or `pytest --rootdir`—over a `cd && ` chain. Edit/Write/Read tools already use absolute paths and need no cwd handling. This rule applies only to the Claude Executor; the Codex and Antigravity wrappers inject cwd.
|
|
499
502
|
- **Task worktree (automatic isolation for every task type)**: During the first phase's preparation for any task type, `okstra-ctl` creates a `git worktree` at `~/.okstra/worktrees/<project-id>/<task-group-segment>/<task-id-segment>/` and branches `<work-category-namespace>/<task-id-segment>` from the resolved commit of the user-selected `--base-ref`, for example `feature/dev-9436` or `fix/dev-7311`. Later phases for the same task key reuse the path and branch and record status `reused`; no new `git worktree add` occurs during run preparation. Special characters such as `/` and `:` in every segment are normalized to `-`, and `~/.okstra/worktrees/registry.json` globally manages task-key-to-path/branch mappings under flock. Executor edits, writes, builds, tests, and commits—and verifier reads—run in this worktree. If the caller is already in another worktree or project_root is not a Git repository, provisioning is skipped and records `skipped-in-worktree` or `skipped-not-git`. Path or branch collisions fail immediately with `PrepareError`. Worktrees are not deleted after a run; remove one manually with `git worktree remove`, then `git branch -D`, then delete the registry entry. **The implementation stage isolation below is the exception.**
|
|
500
503
|
- **`implementation` stage isolation (concurrent parallelism)**: The task-key worktree above applies only from `requirements-discovery` through `implementation-planning`. Each `implementation` run executes in a **stage-specific isolated worktree** at `~/.okstra/worktrees/<project-id>/<task-group-segment>/<task-id-segment>/stage-<N>/`, on branch `<work-category-namespace>/<task-id-segment>-s<N>`. The registry atomically reserves a stage key, `<task-key>#stage-<N>`, under flock. `_resolve_effective_stages` excludes `started` rows in `consumers.jsonl` and reserved stages. Stage selection, worktree creation, and registry reservation all happen in one critical section protected by the task-key provisioning mutex at `~/.okstra/.locks/worktree-provision/`, so concurrent `implementation` runs safely select different ready stages: **one run = one stage**. A stage worktree's base depends on its dependency shape: independent (`depends-on (none)`) uses the common anchor fixed once at first stage entry; a single dependency (`depends-on X`) uses the predecessor stage's completed `head_commit`; multiple dependencies (`depends-on X,Y…`) use task-worktree HEAD after all predecessors have been merged, verified with `git merge-base --is-ancestor`, and otherwise fail with `PrepareError` and merge guidance. Select the stage with `--stage <auto|N>` for `okstra.sh`/`render-bundle`, or with the okstra-run wizard's `stage_pick` step. If `project_root` is not a Git repository or is a nested worktree, stage isolation also degrades to flat operation.
|
|
@@ -754,7 +757,7 @@ The `okstra` Node CLI (`bin/okstra`) provides both installer/admin commands and
|
|
|
754
757
|
| `okstra worker-audit-check --run-dir <runs/<task-type>/> --task-type <type> --seq <nnn> [--worker <id>]` | Apply the Phase 7 worker audit-sidecar rules mid-run, while the worker session is still alive. For each of this run's `worker-results/<worker>-<task-type>-<seq>.md` it checks that the file carries no `## 0. Reading Confirmation` heading, that the matching audit sidecar exists, and — for prompts carrying the required-v1 evidence-ledger marker — that every backticked `path:line` citation has an Evidence read row in that sidecar. `--worker` scopes it to the role that just returned. Emits `{ok, failures[]}` and exits 2 when `failures[]` is non-empty. The rules come from the `okstra_ctl.worker_audit_ledger` SSOT shared with `validate-run.py`, so an early pass and the Phase 7 pass cannot disagree. Run it right after collecting a result: the same failure at Phase 7 leaves only a retroactive edit, which breaks the audit chain, or a failed run |
|
|
755
758
|
| `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 |
|
|
756
759
|
| `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 |
|
|
757
|
-
| `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> [--
|
|
760
|
+
| `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> [--plan-decision <json>] [--task-key <key>]` writes the sidecar; the plan decision carries `status` (`approved` / `revision-requested` / `rejected`) and a `reason` that is mandatory for the latter two. 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 |
|
|
758
761
|
| `okstra pr <template\|branches\|gen> …` | Backend for the okstra-pr-gen skill. Git-only—no project registration required. `template list\|show <name\|default>\|add --name <name> (--content <text>\|--file <path>)\|path` manages PR body templates under `~/.okstra/template/pr/` (bundled fallback `src/commands/pr/default.md`); `branches` recommends a base branch; `gen --base <ref> [--template <name\|default>]` emits a JSON bundle of the template plus `<base>..HEAD` commits and `<base>...HEAD` diffstat |
|
|
759
762
|
| `okstra migrate [--apply] [--cwd <dir>] [--quiet]` | One-time migration of the project artifact root from `.project-docs/okstra/` to `.okstra/`. It is a dry run by default; `--apply` performs the move with `git mv` in a Git worktree, removes an empty `.project-docs/`, and synchronizes the `<PROJECT>/CLAUDE.md` import line, `.gitignore`, the project's rows in `~/.okstra/{recent,active}.jsonl`, and `~/.okstra/worktrees/registry.json`. It exits 1 if `.okstra/` already exists or the legacy directory is absent. Scheduled for removal by the end of v0.x |
|
|
760
763
|
| `okstra task-list [--project-root <path>]` | Combine `list_project_tasks` and `read_latest_task` into JSON containing the task catalog and latest task |
|
|
@@ -821,4 +824,8 @@ Both `wait_for_input` and `replan` stop before a stage worktree is provisioned a
|
|
|
821
824
|
|
|
822
825
|
### Live-log sidecar
|
|
823
826
|
|
|
824
|
-
For every dispatch,
|
|
827
|
+
For every dispatch, whichever provider runs it, okstra creates a `runs/<task-type>/prompts/<worker>-prompt-<phase>-<seq>.log` sidecar and writes the CLI's output into it. All five `okstra-<provider>-exec.sh` entrypoints share one implementation for this, so the log contract does not vary by provider.
|
|
828
|
+
|
|
829
|
+
**Progress appears in the worker's own pane.** Earlier versions split a sibling `tail -F` trace pane next to each worker; they no longer do, and no trace pane is created at all. Instead the presentation is passed to the entrypoint as `--presentation live|quiet`, and only a backend that opened a pane asks for `live` — the default, and what a `cli-wrapper` subagent dispatch passes, is `quiet`. Under `live` each event becomes one readable row on the worker's own streams — `→ Bash: npm run check`, then ` ← ok (2481 bytes)`, and `!! PERMISSION DENIED — <tool>: <reason>` for a refusal. Under `quiet` progress is withheld and only the worker's closing text is printed, which is what a dispatch on a machine with no pane surface needs. The `.log` sidecar records the progress either way, so withholding it from the screen loses nothing.
|
|
830
|
+
|
|
831
|
+
Because nothing spawns a trace pane, the `@okstra_trace_run` and `@okstra_status` pane user options have no writer left, and the `okstra-trace-cleanup.sh --reclaim-completed` mode plus the `okstra-subagent-reclaim.sh` hook that drives it now match no panes. Both stay installed and are harmless — the panes they existed to close are no longer created. tmux-pane backend worker-compute panes are still tagged `@okstra_worker_run=<RUN_DIR>`. When Claude receives `/exit`, the `SessionEnd` hook cleans 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 worker-compute panes and dispatched worker-agent panes within the lead-window scope (title scan uses `tmux list-panes -t <lead-pane>`, no `-s`, so a second lead in another window of the same session is out of range), 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. The lead also runs the same reclaim immediately before any user approval/clarification/decision gate (`PROGRESS: phase-gate-cleanup panes=<n>`), and an `okstra-compact-reminder.sh` `SessionStart` hook (matcher `compact`) re-injects this obligation after a `/compact`.
|
package/docs/for-ai/README.md
CHANGED
|
@@ -20,7 +20,7 @@ This directory is a compressed manual for an AI to quickly select and precisely
|
|
|
20
20
|
| Turn requirements, tickets, links, a codebase scan, or an error-zip into an okstra input brief | `okstra-brief-gen` | [`skills/okstra-brief-gen.md`](skills/okstra-brief-gen.md) |
|
|
21
21
|
| Start an okstra run or execute the next phase in the current Claude Code session | `okstra-run` | [`skills/okstra-run.md`](skills/okstra-run.md) |
|
|
22
22
|
| Manage okstra tasks across multiple projects — bundling, assignment, sync snapshots, child launch packets | `okstra-manager` | [`skills/okstra-manager.md`](skills/okstra-manager.md) |
|
|
23
|
-
| Check status, history, report, time, logs, cost, errors, error-zip, run-audit,
|
|
23
|
+
| Check status, history, report, time, logs, cost, errors, error-zip, run-audit, recap | `okstra-inspect` | [`skills/okstra-inspect.md`](skills/okstra-inspect.md) |
|
|
24
24
|
| Collect and aggregate the results of multiple task runs across a task-group (or the whole project) into a synthesized summary | `okstra-rollup` | [`skills/okstra-rollup.md`](skills/okstra-rollup.md) |
|
|
25
25
|
| Project-wide recent run coverage, tokens, known cost, CPU, and wall-clock usage by task type | `okstra-usage` | [`skills/okstra-usage.md`](skills/okstra-usage.md) |
|
|
26
26
|
| Generate a client-facing work schedule for a whole task-group | `okstra-schedule-gen` | [`skills/okstra-schedule-gen.md`](skills/okstra-schedule-gen.md) |
|
|
@@ -38,7 +38,7 @@ This directory is a compressed manual for an AI to quickly select and precisely
|
|
|
38
38
|
4. Project artifacts go under `<PROJECT_ROOT>/.okstra/` by default. The exception is `okstra-memory`, which uses the global user memory `~/.okstra/memory-book/`.
|
|
39
39
|
5. `runtime/` is build output. When fixing a source skill or template, edit the source under `skills/`, `templates/`, `validators/`, `scripts/`, `src/` and apply it via a build.
|
|
40
40
|
6. Do not guess the contents of a tracker, URL, file, report, log, zip, template, or validator. Use only what you have confirmed by reading or running with a tool.
|
|
41
|
-
7. Read-side skills also produce some artifacts. `okstra-inspect errors` produces an error report Markdown
|
|
41
|
+
7. Read-side skills also produce some artifacts. `okstra-inspect errors` produces an error report Markdown and `okstra-inspect error-zip` produces an anonymized zip. Even in these cases, keep the CLI stdout JSON as the source of truth.
|
|
42
42
|
|
|
43
43
|
## The Order the AI Reads In
|
|
44
44
|
|
|
@@ -17,7 +17,8 @@
|
|
|
17
17
|
|
|
18
18
|
- `status.4`: writes the user-requested `workStatus` into `task-manifest.json`.
|
|
19
19
|
- `errors`, `error-zip`, `recap record`: produce report/zip/log artifacts from the information read.
|
|
20
|
-
|
|
20
|
+
|
|
21
|
+
No sub-command writes outside this machine.
|
|
21
22
|
|
|
22
23
|
## sub-command list
|
|
23
24
|
|
|
@@ -32,7 +33,6 @@
|
|
|
32
33
|
| `errors` | aggregate task error logs into a timestamped markdown report | generates report |
|
|
33
34
|
| `error-zip` | build an anonymized zip of cross-project error logs | generates zip |
|
|
34
35
|
| `run-audit` | check every run's artifacts against progress invariants — catches a run that ended wrong without ever logging a failure | read |
|
|
35
|
-
| `error-issue` | turn cross-project anomalies into GitHub issue candidates (`plan`), then file the approved ones (`submit`) | writes a plan file; `submit` creates/comments GitHub issues after user approval |
|
|
36
36
|
| `recap` | summarize a task's before/after runs and record Q&A | appends `recap-log.jsonl` |
|
|
37
37
|
|
|
38
38
|
## Preflight
|
|
@@ -43,8 +43,8 @@ okstra preflight --runtime claude-code --json
|
|
|
43
43
|
- **Picker: the row's `options[]` plus `Enter directly`** — slots follow array order, the `role: recommended` entry first with its label suffixed `(Recommended)`, `Enter directly` always last. Each `label` is the option's `answer`; each `description` is `<rationale> — Scope: <scopeImpact> · Added work: <addedWork> · Direction: <directionChange>`, in that fixed order. Never fold the three axes into one phrase. An empty axis is written `not stated in the report` — never inferred. More than three entries: keep the recommended one plus the two alternatives whose `scopeImpact` differs most, and say how many were left out. Never mark anything but `recommended` as recommended.
|
|
44
44
|
- **Transcribe**: an `options[]` pick → `value` = that option's `answer` text, `disposition:"answer"`; `Enter directly` → the user's utterance verbatim, `disposition:"answer"`; free text asking for a re-ask → `disposition:"reframe"` (does not satisfy the approval gate). A question back from the user records nothing — **Read** the ref, explain, re-ask the same item with the same options. Echo `[n/N] C-014 → answer: …` and move on. Each item's JSON: `{id, kind, value, rationale?, disposition}`.
|
|
45
45
|
4. **echo → confirmed gate**: before `write`, echo the whole collection (each `id`·`disposition`·`value`·`rationale`·approval) as-is and get explicit confirmation. Never `write` before `confirmed`. On any change, re-echo and re-confirm.
|
|
46
|
-
5. **
|
|
47
|
-
6. **write**: `okstra user-response write --report <reportPath> --answers '<json>' [--
|
|
46
|
+
5. **plan decision (optional)**: only when the user stated one outright. Approval also needs the approval-blocking items **all filled with an answer**: `--plan-decision '{"status":"approved","implementationOption":"<selected option>"}'`. If any item is unfilled/reframe, do not approve and say the gate is still open. A turn-down takes the same flag with a mandatory reason: `--plan-decision '{"status":"rejected","reason":"<the user's own words>"}'` (`revision-requested` when the same plan should be reworked).
|
|
47
|
+
6. **write**: `okstra user-response write --report <reportPath> --answers '<json>' [--plan-decision '<json>'] --task-key <taskKey>` → report the returned `{sidecar:<path>}`. (When a same-named sidecar exists, the same `id` is overwritten with the new value and merged.)
|
|
48
48
|
|
|
49
49
|
## Output Rules
|
|
50
50
|
|
|
@@ -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/
|
|
148
|
+
`src/lib/host-registry-client.mjs` is the single Node boundary for host catalog, ID/alias resolution, and readiness probes. It delegates host policy to `okstra_ctl.entrypoints.hosts`; the Claude Code adapter checks project workspace trust, while other adapters own their own checks. `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 are probed by the selected adapter rather than frozen into the install manifest.
|
|
149
149
|
|
|
150
150
|
---
|
|
151
151
|
|
|
@@ -175,7 +175,7 @@ Runtime/install asset changes follow this checklist:
|
|
|
175
175
|
| `resolve-task-key` | `src/commands/inspect/resolve-task-key.mjs` | Resolve a bare task-id to candidate task-keys from the project catalog |
|
|
176
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`) |
|
|
177
177
|
| `time-report`, `log-report`, `error-report`, `error-zip` | `src/commands/inspect/*.mjs` | Read-side task runtime, wrapper log, and error aggregation helpers |
|
|
178
|
-
| `run-audit
|
|
178
|
+
| `run-audit` | `src/commands/inspect/run-audit.mjs` | Anomaly detection — checks run artifacts against progress invariants and reports invariant violations, read-only (Python: `okstra_ctl.run_audit`) |
|
|
179
179
|
| `worker-liveness` | `src/commands/inspect/worker-liveness.mjs` | Report whether pending workers are still alive, so the lead's poll ends a stalled wait early instead of paying the deadline (Python: `okstra_ctl.worker_liveness`) |
|
|
180
180
|
| `worker-audit-check` | `src/commands/execute/worker-audit-check.mjs` | Apply the Phase 7 worker audit-sidecar rules while the worker session is still alive, so it can fix its own citations (Python: `okstra_ctl.worker_audit_check`, rules in `okstra_ctl.worker_audit_ledger`) |
|
|
181
181
|
| `context-cost` | `src/commands/inspect/context-cost.mjs` | Estimate task bundle file/read context cost |
|
|
@@ -218,15 +218,16 @@ Top-level scripts:
|
|
|
218
218
|
| `okstra.sh` | Bash CLI wrapper around `prepare_task_bundle`, optionally launches `claude` |
|
|
219
219
|
| `okstra-ctl.sh` | Bash control center for list/show/open/rerun/reconcile/project commands |
|
|
220
220
|
| `okstra-central.sh` | Central run index writer / reconciler entrypoint |
|
|
221
|
-
| `okstra-claude-exec.sh
|
|
222
|
-
| `okstra-
|
|
221
|
+
| `okstra-{claude,codex,antigravity,grok,kimi}-exec.sh` | Worker CLI entrypoints — four lines each, `exec`ing `okstra-provider-exec.py` with the provider id. They hold no provider logic; adding a flag to one of these instead of to the provider adapter is exactly the drift this shape exists to prevent |
|
|
222
|
+
| `okstra-provider-exec.py` | The one worker entrypoint: parses the shared positional contract plus `--presentation`, resolves the provider's `ExecutionStrategy` from the registry, refuses a missing CLI before any artifact is written, then hands the run to `okstra_ctl.worker_runner` |
|
|
223
|
+
| `okstra-wrapper-status.py` | Standalone writer for one worker status sidecar. No longer on the dispatch path — `worker_runner.py` writes the same document in-process |
|
|
223
224
|
| `okstra-token-usage.py` | Token usage CLI entrypoint |
|
|
224
225
|
| `okstra-render-final-report.py` | Render version-selected final-report Markdown from data.json |
|
|
225
226
|
| `okstra-render-report-views.py` | Render schema v2 task-specific HTML directly from data.json, or a legacy view from schema v1 / quick Markdown |
|
|
226
227
|
| `okstra-error-log.py` | Normalize worker/lead error sidecars |
|
|
227
228
|
| `okstra-spawn-followups.py` | Follow-up spawning helper |
|
|
228
|
-
| `okstra-trace-cleanup.sh` | tmux okstra pane cleanup (worker-agent +
|
|
229
|
-
| `okstra-subagent-reclaim.sh` | entry that walks active runs and
|
|
229
|
+
| `okstra-trace-cleanup.sh` | tmux okstra pane cleanup (worker-agent + worker-compute, 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. Its `--reclaim-completed` mode keyed on trace panes tagged `@okstra_status`; **no code writes that tag any more**, so the mode is inert rather than wrong — the trace panes it reclaimed are no longer created |
|
|
230
|
+
| `okstra-subagent-reclaim.sh` | entry that walks active runs and drives `--reclaim-completed` (wired to the `SubagentStop`/`TaskCompleted` hooks). **Inert for the same reason** — it still runs and matches nothing. Left installed rather than removed: the hooks are already seeded on user machines, so retiring this is a deliberate follow-up |
|
|
230
231
|
|
|
231
232
|
### 4.3 `scripts/okstra_ctl/` — Python orchestration core
|
|
232
233
|
|
|
@@ -271,7 +272,7 @@ Important modules:
|
|
|
271
272
|
| `index.py`, `jsonl.py`, `reconcile.py`, `listing.py`, `batch.py`, `backfill.py` | `~/.okstra` run index and history operations |
|
|
272
273
|
| `run_index_row.py` | single reference point for creating / slimming / hydrating a `~/.okstra` run-index row — runId SSOT, preserves projectId raw |
|
|
273
274
|
| `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 |
|
|
274
|
-
| `run_audit.py
|
|
275
|
+
| `run_audit.py` | backend for the okstra-inspect run-audit facet — reads run-manifest / final-report / team-state artifacts and reports invariant violations (read-only, never the lead's self-report) |
|
|
275
276
|
| `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`, resolving each pending worker from its team-state row (`livenessMode` picks the artifact, `startedAt` anchors the grace) and reporting `stalled` (heartbeat past the budget, or none yet for this dispatch past the grace) or `did-not-launch` (no wrapper `.log`/`.status.json` past the launch grace) |
|
|
276
277
|
| `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) |
|
|
277
278
|
| `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 |
|
|
@@ -282,7 +283,7 @@ Important modules:
|
|
|
282
283
|
| `code_review_paths.py` | filesystem-layout SSOT for code-review result files — `stage_review_dir` / `branch_review_dir` plus `next_stage_review` / `next_branch_review`, which read the existing files to derive the next round's name (`stage-<NN>.md`, then `-r2`, `-r3`, …) or the next same-day sequence (`<YYYY-MM-DD>-<NN>.md`), so skill markdown never re-derives a literal review path |
|
|
283
284
|
| `code_review_target.py` | `okstra code-review target` backend — argument validation and JSON shaping only. Stage mode delegates whole to `okstra_project.state.code_review_target_snapshot`; branch mode is resolved here, defaulting the diff base to the merge-base with the default branch (`refs/remotes/origin/HEAD`, else `main`/`master`). Read-only: it never creates the review directory |
|
|
284
285
|
| `session.py`, `tmux.py`, `seeding.py`, `locks.py`, `invocation.py`, `sequence.py`, `ids.py`, `material.py` | Supporting lifecycle helpers |
|
|
285
|
-
| `pane_reclaim.py` | decides which completed trace panes are reclaim targets; imports the in-progress status set from the `reconcile.NON_TERMINAL_RECENT_STATUSES` SSOT |
|
|
286
|
+
| `pane_reclaim.py` | decides which completed trace panes are reclaim targets; imports the in-progress status set from the `reconcile.NON_TERMINAL_RECENT_STATUSES` SSOT. Inert alongside `--reclaim-completed` — no trace pane is created any more — but still the owner of that decision if the mechanism returns |
|
|
286
287
|
| `improvement_lenses.py` | lens enum SSOT + cap constants for the improvement-discovery phase (DEFAULT 8, ABSOLUTE 12, MIN/MAX PRIORITY 1/4, SOURCE_WORKERS) |
|
|
287
288
|
| `improvement_assignment.py` | improvement-discovery primary-pass lens assignment — round-robins the resolved `requiredWorkerRoles` order over the resolved priority lenses (`assign_primary_lenses`) and validates the resulting map (`validate_primary_lens_assignments`). Only the primary pass rotates; every analyser still confirms the full lens set afterwards |
|
|
288
289
|
| `container.py` | the `okstra container` convergence entrypoint of the okstra-container-build public skill — `provision_container_group` + `up`/`status`/`logs`/`stop-watcher`/`down` dispatch, env-override synthesis, compose argv assembly, and per-container watcher startup |
|
|
@@ -303,7 +304,9 @@ Important modules:
|
|
|
303
304
|
| `schema_excerpt.py` | generates a task-type-scoped excerpt of the final-report schema — a schema reduction to inject into the worker/lead prompt |
|
|
304
305
|
| `work_categories.py` | requirements-discovery work-category (domain) **SSOT** (`is_valid_category`) — the work-category allowlist is defined only here |
|
|
305
306
|
| `model_discovery.py` | pre-dispatch model-identity normalization for CLI workers — roster-gated label correction + a per-role reasoning-effort policy (deterministic, no per-run improvisation) for CLIs (agy) that bake effort into the model name |
|
|
306
|
-
| `
|
|
307
|
+
| `domain/`, `application/`, `ports/` | Host-neutral values and errors, wizard/run use cases, and the interaction/session/dispatch/accounting port contracts |
|
|
308
|
+
| `registry/host_registry.py`, `registry/provider_registry.py` | Discover bundled adapters plus explicit user installs under `~/.okstra/adapters/{hosts,providers}/<id>/`; project-local adapter code is outside the discovery roots |
|
|
309
|
+
| `adapters/hosts/`, `adapters/providers/` | Six bundled host strategies and the independent provider catalogs; host manifests select a native provider without merging the two axes |
|
|
307
310
|
| `lead_events.py` | structured JSONL events emitted by artifact-accounted lead runtimes |
|
|
308
311
|
| `team_reconcile.py` | stale team-member reconciliation at run-end teardown |
|
|
309
312
|
| `worker_prompt_headers.py` | shared rendering of phase-aware worker prompt anchors (`worker_prompt_headers`): coding-preflight only for implementation and compact target identity for final-verification |
|
|
@@ -319,7 +322,12 @@ Important modules:
|
|
|
319
322
|
| `scope_provenance.py` | single source of truth for the scope-provenance grammar every phase-emitted requirement must declare, shared by `validators/validate-run.py` and `validators/validate_fanout.py` so the planning report and fan-out packets cannot drift |
|
|
320
323
|
| `worker_artifact_paths.py` | canonical worker artifact path derivation (e.g. `audit_sidecar_rel` inserts `-audit-` after the first `-worker-` token), so dispatch and validation agree on non-canonical-path rejection |
|
|
321
324
|
| `report_finalize.py` | Phase 7 post-report sequence **SSOT** — runs `check-source` → `token-usage` → `render-views` → `spawn-followups` → `validate-run` in that load-bearing order, stops at the first non-zero exit and names the failing step. Both lead paths converge here: the Codex adapter calls it in-process (`codex_dispatch`), a Claude-led run reaches it through `okstra report-finalize`. Neither reimplements the sequence |
|
|
322
|
-
| `wrapper_status.py` | worker wrapper status sidecar reader — the host-side reader of the sidecar
|
|
325
|
+
| `wrapper_status.py` | worker wrapper status sidecar reader — the host-side reader of the sidecar `worker_runner.py` writes. `is_terminal` is the one question it answers for the dispatch record and the pane reclaim: does `stage` read `exited` |
|
|
326
|
+
| `worker_runner.py` | runs one worker CLI and records what happened — shared by every provider entrypoint. Owns the `selectors` pump over the child's streams, the stream-arrival idle watchdog (`killpg` on breach), the run-wide progress cap on the log copy, and the status sidecar's whole life. A run that dies after launch still closes its sidecar, so `worker_liveness` never reads a dead worker as running |
|
|
327
|
+
| `worker_request.py` | assembles the `WorkerExecRequest` every strategy then takes on trust: resolved paths, the write scope in the order the CLIs are told it (project root → stage tree → the tree's git-common-dir), the verifier's toolchain grants, and the role's idle budget |
|
|
328
|
+
| `domain/worker_exec.py` | the provider axis' vocabulary — `WorkerExecRequest`, `ExecCommand`, `ExecutionPolicy`, the `ExecutionStrategy` protocol, and `PolicySupport`, by which a provider that *cannot* express the policy must say so rather than silently run without it |
|
|
329
|
+
| `domain/worker_stream.py` | the normalised event vocabulary (`Text` / `ToolCall` / `ToolResult` / `Denial` / `Result`) plus its three pure projections: `format_live` (one readable row per event, for the pane), `format_log` (the same plus bodies, for the archive), `final_text` (the closing message alone). Also `content_block_events`, the normaliser for the wire shape keyed on `type` with `message.content` blocks, which three providers share. No files, no clock |
|
|
330
|
+
| `domain/worker_role.py` | per-role execution budgets — the 1500s/600s idle pair lives here once instead of being re-declared in each wrapper |
|
|
323
331
|
| `task_target.py` | shared helper resolving `task-key → (task_root, project_root)` (`resolve_task_root`) |
|
|
324
332
|
|
|
325
333
|
> `i18n.py` (the final-report i18n dictionary loader + Jinja2 lookup) is an intentionally undocumented internal helper — it is a render helper that users and contributors do not need to know about in the canonical docs, so it is excluded from the module map.
|
|
@@ -406,9 +414,9 @@ Boilerplate shared by several skills (bash invocation rule, outdated-CLI preflig
|
|
|
406
414
|
| Skill | User-invocable | Role |
|
|
407
415
|
|---|---:|---|
|
|
408
416
|
| `okstra-brief-gen` | yes | Produce task brief from ticket/doc/link/conversation |
|
|
409
|
-
| `okstra-run` | yes | Start/resume an okstra task in the current
|
|
417
|
+
| `okstra-run` | yes | Start/resume an okstra task in the current registered host session |
|
|
410
418
|
| `okstra-memory` | yes | Store/search/archive global conversation memory under `~/.okstra/memory-book` |
|
|
411
|
-
| `okstra-inspect` | yes | Unified read-side — sub-commands `status` (lifecycle + workStatus), `history` (past runs / re-run / resume), `report` (find final-report), `time` (elapsed-time breakdown), `logs` (wrapper log inventory + cleanup), `cost` (task bundle context/read cost), `errors` (error-log aggregation), `error-zip` (anonymized cross-project error bundle), `run-audit` (progress-invariant audit over run artifacts), `
|
|
419
|
+
| `okstra-inspect` | yes | Unified read-side — sub-commands `status` (lifecycle + workStatus), `history` (past runs / re-run / resume), `report` (find final-report), `time` (elapsed-time breakdown), `logs` (wrapper log inventory + cleanup), `cost` (task bundle context/read cost), `errors` (error-log aggregation), `error-zip` (anonymized cross-project error bundle), `run-audit` (progress-invariant audit over run artifacts), `recap` (cross-run phase recap). `SKILL.md` is a thin core (preflight + dispatch table + shared rules) and each sub-command body lives in `skills/okstra-inspect/facets/<sub-command>.md`, lazily read only after dispatch resolves; the 1:1 match between dispatch rows and facet files is enforced by `tests/contract/test_okstra_inspect_facets.py` |
|
|
412
420
|
| `okstra-rollup` | yes | Cross-task roll-up — aggregate runs/time/errors across a task-group (or whole project) and synthesize a digest from the report files |
|
|
413
421
|
| `okstra-usage` | yes | Read-only project usage snapshot — aggregate recent run coverage, tokens, known cost, CPU, and wall-clock time by task type (default: 30 days) |
|
|
414
422
|
| `okstra-schedule-gen` | yes | Generate task-group schedule |
|
|
@@ -432,11 +440,11 @@ Boilerplate shared by several skills (bash invocation rule, outdated-CLI preflig
|
|
|
432
440
|
| `agents/workers/kimi-worker.params.json` | Kimi read-only analyser/critic wrapper params |
|
|
433
441
|
| `agents/workers/report-writer-worker.md` | data.json SSOT author and audit sidecar writer |
|
|
434
442
|
|
|
435
|
-
The neutral lead lifecycle contract lives at `prompts/lead/okstra-lead-contract.md`.
|
|
443
|
+
The neutral lead lifecycle contract lives at `prompts/lead/okstra-lead-contract.md`. Executable host strategies and their relay contracts live together under `scripts/okstra_ctl/adapters/hosts/<host-id>/`; `prompts/lead/adapters/cmux.md` remains the environment-selected cmux worker-backend contract. Lead resources are installed under `~/.okstra/prompts/lead/`, while executable host adapters are installed under `~/.okstra/lib/python/okstra_ctl/adapters/hosts/`. They are runtime resources, not agent skills.
|
|
436
444
|
|
|
437
445
|
### 4.12 `tests/` and `tests-e2e/`
|
|
438
446
|
|
|
439
|
-
- `tests/`: pytest modules
|
|
447
|
+
- `tests/`: pytest modules organized by production boundary. `domain/wizard/` owns wizard state and answer behavior, `application/` owns use-case and render orchestration tests, and `adapters/{hosts,host_contract,providers,dispatch,accounting}/` owns external strategy contracts. Existing `run/`, `contract/`, `report/`, `inspect/`, `worktree/`, and `handoff/` folders retain their narrower responsibilities. The shared path SSOT is `tests/_paths.py` (`REPO_ROOT`/`TESTS_DIR`/`FIXTURES`), and the repo-root `pytest.ini` adds `tests/` to the import path. Fixtures live in `tests/fixtures/`.
|
|
440
448
|
- `tests-e2e/`: `scenario-<id>-<name>.sh` shell scenarios (record-start/reconcile, rerun, task lock, agent install, report view, etc.).
|
|
441
449
|
- Each behavior branch has one owning test at the lowest practical layer.
|
|
442
450
|
- An end-to-end scenario must cross the public CLI or installed-runtime boundary.
|
package/package.json
CHANGED
package/runtime/BUILD.json
CHANGED