okstra 0.117.0 → 0.119.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 +115 -104
- package/docs/architecture/storage-model.md +300 -0
- package/docs/architecture.md +802 -0
- package/docs/cli.md +658 -0
- package/docs/container.md +124 -0
- package/docs/contributor-change-matrix.md +5 -4
- package/docs/follow-ups/2026-07-10-final-report-option-3.md +51 -0
- package/docs/performance-improvement-plan-v2.md +374 -0
- package/docs/project-structure-overview.md +21 -10
- package/package.json +10 -5
- package/runtime/BUILD.json +2 -2
- package/runtime/bin/okstra-render-report-views.py +5 -35
- package/runtime/prompts/launch.template.md +1 -0
- package/runtime/python/okstra_ctl/clarification_items.py +48 -0
- package/runtime/python/okstra_ctl/recap.py +80 -3
- package/runtime/python/okstra_ctl/report_views.py +46 -6
- package/runtime/python/okstra_ctl/user_response.py +190 -0
- package/runtime/skills/okstra-inspect/SKILL.md +37 -2
- package/runtime/skills/okstra-pr-gen/SKILL.md +9 -8
- package/runtime/skills/okstra-user-response/SKILL.md +121 -0
- package/runtime/templates/reports/report.js +6 -3
- package/runtime/templates/reports/user-response.template.md +1 -0
- package/src/cli-registry.mjs +7 -0
- package/src/commands/inspect/recap.mjs +6 -1
- package/src/commands/inspect/user-response.mjs +26 -0
- package/src/lib/skill-catalog.mjs +1 -0
- package/README.kr.md +0 -231
- package/docs/kr/architecture/storage-model.md +0 -297
- package/docs/kr/architecture.md +0 -815
- package/docs/kr/cli.md +0 -657
- package/docs/kr/container.md +0 -122
- package/docs/kr/follow-ups/2026-07-10-final-report-option-3.md +0 -51
- package/docs/kr/performance-improvement-plan-v2.md +0 -374
- package/docs/kr/performance-improvement-plan.md +0 -147
|
@@ -0,0 +1,802 @@
|
|
|
1
|
+
# okstra — Architecture and Operations Manual
|
|
2
|
+
|
|
3
|
+
> This document supplements [README.md](../README.md). See the README for a quick start, and this document for internal behavior, contracts, and the workflow.
|
|
4
|
+
>
|
|
5
|
+
> CLI arguments/options and the interactive input flow are documented separately in [cli.md](cli.md).
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## At a glance
|
|
10
|
+
|
|
11
|
+
`okstra` is a **task bundle preparation tool** for Claude Code's cross-verification workflow. It is not a single-file review tool. Instead, it organizes task briefs, profiles, prompts, run history, and project-level discovery metadata around a stable task key so Claude can reliably orchestrate lead and worker agents.
|
|
12
|
+
|
|
13
|
+
Its core capabilities at a glance are:
|
|
14
|
+
|
|
15
|
+
- **Task identity**: Creates or reuses a task root using a stable task key based on `<project-id>/<task-group>/<task-id>`, and consistently updates the manifest, index, and timeline.
|
|
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
|
+
- **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
|
+
- **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
|
+
- **Claude handoff (two modes)**: (a) the traditional mode, where `okstra.sh` launches a new `claude` process; and (b) in-session mode, where the `okstra-run` skill prepares the task in the current Claude session and hands the lead role to that session. Both use the outputs of `prepare_task_bundle`, including the instruction set, unchanged.
|
|
20
|
+
- **Required team contract**: The `Required workers:` block in each phase profile is authoritative for the roster. General analysis phases use Claude/Codex analyzers plus a report writer by default, while Antigravity is included only when allowed by both the profile and `--workers`. Lead-oriented phases such as `release-handoff` have separate rosters.
|
|
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 four 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
|
+
- **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`.
|
|
23
|
+
- **Derived views and telemetry**: Provides final-report data.json → Markdown → Report View Model → self-contained HTML view, worker error sidecars, wrapper log sidecars, and token-usage/cost accounting.
|
|
24
|
+
|
|
25
|
+
Claude lead owns judgment policy and worker orchestration. `okstra` focuses on preparing the structured input bundle and output skeleton Claude needs to work reliably.
|
|
26
|
+
|
|
27
|
+
## Table of contents
|
|
28
|
+
|
|
29
|
+
- [Purpose](#purpose)
|
|
30
|
+
- [What okstra does](#what-okstra-does)
|
|
31
|
+
- [Runtime assets vs support assets](#runtime-assets-vs-support-assets)
|
|
32
|
+
- [Architecture: python authority + thin callers](#architecture-python-authority--thin-callers)
|
|
33
|
+
- [Claude execution behavior](#claude-execution-behavior)
|
|
34
|
+
- [Claude prompt contract](#claude-prompt-contract)
|
|
35
|
+
- [Required team contract](#required-team-contract)
|
|
36
|
+
- [Stable task identity](#stable-task-identity)
|
|
37
|
+
- [Project self-registration](#project-self-registration)
|
|
38
|
+
- [Artifact-home rule](#artifact-home-rule)
|
|
39
|
+
- [Task type](#task-type)
|
|
40
|
+
- [Standard task types](#standard-task-types)
|
|
41
|
+
- [Information transfer between phases](#information-transfer-between-phases)
|
|
42
|
+
- (See [cli.md](cli.md) for CLI arguments, options, and interactive input)
|
|
43
|
+
- [Storage model & contracts](#storage-model--contracts) → [`architecture/storage-model.md`](architecture/storage-model.md)
|
|
44
|
+
- Stable task root / per-run artifacts / `~/.okstra` indexes
|
|
45
|
+
- Task manifest · task index · run manifest · timeline · Claude operating contract
|
|
46
|
+
- [Task brief usage](#task-brief-usage)
|
|
47
|
+
- [Recommended workflow](#recommended-workflow)
|
|
48
|
+
- [1. Write a draft](#1-write-a-draft)
|
|
49
|
+
- [2. Write a formal brief](#2-write-a-formal-brief)
|
|
50
|
+
- [2.5. Triage requirements if needed](#25-triage-requirements-if-needed)
|
|
51
|
+
- [3. Render-only validation](#3-render-only-validation)
|
|
52
|
+
- [4. Run Claude](#4-run-claude)
|
|
53
|
+
- [5. Analyze errors if needed](#5-analyze-errors-if-needed)
|
|
54
|
+
- [5.5. Rerun immediately after answering](#55-rerun-immediately-after-answering)
|
|
55
|
+
- [6. Review the implementation plan if needed](#6-review-the-implementation-plan-if-needed)
|
|
56
|
+
- [7. Implement from the approved plan](#7-implement-from-the-approved-plan)
|
|
57
|
+
- [8. Run the final review after implementation](#8-run-the-final-review-after-implementation)
|
|
58
|
+
- [9. Resume the same task](#9-resume-the-same-task)
|
|
59
|
+
- [Lifecycle status and resume](#lifecycle-status-and-resume)
|
|
60
|
+
- [Final report structure](#final-report-structure)
|
|
61
|
+
- [Final report views (HTML)](#final-report-views-html)
|
|
62
|
+
- [Worker error collection (optional sidecar)](#worker-error-collection-optional-sidecar)
|
|
63
|
+
- [Token usage and cost accounting](#token-usage-and-cost-accounting)
|
|
64
|
+
- [Validators](#validators)
|
|
65
|
+
- [Practical notes](#practical-notes)
|
|
66
|
+
- [Related documents](#related-documents)
|
|
67
|
+
|
|
68
|
+
## Purpose
|
|
69
|
+
|
|
70
|
+
This document is a task-key-oriented operations guide to using `okstra` in `Okstra`.
|
|
71
|
+
Where `README.md` is the quick entry point, this document is the detailed reference for `okstra`'s execution contract, storage model, lifecycle, and Claude handoff rules.
|
|
72
|
+
|
|
73
|
+
`okstra` is not a single-file review tool.
|
|
74
|
+
`okstra` is a supporting tool that prepares stable task bundles, run history, and project-level discovery metadata so Claude Code can perform cross-verification.
|
|
75
|
+
|
|
76
|
+
## What okstra does
|
|
77
|
+
|
|
78
|
+
okstra's prepare responsibilities are consolidated in a single Python entry point, [`okstra_ctl.run.prepare_task_bundle`](../scripts/okstra_ctl/run.py). This function performs the following as one transaction:
|
|
79
|
+
|
|
80
|
+
- Verifies that okstra installation assets exist (`~/.agents/skills/okstra-*`, optional `~/.claude/skills/okstra-*` / `~/.claude/agents/*-worker.md`, `~/.okstra/bin/...`)
|
|
81
|
+
- Self-registers `<PROJECT_ROOT>/.okstra/project.json` (or verifies that the projectId matches)
|
|
82
|
+
- Loads task type → `prompts/profiles/<task-type>.md` and extracts recommended workers
|
|
83
|
+
- Normalizes user worker/model overrides (display ↔ execution-value mapping for Claude/Codex/Antigravity/Report-writer)
|
|
84
|
+
- Resolves task-brief / clarification-response paths (cwd first → PROJECT_ROOT fallback)
|
|
85
|
+
- Computes the stable task root and all paths/sequences inside a per-task mutex (`~/.okstra/.locks/<task-key>.lock`), then persists them to `<run-dir>/manifests/run-context-<seq>.json`
|
|
86
|
+
- Persists user input to `<run-dir>/manifests/run-inputs-<seq>.json`
|
|
87
|
+
- Renders the instruction set (`analysis-profile.md`, `analysis-packet.md`, `analysis-material.md`, `task-brief.md`, `reference-expectations.md`, `final-report-template.md`, `final-report-schema.json`, optional `clarification-response.md`, optional `directive.txt`, `claude-execution-prompt.md`) and writes a run prompt snapshot
|
|
88
|
+
- Updates `task-manifest.json`, `task-index.md`, `run-manifest-*.json`, `history/timeline.json`, and `discovery/{latest-task,task-catalog}.json`
|
|
89
|
+
- Writes a preassigned Claude session ID and `sessions/claude-resume-*.sh` (unless `--render-only` is used)
|
|
90
|
+
- Records record_start in the central indexes (`~/.okstra/{active,recent}.jsonl`, `projects/<id>/{index.jsonl, meta.json}`)
|
|
91
|
+
|
|
92
|
+
The two callers of `prepare_task_bundle` are:
|
|
93
|
+
|
|
94
|
+
1. **`scripts/okstra.sh`**: Parses and confirms CLI arguments → calls `prepare_task_bundle` → unless `--render-only` is used, launches `claude --model ... --session-id ... "$PROMPT"` via `exec`. It is a thin wrapper of about 160 lines.
|
|
95
|
+
2. **`okstra-run` skill**: Runs the [`okstra_ctl.wizard`](../scripts/okstra_ctl/wizard.py) state machine (`okstra wizard init|step|...` CLI) in the same Claude session to collect user input → calls `okstra render-bundle` (that is, `prepare_task_bundle(render_only=True)`) → the current session reads the rendered lead prompt and assumes the lead role. It does not launch a new Claude process. The wizard decides all branching, validation, and ordering, so the skill body is a roughly 30-line loop that displays either `AskUserQuestion` (`pick`) or a plain-text message (`text`) according to `Prompt.kind`.
|
|
96
|
+
|
|
97
|
+
The lead Claude owns judgment policy and worker orchestration. okstra's prepare stage only creates structured assets so that the lead starts with the correct input bundle and output skeleton.
|
|
98
|
+
|
|
99
|
+
## Runtime assets vs support assets
|
|
100
|
+
|
|
101
|
+
Runtime entry points are consolidated in Python packages. Bash and skills only call into them.
|
|
102
|
+
|
|
103
|
+
### Python module entry points (single authority)
|
|
104
|
+
|
|
105
|
+
> **Invocation contract.** The `python3 -m okstra_ctl.*` / `python3 -m okstra_project.*` forms below are **module identifiers** only; they are not installed into system site-packages. To invoke them directly from a shell, first export `PYTHONPATH` as `~/.okstra/lib/python`:
|
|
106
|
+
>
|
|
107
|
+
> ```bash
|
|
108
|
+
> eval "$(okstra paths --shell)" # Export OKSTRA_PYTHONPATH and related variables
|
|
109
|
+
> export PYTHONPATH="$OKSTRA_PYTHONPATH"
|
|
110
|
+
> python3 -m okstra_ctl.run --help # Now this works
|
|
111
|
+
> ```
|
|
112
|
+
>
|
|
113
|
+
> If those two lines are omitted, the command immediately fails with `ModuleNotFoundError: No module named 'okstra_ctl'` (a common pattern when an actual implementation-phase worker reads only the docs and invokes it directly). General users and workers should not invoke the modules directly; use the `scripts/okstra.sh` or `/okstra-run` entry point instead. Those wrappers configure PYTHONPATH automatically.
|
|
114
|
+
|
|
115
|
+
- [`okstra_ctl.run`](../scripts/okstra_ctl/run.py) — `prepare_task_bundle()` orchestrator + argparse CLI (`python3 -m okstra_ctl.run --workspace-root ... --project-root ... ...`, **PYTHONPATH must be configured—see the invocation contract above**).
|
|
116
|
+
- [`okstra_ctl.paths`](../scripts/okstra_ctl/paths.py) — pure path/sequence calculation in `compute_run_paths()`.
|
|
117
|
+
- [`okstra_ctl.run_context`](../scripts/okstra_ctl/run_context.py) — `compute_and_write_run_context()`, `write_run_inputs()`, and the per-task mutex.
|
|
118
|
+
- [`okstra_ctl.render`](../scripts/okstra_ctl/render.py) — task-manifest / run-manifest / timeline / task-index / team-state / launch.template / reference-expectations / discovery render functions + `python3 -m okstra_ctl.render <subcommand>` dispatcher (**PYTHONPATH must be configured—see the invocation contract above**).
|
|
119
|
+
- [`okstra_ctl.workers`](../scripts/okstra_ctl/workers.py) · [`okstra_ctl.models`](../scripts/okstra_ctl/models.py) — worker / model resolution.
|
|
120
|
+
- [`okstra_ctl.workflow`](../scripts/okstra_ctl/workflow.py) — phase rules (PHASE_ALLOWED_OUTPUTS / PHASE_FORBIDDEN_ACTIONS).
|
|
121
|
+
- [`okstra_ctl.material`](../scripts/okstra_ctl/material.py) — `analysis-material.md` body + related-tasks builder.
|
|
122
|
+
- [`okstra_ctl.session`](../scripts/okstra_ctl/session.py) · [`okstra_ctl.seeding`](../scripts/okstra_ctl/seeding.py) — Claude session ID / resume command / installation validation / runtime settings.
|
|
123
|
+
- [`okstra_ctl.{ids,index,invocation,jsonl,project_meta,reconcile,resolver,sequence,batch,backfill,listing,locks,tmux}`](../scripts/okstra_ctl/) — existing central-index (`~/.okstra`) modules.
|
|
124
|
+
- [`okstra_project.{resolver,state}`](../scripts/okstra_project/) — PROJECT_ROOT resolution + project.json upsert + task-catalog/manifest reader.
|
|
125
|
+
- [`okstra_ctl.manager_cli`](../scripts/okstra_ctl/manager_cli.py), [`manager_store`](../scripts/okstra_ctl/manager_store.py), [`manager_sync`](../scripts/okstra_ctl/manager_sync.py), [`manager_launch`](../scripts/okstra_ctl/manager_launch.py), [`manager_paths`](../scripts/okstra_ctl/manager_paths.py) — cross-project manager state, one-way project snapshot sync, and child launch packet/context creation for `okstra manager`.
|
|
126
|
+
|
|
127
|
+
### Bash entry points (thin)
|
|
128
|
+
|
|
129
|
+
- [`scripts/okstra.sh`](../scripts/okstra.sh) — CLI parsing / interactive prompt / confirm-execution-plan / `prepare_task_bundle` invocation / `exec claude`.
|
|
130
|
+
- [`scripts/lib/okstra/{cli,globals,interactive,project-resolver,usage}.sh`](../scripts/lib/okstra/) — CLI/interactive support only; contains no artifact-generation logic.
|
|
131
|
+
- [`scripts/okstra-ctl.sh`](../scripts/okstra-ctl.sh) + [`scripts/lib/okstra-ctl/`](../scripts/lib/okstra-ctl/) — central control-center CLI (list / show / open / rerun / reconcile / etc.).
|
|
132
|
+
|
|
133
|
+
### Claude assets (templates + skills)
|
|
134
|
+
|
|
135
|
+
- `prompts/launch.template.md` — lead prompt template.
|
|
136
|
+
- `prompts/profiles/*.md` — six task-type profiles (`requirements-discovery`, `error-analysis`, `implementation-planning`, `implementation`, `final-verification`, `release-handoff`).
|
|
137
|
+
- `templates/project-docs/task-index.template.md` · `templates/reports/final-report.template.md` · `templates/reports/settings.template.json` — runtime render inputs.
|
|
138
|
+
- `<PROJECT_ROOT>/.okstra/project.json` — project self-registration. Created/verified automatically on the first okstra.sh run; when `--project-root` is omitted, PROJECT_ROOT is resolved through ancestors / `git toplevel`.
|
|
139
|
+
|
|
140
|
+
### Support assets (not referenced at runtime)
|
|
141
|
+
|
|
142
|
+
- `templates/reports/*-input.template.md` — aids for authoring user input.
|
|
143
|
+
- `validators/validate-workflow.sh`, `validators/validate-schedule.py`, `validators/validate-run.py` — for manual/CI validation. The path to `validate-run.py` is recorded in run metadata.
|
|
144
|
+
|
|
145
|
+
### Skills (`skills/`) and lead resources (`prompts/`)
|
|
146
|
+
|
|
147
|
+
- [`prompts/lead/okstra-lead-contract.md`](../prompts/lead/okstra-lead-contract.md) — main okstra lead contract. It is a runtime resource (`~/.okstra/prompts/lead/`), not an agent skill.
|
|
148
|
+
- [`skills/okstra-setup/SKILL.md`](../skills/okstra-setup/SKILL.md) — **first-run bootstrap**. Runs `okstra install` and creates `project.json`.
|
|
149
|
+
- [`skills/okstra-run/SKILL.md`](../skills/okstra-run/SKILL.md) — in-session entry point that **starts an okstra task in the current Claude session**. Calls `prepare_task_bundle` directly.
|
|
150
|
+
- Only ten 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-schedule/SKILL.md`, `skills/okstra-container-build/SKILL.md`, and `skills/okstra-graphify/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), schedule support, and `okstra-container-build`, a nonlinear container deployment/monitoring skill outside PHASE_SEQUENCE that deploys verified task code as a docker compose group and monitors it with per-container watchers. `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. 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.
|
|
151
|
+
- 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`.
|
|
152
|
+
- 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 ten user entry points (`okstra-setup`, `okstra-brief-gen`, `okstra-run`, `okstra-manager`, `okstra-memory`, `okstra-inspect`, `okstra-rollup`, `okstra-schedule`, `okstra-container-build`, `okstra-graphify`).
|
|
153
|
+
- Installation location: `~/.claude/skills/<name>/SKILL.md` or `~/.agents/skills/<name>/SKILL.md`.
|
|
154
|
+
- Release procedure: [`../../RELEASING.md`](../RELEASING.md) — npm publish flow and release-please / manual fallback.
|
|
155
|
+
|
|
156
|
+
## Architecture: python authority + thin callers
|
|
157
|
+
|
|
158
|
+
okstra's prepare stage follows an on-disk authority + single Python entry-point model. This design satisfies two goals simultaneously.
|
|
159
|
+
|
|
160
|
+
1. **Compatibility with parallel Claude Code execution**: Even if the same Claude session launches multiple children through subagents, parallel Bash tools, or background work, environment variables are not mutated across them, so no race occurs.
|
|
161
|
+
2. **Behavioral equivalence between the bash CLI and the in-session skill**: Because `okstra.sh` and the `okstra-run` skill call the same `prepare_task_bundle()`, their artifacts, central-index registration, and validation paths are identical.
|
|
162
|
+
|
|
163
|
+
```
|
|
164
|
+
┌────────────────────────────────────────────────────────────────┐
|
|
165
|
+
│ Two callers, one authority │
|
|
166
|
+
├────────────────────────────────────────────────────────────────┤
|
|
167
|
+
│ │
|
|
168
|
+
│ scripts/okstra.sh skills/okstra-run/SKILL.md │
|
|
169
|
+
│ (CLI: parse bash args) (okstra_ctl.wizard state loop) │
|
|
170
|
+
│ │ │ │
|
|
171
|
+
│ └─────────────┬────────────────┘ │
|
|
172
|
+
│ ▼ │
|
|
173
|
+
│ okstra_ctl.run.prepare_task_bundle() │
|
|
174
|
+
│ (single Python function owns every artifact) │
|
|
175
|
+
│ │ │
|
|
176
|
+
│ ┌────────────┴────────────────┐ │
|
|
177
|
+
│ ▼ ▼ │
|
|
178
|
+
│ on-disk authority ~/.okstra (central index) │
|
|
179
|
+
│ <PROJECT_ROOT>/.okstra/ per-task mutex + record_start │
|
|
180
|
+
└────────────────────────────────────────────────────────────────┘
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
### State authority on disk
|
|
184
|
+
|
|
185
|
+
Task identity, paths, and workflow state are not stored in per-process environment variables. Every reader recalculates them from the following files:
|
|
186
|
+
|
|
187
|
+
| Data | Authoritative file |
|
|
188
|
+
|---|---|
|
|
189
|
+
| projectId, projectRoot | `<PROJECT_ROOT>/.okstra/project.json` |
|
|
190
|
+
| task identity / workflow | `<task-root>/task-manifest.json` |
|
|
191
|
+
| task candidate list | `<PROJECT_ROOT>/.okstra/discovery/task-catalog.json` |
|
|
192
|
+
| latest task pointer | `<PROJECT_ROOT>/.okstra/discovery/latest-task.json` |
|
|
193
|
+
| run inputs | `<run-dir>/manifests/run-inputs-<task-type>-<seq>.json` |
|
|
194
|
+
| run path hints / seq | `<run-dir>/manifests/run-context-<task-type>-<seq>.json` |
|
|
195
|
+
| run history | `<task-root>/history/timeline.json` |
|
|
196
|
+
| global indexes | `~/.okstra/{active,recent}.jsonl`, `~/.okstra/projects/<id>/{index.jsonl, meta.json}` |
|
|
197
|
+
|
|
198
|
+
### Concurrency
|
|
199
|
+
|
|
200
|
+
Two types of file locks handle all concurrency.
|
|
201
|
+
|
|
202
|
+
- `~/.okstra/.locks/<task-key>.lock` — per-task mutex. `compute_and_write_run_context` combines sequence calculation and persistence of compact `run-context.json` into one transaction. Two calls for the same task are serialized.
|
|
203
|
+
- `~/.okstra/.lock` — central-index mutex. Used by `record_start` / `reconcile` / `rotate_recent_if_needed`.
|
|
204
|
+
|
|
205
|
+
There is no serialization between different (project, task-group, task-id) tuples because their disk paths are separate and cannot collide. With environment-variable races eliminated, one Claude session can safely run multiple tasks in parallel.
|
|
206
|
+
|
|
207
|
+
### Allowed env vars (user knobs only)
|
|
208
|
+
|
|
209
|
+
The following environment variables are read only as user settings, not for state transfer.
|
|
210
|
+
|
|
211
|
+
- `OKSTRA_HOME` — overrides the central directory location (default `~/.okstra`).
|
|
212
|
+
- `OKSTRA_DEFAULT_LEAD_MODEL`, `OKSTRA_DEFAULT_CLAUDE_MODEL`, `OKSTRA_DEFAULT_CODEX_MODEL`, `OKSTRA_DEFAULT_ANTIGRAVITY_MODEL`, `OKSTRA_DEFAULT_REPORT_WRITER_MODEL` — model defaults.
|
|
213
|
+
- `OKSTRA_TOOL_NAME`, `OKSTRA_COMMAND_NAME` — display names in usage output.
|
|
214
|
+
- `OKSTRA_RUN_SEQ_OVERRIDE` — run-sequence override forced by okstra-ctl rerun / test hooks (per-process).
|
|
215
|
+
|
|
216
|
+
Other variables such as `PROJECT_ID`, `TASK_GROUP`, `RUN_*`, `FINAL_*`, and `CLAUDE_*` are not exported and do not leak into child processes.
|
|
217
|
+
|
|
218
|
+
## Claude execution behavior
|
|
219
|
+
|
|
220
|
+
In the current implementation, `okstra` executes Claude as follows.
|
|
221
|
+
|
|
222
|
+
**Mode A — `okstra.sh` launches a new Claude process**
|
|
223
|
+
- With `--render-only`, it exits after creating the instruction set without running Claude.
|
|
224
|
+
- Without `--render-only`, the prepare stage preassigns a Claude session ID and creates `claude-resume-<task-type>-<seq>.sh` under the current run's `sessions/` directory.
|
|
225
|
+
- It then runs `claude --model <lead> --session-id "$CLAUDE_SESSION_ID" "$PROMPT"` via `exec` from the target project root using the resolved `Claude lead` model execution value. (The former `--settings <runtime-settings>` argument was removed in 0.14.0; permissions are now provided by the `<PROJECT_ROOT>/.claude/settings.local.json` symlink.)
|
|
226
|
+
- `okstra.sh` performs only the handoff; the Claude lead continues by saving the final report and updating run/task state.
|
|
227
|
+
|
|
228
|
+
**Mode B — the `okstra-run` skill hands off within the current Claude session**
|
|
229
|
+
- Use this when the user is already in a Claude session and wants to start a new okstra task there.
|
|
230
|
+
- The skill collects task candidates, task type, brief, and other input through `AskUserQuestion`, then calls `prepare_task_bundle(render_only=True)` to create the same instruction set on disk.
|
|
231
|
+
- It does not launch a new Claude process. The current session reads the rendered lead prompt and immediately assumes the lead role.
|
|
232
|
+
|
|
233
|
+
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.
|
|
234
|
+
- The handed-off main Claude acts as the `Claude lead`, responsible for orchestration and final synthesis.
|
|
235
|
+
- The default worker roles for the standard workflow are `Claude worker`, `Codex worker`, and `Report writer worker`; `Antigravity worker` is optional and is included only when explicitly requested through `--workers` or the profile.
|
|
236
|
+
- Claude assigns worker responsibilities and makes the final judgment after reading the task bundle.
|
|
237
|
+
- okstra Claude assets installed in the user home (`~/.claude/skills`, `~/.claude/agents`) instruct Claude to dispatch workers through `Agent(name: ...)`; workers automatically join the session's implicit team.
|
|
238
|
+
- **Team lifecycle (Claude Code v2.1.178+)**: v2.1.178 removed the `TeamCreate` / `TeamDelete` tools and the `team_name` parameter from `Agent(...)`. When `CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1` (seeded into `settings.json` by `okstra install`), one implicit team per session is created automatically at startup. In Phase 3, the lead does not call a team-creation tool. It records only the `teamName` audit label and `teamCreate: { attempted: false, status: "implicit", splitPane: <true-if-TMUX-is-set> }`, then dispatches workers through `Agent(name: "<role>-worker", run_in_background: true)` (without team_name). Split-pane teammates appear when `$TMUX` is set and `teammateMode: auto`; outside tmux they run in-process, and both modes are valid. At run end, after Phase 7 token accounting, the lead checks for remaining tmux panes and asks whether to clean up worker teammates only for split-pane runs. If approved, `okstra-team-reconcile.sh` marks dead-pane stale-active members inactive and sends each completed teammate a `SendMessage` shutdown_request. There is no tool for deleting the implicit team; it disappears when the session ends. If the user keeps the teammates, they remain in the FleetView roster and the lead tells the user to remove them through Teams/FleetView (see *Run-end teammate teardown* in `prompts/profiles/_common-contract.md`). Phase 7 token accounting locates worker sessions by top-level `agentName` or nested `subagents/agent-a<name>-<hash>.jsonl` filenames when `teamCreate.status` is `implicit`/`skipped`/`error`.
|
|
239
|
+
|
|
240
|
+
## Claude prompt contract
|
|
241
|
+
|
|
242
|
+
The Claude launch prompt body is always rendered only from the `prompts/launch.template.md` template.
|
|
243
|
+
|
|
244
|
+
- Prompt substitution is limited to scalar placeholder values such as the task key, session ID, and absolute/relative paths.
|
|
245
|
+
- The selected profile body is rendered to `instruction-set/analysis-profile.md`.
|
|
246
|
+
- The analysis material body is rendered to `instruction-set/analysis-material.md`.
|
|
247
|
+
- The expected state for config/deployment is rendered to `instruction-set/reference-expectations.md`.
|
|
248
|
+
- Claude must read these artifact files directly; long task-specific bodies must not be duplicated inline in the launch prompt.
|
|
249
|
+
|
|
250
|
+
## Required team contract
|
|
251
|
+
|
|
252
|
+
The standard `okstra` workflow applies the following team contract consistently across runtime prompts, profiles, manifests, and skill documentation.
|
|
253
|
+
|
|
254
|
+
- The main Claude is always the `Claude lead` and operates in synthesis-only mode.
|
|
255
|
+
- The default required worker roles are `Claude worker`, `Codex worker`, and `Report writer worker`. `Antigravity worker` is optional and is included as required only when explicitly named by `--workers` or the profile's `- Workers:` section.
|
|
256
|
+
- `Report writer worker` focuses on report structure and evidence organization, but `Claude lead` remains the final synthesis owner.
|
|
257
|
+
- The default model contract is computed from central defaults. Fallbacks are `Claude lead`=`opus`, `Claude worker`=`opus`, `Codex worker`=`gpt-5.5`, and `Antigravity worker`=`auto` (when opted in). Without a separate override, `Report writer worker` follows the `Claude lead` model (therefore `opus` by default).
|
|
258
|
+
- Because `Antigravity worker` is optional, it is attempted only in runs where it is explicitly included.
|
|
259
|
+
- Before the final judgment, each required role in the current run's worker roster must have either a result or an explicit terminal status (`completed`, `timeout`, `error`, `not-run`).
|
|
260
|
+
- Every attempted worker (`completed`, `timeout`, `error`) must have an assigned worker prompt history file under the current run's `prompts/` directory.
|
|
261
|
+
- An unnamed generic parallel worker is not accepted as a substitute for a required role.
|
|
262
|
+
|
|
263
|
+
## Stable task identity
|
|
264
|
+
|
|
265
|
+
`okstra` uses the following combination as its basic identifier:
|
|
266
|
+
|
|
267
|
+
- `project-id`
|
|
268
|
+
- `task-group`
|
|
269
|
+
- `task-id`
|
|
270
|
+
|
|
271
|
+
The logical task key has this form:
|
|
272
|
+
|
|
273
|
+
```text
|
|
274
|
+
<project-id>:<task-group>:<task-id>
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
Reuse the same `task-group` and `task-id` when reopening the same bug or continuing the same work.
|
|
278
|
+
Use a new `task-group` or `task-id` for unrelated work.
|
|
279
|
+
|
|
280
|
+
## Project self-registration
|
|
281
|
+
|
|
282
|
+
`okstra.sh` operates without an external registration directory (the former `examples/projects/*.conf.sh` model has been retired). At the start of each run, it resolves PROJECT_ROOT in the following order and self-registers `.okstra/project.json` at that location as the authoritative source.
|
|
283
|
+
|
|
284
|
+
Resolution order:
|
|
285
|
+
|
|
286
|
+
1. CLI argument `--project-root <path>`.
|
|
287
|
+
2. The location containing `.okstra/project.json` in cwd or one of its ancestor directories.
|
|
288
|
+
3. `git rev-parse --show-toplevel` from cwd.
|
|
289
|
+
|
|
290
|
+
If all three fail, `okstra.sh` exits immediately with an error (there is no automatic guess).
|
|
291
|
+
|
|
292
|
+
`<PROJECT_ROOT>/.okstra/project.json` schema:
|
|
293
|
+
|
|
294
|
+
```json
|
|
295
|
+
{
|
|
296
|
+
"projectId": "sample-project-v2-api",
|
|
297
|
+
"projectRoot": "/Volumes/Workspaces/workspace/projects/sample-project",
|
|
298
|
+
"createdAt": "2026-05-10T00:00:00Z",
|
|
299
|
+
"updatedAt": "2026-05-10T00:00:00Z",
|
|
300
|
+
"worktreeSyncDirs": [".project-docs", ".scratch", "graphify-out", ".claude"]
|
|
301
|
+
}
|
|
302
|
+
```
|
|
303
|
+
|
|
304
|
+
On the first run, it writes the four fields `projectId`, `projectRoot`, `createdAt`, and `updatedAt`. If the file already exists, it verifies that the `--project-id` argument matches the stored `projectId`, then updates only `projectRoot`/`updatedAt`. Unknown user-added fields such as `worktreeSyncDirs` and future `mcpServers` are preserved during the upsert. A mismatch causes an immediate exit, preventing two IDs from being mixed in the same directory.
|
|
305
|
+
|
|
306
|
+
`worktreeSyncDirs` (optional) overrides, per project, the list of project-root-relative directories to symlink into task worktrees. Resolution order is the `OKSTRA_WORKTREE_SYNC_DIRS` environment variable → `project.json` → built-in default (`.project-docs`, `.scratch`, `graphify-out`, `.claude`). An empty array disables syncing entirely. Sync exists only for filesystem continuity; the okstra context/write boundary remains `<PROJECT_ROOT>/.okstra/**`.
|
|
307
|
+
|
|
308
|
+
The authoritative source for `okstra-ctl` reindex/backfill also changed under the new model. Previously it sourced `examples/projects/*.conf.sh`; it now scans `~/.okstra/projects/<projectId>/meta.json` (the mirror of the project.json information produced by record_start) to restore (projectId, projectRoot) mappings. The `OKSTRA_PROJECT_DEFINITION_DIR_OVERRIDE` environment variable has also been retired.
|
|
309
|
+
|
|
310
|
+
## Artifact-home rule
|
|
311
|
+
|
|
312
|
+
okstra has exactly one project artifact root: `<PROJECT_ROOT>/.okstra/`. Anything outside this root is not okstra memory. It may be read as read-only source material only when explicitly cited by the brief's `Source Material` or `Reporter Confirmations`; okstra does not write outside the root on its own judgment.
|
|
313
|
+
|
|
314
|
+
There is one exception: when the user requests, **verbatim**, that a specific non-okstra file be edited in the brief's `Source Material` or `Reporter Confirmations` section. The phase that performs the edit must include the user's original wording in its final report.
|
|
315
|
+
|
|
316
|
+
okstra maintains its own institutional memory inside its subtree.
|
|
317
|
+
|
|
318
|
+
- `<PROJECT_ROOT>/.okstra/glossary.md` — the okstra glossary accumulated across runs.
|
|
319
|
+
- `<PROJECT_ROOT>/.okstra/decisions/<NNNN>-<slug>.md` — okstra decision records. Candidates are evaluated during the `implementation-planning` phase; `okstra-brief-gen` only marks them as candidates.
|
|
320
|
+
|
|
321
|
+
okstra phases do not write PRD or issue files directly. Equivalent decision artifacts are created inside `.okstra/` by `requirements-discovery` and `implementation-planning`.
|
|
322
|
+
|
|
323
|
+
## Task type
|
|
324
|
+
|
|
325
|
+
`task-type` simultaneously determines the purpose of the current run, profile selection, and lifecycle phase routing.
|
|
326
|
+
|
|
327
|
+
Selection rules:
|
|
328
|
+
|
|
329
|
+
- With `--task-type <name>`, `prompts/profiles/<name>.md` is rendered as the task bundle's `instruction-set/analysis-profile.md`.
|
|
330
|
+
- The single selector in the external interface is `task-type`.
|
|
331
|
+
- The selected task type is reflected unchanged in `taskType`, `workflow.currentPhase`, and `workflow.nextRecommendedPhase` in task-manifest.json.
|
|
332
|
+
- It is also used as the run-directory path segment (`runs/<task-type>/...`).
|
|
333
|
+
|
|
334
|
+
### Standard task types
|
|
335
|
+
|
|
336
|
+
Each task type enforces phase-specific allowed and forbidden actions. A run creates only the artifacts for its own task type and does not advance to the next phase. The next phase always begins with a new `okstra.sh` execution.
|
|
337
|
+
|
|
338
|
+
| task type | Purpose | Core artifacts | Next recommended phase | Code changes allowed? |
|
|
339
|
+
|---|---|---|---|---|
|
|
340
|
+
| `requirements-discovery` | Classify the request as bugfix, feature, refactor, ops, or improvement, then route it to a safe next phase | work category, routing decision, missing-input list, clarification requests | `pending-routing-decision` (decided after the user responds) | No |
|
|
341
|
+
| `error-analysis` | Analyze the symptoms, causes, and reproduction gaps of a reported error/incident based on evidence | symptom/trigger summary, root-cause hypotheses, reproduction gap, validation path | `implementation-planning` | No |
|
|
342
|
+
| `implementation-planning` | Evaluate safe implementation directions and options before coding begins | At least two implementation options, affected-file list, trade-offs, validation/rollback, YAML frontmatter `approved: false` / `implementation-option:`, **§5.5.9 Plan Body Verification** (a post-synthesis Phase 6 worker verification round in which workers cross-verify the internal consistency of the synthesized plan with `AGREE` / `DISAGREE(a-e)` / `SUPPLEMENT`; the user may change frontmatter to `approved: true` only when the gate result is `passed` / `passed-with-dissent`; for `blocked-by-disagreement` / `aborted-non-result`, majority DISAGREE items are converted into `Blocks=approval` rows in `## 1. Clarification Items`). **Artifact structure**: always `## 5.5 Stage Map` plus N `## 5.5.<i> Stage <i>` sections. Each stage has at most 8 effective steps. Stages with `depends-on (none)` may run in parallel as separate `implementation` runs | `implementation` (after user approval) | No |
|
|
343
|
+
| `implementation` | Modify source code according to the approved `implementation-planning` final report. **One run executes exactly one stage** (selected with `--stage <auto\|N>`) | commit list, diff summary, out-of-plan edits block, validation/TDD evidence, rollback verification, verifier results (Antigravity/Codex/Claude), `carry/stage-<N>.json` evidence sidecar | `final-verification` | Yes (limited to the approved plan's file list; `git push`/publish/deploy/real migration prohibited) |
|
|
344
|
+
| `final-verification` | Check completed work for residual defects and regression risk, then make a release judgment | acceptance verdict, residual risk, follow-up routing (`error-analysis`/`implementation-planning`/`release-handoff`) | `pending-release-handoff` (enters `release-handoff` only when the verdict is `accepted`; otherwise reroutes to `error-analysis` or `implementation-planning`) | No (read-only tests only) |
|
|
345
|
+
| `release-handoff` | Deliver `accepted` changes as a commit, push, or PR according to the user's chosen method | user menu responses (H1 action / H2 PR base / H3 message handling), executed git/gh command log, commit SHA list, PR URL | `done-or-follow-up` | Yes—but execute **only the mutating commands selected by the user in the menu**. `git push --force*`, direct push to the base branch, `--no-verify`, `gh release`, and publish/deploy are prohibited. The source code itself must not be changed; package the existing `implementation` diff unchanged. |
|
|
346
|
+
|
|
347
|
+
Common constraints:
|
|
348
|
+
|
|
349
|
+
- Every phase except `implementation` prohibits source-code edits, builds, migrations, deployments, and other state-mutating commands (`final-verification` allows read-only test commands only). `implementation` permits edits/commits only within the file list of the approved plan; `git push`, publish, deploy, real migration, and third-party write APIs remain prohibited.
|
|
350
|
+
- **Isolated worktree for pre-implementation non-implementation phases (BLOCKING)**: The first pre-implementation non-implementation phase prepare creates a task-key `git worktree` through `okstra-ctl`. Pre-implementation non-implementation phases reuse the task-key worktree: `requirements-discovery` → `error-analysis` → `implementation-planning` use the same worktree and branch for the same task key. `implementation` does not reuse this task-key worktree; implementation uses a dedicated stage-specific worktree and branch for every stage/run, as described in the next item. The task-key worktree lives at `~/.okstra/worktrees/<project-id>/<task-group-segment>/<task-id-segment>/` (special characters such as `/` and `:` in segments are normalized to `-`), and the branch is named `<work-category-namespace>/<task-id-segment>` (for example, `feature/dev-9436` or `fix/dev-7311`). The namespace is derived from work_category (`feature`·`improvement`→`feature/`, `bugfix`→`fix/`, `refactor`→`refactor/`, `ops`→`ops/`, unspecified→`task/`). The base ref is the commit selected by the user's `--base-ref` during the first phase's prepare. `~/.okstra/worktrees/registry.json` (guarded by flock) globally manages task-key → path/branch mappings to prevent path and branch collisions during concurrent runs. Configured sync directories are linked from the main worktree as symlinks to provide filesystem continuity across task checkouts (the sync list can be overridden by `worktreeSyncDirs` in `project.json` or the `OKSTRA_WORKTREE_SYNC_DIRS` environment variable; an empty array disables syncing). This sync does not expand the okstra context/write boundary. Provisioning is skipped when the caller is already inside another worktree or project_root is not a Git repository, and the executor works directly from project_root. The worktree is not automatically deleted after a run; it is the authoritative artifact for later phases, PR authoring, and rollback verification. Manual cleanup: `git -C <main-worktree> worktree remove <path>` → `git -C <main-worktree> branch -D <branch>` + remove the registry entry. See the *Task worktree* block in `prompts/profiles/implementation.md` and the *Task worktree (BLOCKING for every task-type)* section in `prompts/lead/okstra-lead-contract.md` for details.
|
|
351
|
+
- **Isolated implementation-stage worktrees (concurrent parallelism)**: The task-key worktree above is the model for `requirements-discovery` through `implementation-planning`. `implementation` tasks use **stage isolation**: **one run = one stage**, and every run receives an isolated worktree at `.../<task-id-segment>/stage-<N>/` (branch `<work-category-namespace>/<task-id-segment>-s<N>`). The registry reserves task keys and **stage keys** (`<task-key>#stage-<N>`) together under flock. The Stage Lifecycle Snapshot reads `done`/`started` entries in `consumers.jsonl`, carry-sidecar backfills, and reserved registry stages together, and removes them from the ready set (occupancy SSOT = registry). Thus, if the user starts two `implementation` runs simultaneously, they proceed on different independent stages without collision. Base selection: independent = common anchor (HEAD fixed at entry to the first stage); single dependency = predecessor's done commit; multiple dependencies = task worktree HEAD only if every predecessor is an ancestor (`git merge-base --is-ancestor`; otherwise `PrepareError`). The cost-aware-design ready-set batch has been retired because each stage needs an isolated branch and reserving two stage keys on one branch creates a branch-uniqueness collision, so it offers no benefit: sequential work uses the next run after a stage is done, and concurrent work uses separate runs, at equivalent cost. Select a stage with `--stage <auto|N>` or the wizard's `stage_pick`. The wizard's `stage_pick` is a multiselect that labels each stage with its state (`mark_done`/`mark_active`/`mark_ready`/`mark_blocked`), topologically sorts the dependency closure of the selection with Kahn's algorithm (`stage_targets.order_stage_closure`), and exports it as the `chain-stages` CSV in render-args. The `okstra-run` SKILL consumes this queue and sequentially executes N single-stage runs in dependency order as an unattended chain, advancing only after checking the Phase 6 `done` row for each stage. This is an orchestration layer only; the **one run = one stage** isolation invariant of the wizard and prepare remains unchanged. Not only worktrees but also **run artifacts (reports, state, worker results, manifests) are isolated per stage under `runs/implementation/stage-<N>/`**, so reports and state from two concurrently running stages do not mix. In contrast, `consumers.jsonl` and the worktree registry remain at the task-type root (`runs/implementation/`) because they are shared coordination sources of truth across stages.
|
|
352
|
+
- **Isolation of single-stage final-verification run artifacts (concurrent parallelism)**: Single-stage `final-verification` (`--stage <N>`) also isolates run artifacts under `runs/final-verification/stage-<N>/`, like implementation, with independent sequences per stage, and appends `-fv-s<N>` to the team name. The `-fv-` delimiter prevents collisions with the same stage's implementation team (`-s<N>`) and with the default whole-task verification name. Thus, final-verification for multiple stages can run concurrently without mixing state, worker results, reports, or teams. It does not create a new worktree; it reuses the corresponding implementation stage worktree from the registry read-only and therefore does not reserve a registry stage key. The `-fv-s<N>` suffix on the `teamName` label is only for audit/display distinction. The actual team is the per-session implicit team (`session-<leadSid>`), so the pre-v2.1.178 hard failure caused by a `TeamCreate` name collision no longer occurs. Whole-task verification (empty stage value) retains the existing flat `runs/final-verification/` structure.
|
|
353
|
+
- Every phase except `implementation` and `release-handoff` prohibits source-code edits, builds, migrations, deployments, and other state-mutating commands (`final-verification` permits read-only test commands only). `implementation` allows edits/commits only within the approved plan's file list; `git push`, publish, deploy, real migration, and third-party write APIs remain prohibited. `release-handoff` does not modify source code and executes only the commit / push / PR commands selected by the user in the menu (force push, direct push to the base branch, hook bypass, and release publication remain prohibited).
|
|
354
|
+
- Even if the user says something like "continue to the next step," that statement alone does not automatically begin the next phase. The next phase begins only with a new `okstra.sh` execution.
|
|
355
|
+
- **Authority & permissions assumption (shared by every task type and `okstra-schedule`)**: Assume that the user and team have full authority and approval authority for every anticipated action. Do not include external approvals, third-party access, role/IAM permissions, organizational sign-off, legal/security review, vendor coordination, or questions about whether permission is held in routing decisions, missing inputs, clarification questions, risks, dependencies, open questions, or effort/day estimates. Internal okstra phase handoffs such as the `approved:` frontmatter in `implementation-planning` are gates the user can approve immediately and are unaffected. Forbidden `implementation` actions such as `git push`, production deployment, and shared-DB migration also remain prohibited for **safety reasons**, not permission reasons.
|
|
356
|
+
- Detailed phase rules are defined in `prompts/profiles/<task-type>.md`, whose body is rendered unchanged into `instruction-set/analysis-profile.md`.
|
|
357
|
+
|
|
358
|
+
### Information transfer between phases
|
|
359
|
+
|
|
360
|
+
- After the user fills answers into the `## 1. Clarification Items` section of a final report produced by `requirements-discovery`, `error-analysis`, or `implementation-planning`, carry that file into the next run with `--clarification-response <previous-final-report.md>`.
|
|
361
|
+
- The carried-in file is copied to the current run's `instruction-set/clarification-response.md`; the lead updates each prior `Q*` row's `Status` (`resolved` / `obsolete`) in Section 0 before proceeding.
|
|
362
|
+
- To edit answers and rerun in one operation, use `--resume-clarification`. See the `### --resume-clarification` section for details.
|
|
363
|
+
- **Stage carry-in (`implementation` → next stage)**: Every `implementation` run writes a `runs/implementation/stage-<N>/carry/stage-<N>.json` evidence sidecar beneath its resolved stage run directory. The next stage automatically carries in this file. Reverse links identifying which `implementation` run consumed each stage accumulate in the shared coordination file `runs/implementation-planning/consumers.jsonl`.
|
|
364
|
+
|
|
365
|
+
### Fix cycle (post-release bug hotfix history)
|
|
366
|
+
|
|
367
|
+
If a bug is discovered in artifacts after a task has completed release-handoff, fix it by reentering the same task ID through an entry phase (`requirements-discovery` / `error-analysis` / `implementation-planning`). There is no dedicated hotfix task type, and the phase gates remain unchanged. This set of reentry runs is a **fix cycle**. Its source of truth is the append-only event rows (`opened` / `run` / `closed`) in `<task_root>/history/fix-cycles.jsonl`, owned exclusively by the module `scripts/okstra_ctl/fix_cycles.py`. The entry-phase list is defined only in `fix_cycles.FIX_CYCLE_ENTRY_PHASES` and is shared by the prepare gate and wizard detection predicate.
|
|
368
|
+
|
|
369
|
+
- **Entry**: The okstra-run wizard detects reentry into an entry phase for a completed task and confirms it at the `fix_cycle_confirm` step. The CLI uses `--fix-cycle <yes|no>` (when omitted, nothing is recorded). `--fix-cycle yes` opens a cycle only if both guards pass: task type is an entry phase, and the manifest's `workflow.lastCompletedPhase` is `release-handoff`; a violation raises `PrepareError`. A task may have only one open cycle at a time.
|
|
370
|
+
- **Attachment**: While a cycle is open, all runs for the same task attach to it as `run` rows even without a later `--fix-cycle` flag, and `fixCycleId` is recorded in run-manifest and timeline entries.
|
|
371
|
+
- **Closure**: After a release-handoff run attaches to an open cycle and the manifest's `workflow.lastCompletedPhase` becomes `release-handoff`, the next prepare lazily appends a `closed` row.
|
|
372
|
+
- **Consumers (all derived views)**: ① the `## Fix History` section of a later run's analysis-packet ② quotation in Task Continuity Notes from okstra-brief-gen ③ final-report `## 5.10 Fix History` (when run-manifest has `fixCycleId`, validator `_validate_fix_cycle` requires a `fixCycle` block in data.json) ④ a `fixCycles` summary in task-manifest plus a one-line entry in task-index / task-catalog. All four consumers read only derived views from `fix_cycles.summarize()` / `packet_summary()`.
|
|
373
|
+
|
|
374
|
+
### release-handoff stage-group mode
|
|
375
|
+
|
|
376
|
+
`release-handoff` operates in two modes.
|
|
377
|
+
|
|
378
|
+
- **whole-task (default)**: Exports the entire task as one PR. This is the existing behavior.
|
|
379
|
+
- **stage-group**: Selects some stages that received `accepted` in single-stage final-verification and combines them into one PR on a collector branch. This allows a PR to be opened for a verified stage group without waiting for the entire task to finish.
|
|
380
|
+
|
|
381
|
+
Entry is based on **task ID**, without a brief. Briefs are inputs to entry phases; for release-handoff, prepare determines eligibility from the approved plan's Stage Map + Stage Lifecycle Snapshot, then automatically creates an input document (`<task_root>/release-handoff-input.md`) that cites the verification reports. Stage selection comes from the okstra-run wizard's `handoff_stage_pick` multiselect (eligible stage groups / whole task when an accepted whole-task report exists) or CLI `--stages <csv>`, and is exposed to the lead as `HANDOFF_MODE` / `HANDOFF_STAGES` in run-context.
|
|
382
|
+
|
|
383
|
+
The stage-group interaction order is: **G1 select base → G2 confirm stages (selection finishes before prepare—do not ask again) → assemble (create collector branch + merge selected stages) → conflict probe → draft PR → push/PR**.
|
|
384
|
+
|
|
385
|
+
- The Stage Lifecycle Snapshot is the source of truth for eligibility. The Snapshot reads `verified` entries (which stages were accepted in single-stage final-verification), `pr` entries (which stages went into which PR), and done rows in `consumers.jsonl`, then computes stages that are `verified` but not yet included in a `pr` as candidates.
|
|
386
|
+
- The worktree registry reserves stage-group occupancy under the key `<task-key>#group-<id>`, and collector branches are named `<work-category-namespace>/<task-id-segment>-g2-3` (for example, `-g2-3` when stages 2 and 3 are selected).
|
|
387
|
+
- Enforcement is implemented in the Python module `okstra_ctl.handoff`, not merely declared (`okstra handoff <subcommand>`). It has four subcommands: `eligible` (query eligible stages) / `assemble` (create and merge the collector branch) / `record-verified` (record a `verified` row) / `record-pr` (record a `pr` row). Merging during collection is an explicit exception to the isolation spec's non-goal that "okstra does not merge automatically."
|
|
388
|
+
|
|
389
|
+
### improvement-discovery (sidetrack entry-point)
|
|
390
|
+
|
|
391
|
+
````
|
|
392
|
+
[brief: scope=codebase + priority-lenses]
|
|
393
|
+
↓ okstra-run --task-type improvement-discovery
|
|
394
|
+
[improvement-discovery]
|
|
395
|
+
↓ final-report (## 5.9 Improvement Candidates, N candidates)
|
|
396
|
+
↓ (user selects K candidates and writes a new brief for each)
|
|
397
|
+
[requirements-discovery | implementation-planning | error-analysis] (new task-id per selected candidate)
|
|
398
|
+
````
|
|
399
|
+
|
|
400
|
+
A sidetrack entry point that is not a formal member of `PHASE_SEQUENCE`. It supports codebase-discovery scenarios without breaking the one-way lifecycle. The lens allowlist and candidate cap are consolidated in the single source of truth `scripts/okstra_ctl/improvement_lenses.py`. The 11-item contract in `validators/validate_improvement_report.py` enforces the 10-column `## 5.9 Improvement Candidates` table in the final report. Two bidirectional grilling points—an enhanced budget of 8 in `okstra-brief-gen` Step 4 and the lead's Phase 1.5 reflect-back budget of 12—align the user's and AI's understanding.
|
|
401
|
+
|
|
402
|
+
### requirements-discovery fan-out
|
|
403
|
+
|
|
404
|
+
For mixed or multi-item requests, requirements-discovery splits the request into packets by domain (the five-value work-category enum) and publishes them to `runs/requirements-discovery/fan-out/unit-*.md`. Each packet becomes a new task key through `okstra-run --task-brief <path>`. The dependency topological order is recorded in `index.md`, and okstra-schedule owns the integrated schedule after task creation. okstra-brief-gen is not involved in this path. Validation: `validators/validate_fanout.py` (validate-run hook).
|
|
405
|
+
|
|
406
|
+
### Worktree preview at the confirm step
|
|
407
|
+
|
|
408
|
+
The okstra-run wizard does not add a separate branch-confirmation step. Instead, the final summary block (`confirmation_block`) immediately before `confirm` shows one `worktree` line indicating "create a new branch/worktree vs reuse the current worktree." The decision is previewed through the side-effect-free `worktree.preview_worktree_decision()`, and `provision_task_worktree` uses the same helper during execution, so preview and reality match. Because `implementation` uses stage isolation, the preview reflects the stage worktree the current run will actually use rather than the task-key directory (`preview_stage_worktree_decision`; stage `auto` uses `compute_worktree_path`). `final-verification` omits the worktree line because it reuses a stage worktree read-only. `confirm` offers three options: `Proceed`/`Edit`/`Abort`. `Edit` rewinds to any step, including base-ref selection. `Abort` is terminal: state is fixed as `aborted`, subsequent `next_prompt` calls return only `kind: "aborted"`, and `render-args` rejects the request with `ok: false`.
|
|
409
|
+
|
|
410
|
+
|
|
411
|
+
---
|
|
412
|
+
|
|
413
|
+
## Storage model & contracts
|
|
414
|
+
|
|
415
|
+
The complete specification for `okstra`'s three storage areas (stable task root / per-run artifacts / `~/.okstra` indexes), along with the task manifest, task index, run manifest, timeline, and Claude operating contract, has moved to a separate document: [`architecture/storage-model.md`](architecture/storage-model.md).
|
|
416
|
+
|
|
417
|
+
## Task brief usage
|
|
418
|
+
|
|
419
|
+
`okstra` is brief-first. The brief is the canonical source material that preserves external input and okstra augmentations. Any additional material workers need—reports, code snippets, logs, and so on—must be included inline or by path in the brief's `Evidence and Source Materials` section.
|
|
420
|
+
|
|
421
|
+
Briefs are accepted as direct input **only for entry phases**: users provide a brief path for `requirements-discovery`, `error-analysis`, and `improvement-discovery`. Downstream phases (implementation-planning / implementation / final-verification) automatically carry in the task manifest's `taskBriefPath` (the okstra-run wizard does not ask for it; if it is unregistered, a fallback picker recommends switching to an entry phase). `release-handoff` has no brief; prepare generates an input document that cites verification reports.
|
|
422
|
+
|
|
423
|
+
A brief is a **translation layer**: it converts external input—an issue-tracker ticket, requirements document, or user message—into an okstra-readable format while preserving the original verbatim and clearly distinguishing okstra additions as labelled augmentation. The output of the `okstra-brief-gen` skill is the source of truth. For each analysis phase, `prepare_task_bundle()` extracts the necessary frontmatter, task-specific brief sections, reference expectations, carried-in clarification, and directive into `instruction-set/analysis-packet.md`. This compact packet is the analysis workers' primary input; the original brief and profile/material files are fallback evidence opened only to verify evidence or fill omissions.
|
|
424
|
+
|
|
425
|
+
A brief typically includes:
|
|
426
|
+
|
|
427
|
+
- Problem description
|
|
428
|
+
- Requirements
|
|
429
|
+
- Existing analysis
|
|
430
|
+
- Raw sample or log
|
|
431
|
+
- Related code paths
|
|
432
|
+
- Constraints
|
|
433
|
+
- Questions for workers
|
|
434
|
+
- Expected output
|
|
435
|
+
- Previous-run or related-task information
|
|
436
|
+
- (Optional) glossary candidates—okstra-brief-gen Step 4.5 writes these directly to `<PROJECT_ROOT>/.okstra/glossary.md`
|
|
437
|
+
- (Optional) decision candidates—evaluated in the `implementation-planning` phase and promoted to `.okstra/decisions/<NNNN>-<slug>.md`
|
|
438
|
+
|
|
439
|
+
Step 6.5 of okstra-brief-gen is **reporter batch confirmation**. It asks the user to confirm, in one batch, whether meaning changed while external input was translated into the brief, and records the results in the `Reporter Confirmations` section. Every analysis profile requires this section as a precondition to phase analysis (validator: `validators/validate-brief.py`).
|
|
440
|
+
|
|
441
|
+
Default templates:
|
|
442
|
+
|
|
443
|
+
- `templates/reports/quick-input.template.md`
|
|
444
|
+
- `templates/reports/task-brief.template.md`
|
|
445
|
+
- `templates/reports/error-analysis-input.template.md`
|
|
446
|
+
- `templates/reports/implementation-planning-input.template.md`
|
|
447
|
+
- `templates/reports/implementation-input.template.md`
|
|
448
|
+
- `templates/reports/final-verification-input.template.md`
|
|
449
|
+
|
|
450
|
+
At minimum, fill the following fields in input templates:
|
|
451
|
+
|
|
452
|
+
- `Project ID`
|
|
453
|
+
- `Task Group`
|
|
454
|
+
- `Task ID`
|
|
455
|
+
- `Related Tasks`
|
|
456
|
+
- `Task Type`
|
|
457
|
+
- `Requested Outcome`
|
|
458
|
+
|
|
459
|
+
## Recommended workflow
|
|
460
|
+
|
|
461
|
+
### 1. Write a draft
|
|
462
|
+
|
|
463
|
+
Use `okstra-quick-input.template.md` to organize notes quickly.
|
|
464
|
+
|
|
465
|
+
### 2. Write a formal brief
|
|
466
|
+
|
|
467
|
+
Organize the final input as `okstra-task-brief.md`.
|
|
468
|
+
If you plan to continue the same task later, keep the same `task-group` and `task-id`.
|
|
469
|
+
|
|
470
|
+
### 2.5. Triage requirements if needed
|
|
471
|
+
|
|
472
|
+
If you first need to classify whether the request is a bug fix or new feature, or determine whether the requirements are sufficient, set `Task Type: requirements-discovery` in the same `okstra-task-brief.md` and run it.
|
|
473
|
+
This stage does not automatically execute later phases. It only records the work category and next recommended phase in task lifecycle metadata.
|
|
474
|
+
|
|
475
|
+
```bash
|
|
476
|
+
scripts/okstra.sh --task-type requirements-discovery --project-id <project-id> --task-group <task-group> --task-id <task-id> --task-brief <brief-path>
|
|
477
|
+
```
|
|
478
|
+
|
|
479
|
+
### 3. Render-only validation
|
|
480
|
+
|
|
481
|
+
```bash
|
|
482
|
+
scripts/okstra.sh --render-only --task-type error-analysis --project-id <project-id> --task-group <task-group> --task-id <task-id> --task-brief <brief-path>
|
|
483
|
+
```
|
|
484
|
+
|
|
485
|
+
### 4. Run Claude
|
|
486
|
+
|
|
487
|
+
There are two entry methods, and they produce identical artifacts.
|
|
488
|
+
|
|
489
|
+
**Option A — launch a new Claude process (`okstra.sh`)**
|
|
490
|
+
|
|
491
|
+
```bash
|
|
492
|
+
scripts/okstra.sh --task-type error-analysis --project-id <project-id> --task-group <task-group> --task-id <task-id> --task-brief <brief-path>
|
|
493
|
+
```
|
|
494
|
+
|
|
495
|
+
On this path, `okstra.sh` finishes the prepare stage and then runs a new interactive Claude session via `exec` from the target project root. It performs only the handoff; the Claude lead continues by saving the final report. Because `sessions/claude-resume-<task-type>-<seq>.sh` is written immediately before execution, the same run can be resumed if the session is interrupted.
|
|
496
|
+
|
|
497
|
+
**Option B — hand off within the current Claude session (`okstra-run` skill)**
|
|
498
|
+
|
|
499
|
+
If you are already using a Claude Code session, the current session can assume the Claude lead role without launching a new process. Example triggers: `"run okstra here"`, `"start error-analysis on this project"`.
|
|
500
|
+
|
|
501
|
+
Skill flow:
|
|
502
|
+
|
|
503
|
+
1. The `okstra-run` skill activates and collects task candidates / task type / brief path with `AskUserQuestion`.
|
|
504
|
+
2. It calls `okstra_ctl.run.prepare_task_bundle(render_only=True)` with the user's input—directly invoking the same Python function without passing through `okstra.sh`.
|
|
505
|
+
3. After the same instruction-set artifacts are written to disk, the current Claude reads the prompt and assumes the lead role.
|
|
506
|
+
|
|
507
|
+
See [`skills/okstra-run/SKILL.md`](../skills/okstra-run/SKILL.md) for the detailed procedure.
|
|
508
|
+
|
|
509
|
+
### 5. Analyze errors if needed
|
|
510
|
+
|
|
511
|
+
```bash
|
|
512
|
+
scripts/okstra.sh --task-type error-analysis --project-id <project-id> --task-group <task-group> --task-id <task-id> --task-brief <brief-path>
|
|
513
|
+
```
|
|
514
|
+
|
|
515
|
+
After the first entry, use the abbreviated form for additional runs of the same task:
|
|
516
|
+
|
|
517
|
+
```bash
|
|
518
|
+
scripts/okstra.sh --task-key <project-id>:<task-group>:<task-id> --task-type error-analysis
|
|
519
|
+
```
|
|
520
|
+
|
|
521
|
+
### 5.5. Rerun immediately after answering
|
|
522
|
+
|
|
523
|
+
If you need to fill answers into Section 5 of a `requirements-discovery` or `error-analysis` final report, handle the edit and rerun in one operation rather than carrying the path manually.
|
|
524
|
+
|
|
525
|
+
```bash
|
|
526
|
+
scripts/okstra.sh --resume-clarification --task-key <project-id>:<task-group>:<task-id>
|
|
527
|
+
```
|
|
528
|
+
|
|
529
|
+
The latest final report opens in `$EDITOR`, and after saving, the same phase reruns automatically with the report carried in through `--clarification-response`.
|
|
530
|
+
|
|
531
|
+
#### Incremental re-verification (implementation-planning reruns only)
|
|
532
|
+
|
|
533
|
+
The default for an `implementation-planning` clarification rerun is **full re-verification**. However, if an answer has only local impact and the code is unchanged, the lead re-verifies only the downstream closure of affected stages and carries forward the other stages' plan-item verdicts from the previous run. The decision is split between deterministic CLI logic and lead judgment.
|
|
534
|
+
|
|
535
|
+
- **C1 (CLI decision, deterministic)**: The `executorWorktree.baseRef` in the previous run's `state/active-run-context-implementation-planning-<prev-seq>.json` must match the current run's base-ref SHA. If they differ, the code changed, so the result is immediately `full`.
|
|
536
|
+
- **C2 (lead judgment)**: The set of Stage Map stage numbers affected by the answer. Never include a number not in the Stage Map. If the mapping is uncertain or the answer reverses the selected Option/approach, pass an **empty set** and fall back to `full`.
|
|
537
|
+
- **Closure cutoff**: `okstra incremental-scope` calculates the `downstream_stage_closure` of affected stages in the `implementationPlanning.stageMap` dependency graph. If its size is **more than half** of all stages, the result is `full`; otherwise it outputs `{mode, reverify_stages, carry_stages, reason}` JSON.
|
|
538
|
+
|
|
539
|
+
```bash
|
|
540
|
+
okstra incremental-scope --prev-data <prev data.json> --cur-base-sha <sha> --prev-base-sha <sha> --impacted 2,3
|
|
541
|
+
okstra incremental-carry --prev-data <prev data.json> --cur-data <cur data.json> --prev-seq <prev-seq> --out <cur data.json>
|
|
542
|
+
```
|
|
543
|
+
|
|
544
|
+
When `mode == "incremental"`, worker dispatch is narrowed to `reverify_stages` (see *Cross-verification mode* in `prompts/profiles/implementation-planning.md`), and workers do not reopen or rejudge `carry_stages`. After the rerun, `okstra incremental-carry` merges plan-item verdicts missing from the current run from the previous run and adds a `carriedForwardFromSeq` tag. If the two runs have different `schemaVersion` values, it exits nonzero with `CarryError` and falls back to full. If a reverified stage concludes that a plan item must be **deleted**, that indicates nonlocal impact and likewise triggers a full rerun. `verdictCard` / `finalVerdict` are never carried and are recomputed on every run.
|
|
545
|
+
|
|
546
|
+
The report writer records the decision unchanged in `implementationPlanning.incrementalDecision` in data.json, and the renderer exposes it as a `### 0.1 Incremental Re-Verification Scope` audit block. The source procedure is the §"Incremental re-verification" section of `prompts/launch.template.md`.
|
|
547
|
+
|
|
548
|
+
### 6. Review the implementation plan if needed
|
|
549
|
+
|
|
550
|
+
```bash
|
|
551
|
+
scripts/okstra.sh --task-type implementation-planning --workers claude,codex --project-id <project-id> --task-group <task-group> --task-id <task-id> --task-brief <brief-path>
|
|
552
|
+
```
|
|
553
|
+
|
|
554
|
+
Abbreviated form for a later phase (if the manifest's `workflow.nextRecommendedPhase` is `implementation-planning`, `--task-type` may also be omitted):
|
|
555
|
+
|
|
556
|
+
```bash
|
|
557
|
+
scripts/okstra.sh --task-key <project-id>:<task-group>:<task-id> --workers claude,codex
|
|
558
|
+
```
|
|
559
|
+
|
|
560
|
+
### 7. Implement from the approved plan
|
|
561
|
+
|
|
562
|
+
Run only when the YAML frontmatter `approved` field in the `implementation-planning` final report is `true`. The approved plan path must be carried in through `--approved-plan`; if the plan is missing or its frontmatter is not `approved: true`, the run is rejected as `contract-violated`.
|
|
563
|
+
|
|
564
|
+
Approval format (code truth: `APPROVED_FRONTMATTER_PATTERN` in `scripts/okstra_ctl/run.py`):
|
|
565
|
+
|
|
566
|
+
- Exactly one line inside the final report's leading `---` YAML fence: `approved: true` or `approved: false`
|
|
567
|
+
- Case-insensitive. The report writer always publishes `approved: false`; implementation becomes available after the user toggles it to `true`
|
|
568
|
+
|
|
569
|
+
To treat the CLI invocation itself as approval without editing the approval line directly, add the `--approve` flag. okstra toggles the `approved` field in the `--approved-plan` file's frontmatter to `true`, appends an audit line, and continues into the implementation phase (the former `--ack-approved` alias was removed in 0.8.0). See [`docs/kr/cli.md`](cli.md#--approve) for details.
|
|
570
|
+
|
|
571
|
+
```bash
|
|
572
|
+
scripts/okstra.sh --task-type implementation --workers claude,codex,antigravity --project-id <project-id> --task-group <task-group> --task-id <task-id> --task-brief <brief-path> --approved-plan <runs/implementation-planning/.../reports/final-report.md>
|
|
573
|
+
```
|
|
574
|
+
|
|
575
|
+
Abbreviated form:
|
|
576
|
+
|
|
577
|
+
```bash
|
|
578
|
+
scripts/okstra.sh --task-key <project-id>:<task-group>:<task-id> --task-type implementation --workers claude,codex,antigravity --approved-plan <runs/implementation-planning/.../reports/final-report.md>
|
|
579
|
+
```
|
|
580
|
+
|
|
581
|
+
### 8. Run the final review after implementation
|
|
582
|
+
|
|
583
|
+
```bash
|
|
584
|
+
scripts/okstra.sh --task-type final-verification --project-id <project-id> --task-group <task-group> --task-id <task-id> --task-brief <brief-path>
|
|
585
|
+
```
|
|
586
|
+
|
|
587
|
+
Abbreviated form:
|
|
588
|
+
|
|
589
|
+
```bash
|
|
590
|
+
scripts/okstra.sh --task-key <project-id>:<task-group>:<task-id> --task-type final-verification
|
|
591
|
+
```
|
|
592
|
+
|
|
593
|
+
### 9. Resume the same task
|
|
594
|
+
|
|
595
|
+
When reopening the same bugfix or workstream, use the same `task-group` and `task-id`.
|
|
596
|
+
History then continues accumulating in `runs/` and `history/timeline.json` under the existing task root.
|
|
597
|
+
After the first entry, the abbreviated `--task-key <p>:<g>:<i>` form is the most concise; missing brief/task-type values are populated automatically from the manifest.
|
|
598
|
+
|
|
599
|
+
## Lifecycle status and resume
|
|
600
|
+
|
|
601
|
+
For long-running work, the `workflow` object in `task-manifest.json` is the canonical lifecycle state.
|
|
602
|
+
Checking the following fields first makes it easy to determine the current position and resume point:
|
|
603
|
+
|
|
604
|
+
- `workflow.currentPhase`
|
|
605
|
+
- `workflow.currentPhaseState`
|
|
606
|
+
- `workflow.phaseStates`
|
|
607
|
+
- `workflow.lastCompletedPhase`
|
|
608
|
+
- `workflow.nextRecommendedPhase`
|
|
609
|
+
- `workflow.awaitingApproval`
|
|
610
|
+
- `workflow.routingStatus`
|
|
611
|
+
- `workflow.lastSafeCheckpoint`
|
|
612
|
+
- `phaseOutcome`
|
|
613
|
+
|
|
614
|
+
Use `.okstra/discovery/task-catalog.json` to review project-wide state.
|
|
615
|
+
For the latest state of a specific task, check `.okstra/discovery/latest-task.json`, `task-manifest.json`, the latest `run-manifest`, and `history/timeline.json`, in that order.
|
|
616
|
+
|
|
617
|
+
In Claude, use the `status` subflow of the seeded `okstra-inspect` skill to answer questions such as:
|
|
618
|
+
|
|
619
|
+
- Show all okstra task statuses
|
|
620
|
+
- Show the current phase and next phase for a specific `task-key`
|
|
621
|
+
- Show tasks awaiting approval and tasks that can be resumed
|
|
622
|
+
- Update `<task-id>`'s `workStatus` to `todo` / `in-progress` / `blocked` / `done` (for example, "okstra mark <task-id> done", "mark <task-id> in progress")—the skill updates `workStatus`, `workStatusUpdatedAt`, and `workStatusNote` in the corresponding `task-manifest.json`.
|
|
623
|
+
|
|
624
|
+
Resume decision rules:
|
|
625
|
+
|
|
626
|
+
- Resume the current run: if `latestResumeCommandPath` exists, use that path first.
|
|
627
|
+
- Restart the current phase: run again with the same `task-key` and current `task-type`.
|
|
628
|
+
- Start the next phase: if `workflow.nextRecommendedPhase` is a concrete phase, prepare the next `okstra.sh` run with that value.
|
|
629
|
+
- Additional material required: if `routingStatus=pending` or `nextRecommendedPhase=pending-routing-decision`, augment the brief first.
|
|
630
|
+
|
|
631
|
+
## Final report structure
|
|
632
|
+
|
|
633
|
+
The default final report template is `templates/reports/final-report.template.md`.
|
|
634
|
+
Final reports written by Claude should use the following structure unless the brief's augmentation requires a more specific format.
|
|
635
|
+
|
|
636
|
+
- `## Verdict Card` — **mandatory top section**. Five rows: Final Conclusion / Verdict Token / Direction / Approval Required? / Next Step. The Verdict Token / Direction / Next Step cells must byte-match the authoritative cells in body §2 (execution status) and §6 (next steps).
|
|
637
|
+
- (Optional) `## Reader Summary` — a five-row table rendered immediately below the Verdict Card only when data.json has `readerSummary`: decision (`decision`) / action required from a human (`humanActionRequired`) / blocking items (`blockingItems`) / safe-to-skip items (`safeToSkip`) / recommended command (`recommendedCommand`). When present, all five fields are required (schema `required`), and it contains only a summary rather than repeating raw evidence tables. Older data.json files without it continue to render unchanged.
|
|
638
|
+
- `## Background and Rationale` — **mandatory for every task type** (data.json `rationale`). Reviewer-oriented prose that answers four questions in order: Why are we doing this (`motivation`)? / Why is it a problem (`problem`)? / What work is therefore needed (`approach`)? / Why is this a reasonable choice (`justification`)? It is prose, not a table. Every field must contain either an evidence reference such as `path:line`, a report ID (`C-001`), or `§5.4`, or an explicit insufficiency marker (`insufficient evidence`). `_validate_rationale_evidence` in `validators/validate-run.py` fails any field that has neither.
|
|
639
|
+
- (Optional) `## 0. Clarification Response Carried In From Previous Run` — rendered only when a response was carried in from the previous run. The heading itself is omitted for an empty carry-in.
|
|
640
|
+
- (Optional) `### 0.1 Incremental Re-Verification Scope` — rendered only when data.json contains `implementationPlanning.incrementalDecision`. When `mode == "incremental"`, the `Re-verified stages` and `Carried-forward stages` rows are mandatory, and `validators/validate-run.py` blocks their absence as `contract-violated`. Carried plan items record the run in which they were verified with a `carriedForwardFromSeq` tag.
|
|
641
|
+
- `## 1. Problem or Verification Target Summary` — preserves the `Source items (worker:item)` column in both the §6.1 Consensus and §6.2 Differences tables for cross-worker traceability.
|
|
642
|
+
- `## 2. Agent Execution Status`
|
|
643
|
+
- `## 3. Cross-Verification Results` — §2.1 Primary Evidence contains the `Source items (worker:item)` and `Source (path:line / log)` columns.
|
|
644
|
+
- `## 4. Final Assessment` — emits §5.5.9 Plan Body Verification for `implementation-planning` grouped by plan item: the item's `subject` (a one-line description of what was verified) becomes the heading, followed by a per-worker `Worker / Verdict / Breakage kind / Note` table. It also renders three legends: gate values, verdict tokens, and breakage kinds (a–f).
|
|
645
|
+
- `## 1. Clarification Items` — a single consolidated eight-column table. The former §6.1 / §6.2 / §5.5.8 / §5.5.9 Open Questions are deprecated, and the validator fails if they appear.
|
|
646
|
+
- `## 6. Recommended Next Steps`
|
|
647
|
+
- `## Token Usage Summary` — the validator blocks publication if sentinel (`pending` / `N/A` / `--` / `?` / empty cell) or zero (`0` / `$0.00`) values are frozen into the report. Only the `Codex/Antigravity CLI Add-on` row may use `$0.00` to mean "CLI not used."
|
|
648
|
+
|
|
649
|
+
The `## 0. Reading Confirmation` block from worker output is written to the sidecar at the resolved `<run-dir>/worker-results/<worker>-audit-<task-type>-<seq>.md`, not included in the report body (enforced by the validator).
|
|
650
|
+
|
|
651
|
+
If there are no substantive differences, state that fact rather than manufacturing a contrast.
|
|
652
|
+
Write the actual Markdown report body to the file instead of metadata about save failures or session limitations.
|
|
653
|
+
|
|
654
|
+
## Final report views (HTML)
|
|
655
|
+
|
|
656
|
+
Phase 7 step 1.5 deterministically generates a self-contained HTML view from a single final-report MD input.
|
|
657
|
+
|
|
658
|
+
- `reports/final-report-<task-type>-<seq>.html` — self-contained HTML for human reviewers. CSS / JS are embedded inline (zero external URLs), with system-color dark mode, sticky header, and print support. Reviewers can fill in decision inputs for §1 `C-*` rows—checkboxes, selects, and textareas—in the browser, then generate sidecar Markdown with the `Export user response` button.
|
|
659
|
+
- **Reader Summary dashboard + reader mode**: Renders a top-level dashboard based on `readerSummary` (falling back to `verdictCard` when absent) and offers `Action` / `Audit` / `Full` reader-mode toggles. The default is `Action`, which shows only Reader Summary / Verdict Card / Clarification Items / Recommended Next Steps / Follow-up Tasks. Audit sections such as Evidence, Cross Verification, Execution Status, Token Usage, Plan Body Verification, and Round History are expanded in `Audit` / `Full`.
|
|
660
|
+
- **`C-*` select option order**: The `Recommended:` answer from `Expected form` is always the **first option**, followed by the `Alternatives:` items relabelled consecutively as `(a)`, `(b)`, and so on (the original character labels are not retained).
|
|
661
|
+
|
|
662
|
+
Entry points:
|
|
663
|
+
|
|
664
|
+
- Single Python reference: `scripts/okstra_ctl/report_views.py` (`build_report_view_model(...)`, `render_report_view_model(..., css, js)`, `render_html(..., css, js)`, `serialize_user_response(...)`). The HTML JavaScript function `buildUserResponseMarkdown` is **byte-identical** to Python `serialize_user_response` (automatically verified by a Node `vm.runInThisContext` unit test).
|
|
665
|
+
- CLI: `scripts/okstra-render-report-views.py <final-report.md>` or delegated Node wrapper `bin/okstra render-views <md>`.
|
|
666
|
+
- Validation: `validators/validate-report-views.py` checks form-control placement in the HTML, absence of external URLs, stale source digests, and Response ID parity (`C-*` ↔ HTML).
|
|
667
|
+
- User-response sidecar schema source of truth: `templates/reports/user-response.template.md`.
|
|
668
|
+
|
|
669
|
+
Generating a view never modifies the original final-report MD.
|
|
670
|
+
|
|
671
|
+
## Worker error collection (optional sidecar)
|
|
672
|
+
|
|
673
|
+
Errors that occur while workers (Claude/Codex/Antigravity worker, Report writer, Claude lead) run can be collected into a single chronological log for later retrospectives.
|
|
674
|
+
|
|
675
|
+
- Storage location: resolved `<run-dir>/logs/errors-<task-type>-<seq>.jsonl` (`<run-dir>` includes `stage-<N>/` for a stage-isolated run)
|
|
676
|
+
- Append-only JSON Lines, isolated per run, so there is no separate rotation policy.
|
|
677
|
+
- **Single writer**: To avoid concurrent-append collisions, only the `Claude lead` writes this file directly. `<seq>` is an independent three-digit zero-padded counter (`001`, `002`, …) scanned per category directory (`logs/`, `manifests/`, `state/`, and so on), so category values may differ within one run when a prior run recorded only some categories. The cross-category identifier for one run is the manifest's `runDateTimeSegment` ISO timestamp field.
|
|
678
|
+
- Internal worker tool failures are reported in the worker-result manifest's `errors[]`, then dumped by the lead immediately after merge
|
|
679
|
+
- Codex/Antigravity CLI failures, timeouts, and rate limits are observed directly by the lead through the wrapper
|
|
680
|
+
- resultContract violations, schema mismatches, and missing required fields are observed directly during lead validation
|
|
681
|
+
- The `source` field (`worker-reported` | `lead-observed`) distinguishes the origin, and `errorType` (`tool-failure` | `cli-failure` | `contract-violation`) distinguishes the type.
|
|
682
|
+
- `stderrExcerpt` is capped at 2 KB for one-line jsonl readability and protected by the `PIPE_BUF` (4096B) atomic-append guard.
|
|
683
|
+
- The `errorsLogPath` field in run-manifest or team-state records `logs/errors-<task-type>-<seq>.jsonl` once, relative to the resolved run directory, so it can be discovered.
|
|
684
|
+
- Path-delivery wiring (`f6f9f69`): `scripts/okstra_ctl/paths.py` exports `RUN_ERRORS_LOG_FILE` / `RUN_ERRORS_LOG_RELATIVE_PATH` and per-worker sidecar paths, while `scripts/okstra_ctl/render.py` exposes the `{{RUN_ERRORS_LOG_PATH}}` / `{{<WORKER>_ERRORS_SIDECAR_PATH}}` template tokens. The `## Run Logs (error-log wiring)` section of `prompts/launch.template.md` passes the resolved absolute path to the lead, which must forward it in the `**Errors log path:**` / `**Errors sidecar path:**` lines of the worker dispatch prompt. Path delivery became a formal contract after a regression in which a worker with only the literal `<runDir>/logs/...` template fragment dropped an entry through argparse exit.
|
|
685
|
+
- Helper CLI: `scripts/okstra-error-log.py`
|
|
686
|
+
- Appends records through a single entry point.
|
|
687
|
+
- Both worker-sidecar dumps (`append_observed`, guarded by schema version) and lead observations (`lead-observed`) use the same helper.
|
|
688
|
+
|
|
689
|
+
### Live-log mirror (codex / antigravity wrapper)
|
|
690
|
+
|
|
691
|
+
- On every dispatch, `scripts/okstra-codex-exec.sh` and `scripts/okstra-antigravity-exec.sh` create a `<prompt>.log` sidecar next to the prompt path and mirror stdout there (`tee`, preserving the exit code with `PIPESTATUS[0]`). stderr is appended to the same file, preserving the subagent stderr-capture contract, and the file is truncated on each dispatch. This solves the problem where a calling subagent polls `BashOutput` every 60 seconds, leaving users unable to detect a stalled state during long-running work such as large-codebase scans in analysis or cargo / pytest in implementation.
|
|
692
|
+
- When tmux is reachable in the lead environment, the wrapper automatically splits a sibling pane and runs `tail -F <log-path>`. The trace-pane title appends `-tail` to the caller (worker) pane title: `<cli>-<role>-<pid>-tail` (for example, `codex-worker-93421-tail`). At the same time, the caller (worker) pane title is set to `<cli>-<role>-<pid>`. `<pid>` is the wrapper's own PID, so multiple workers with the same role spawned concurrently remain distinguishable, and operators can visually map `<caller> ↔ <caller>-tail`. **Caller-pane resolution**—because the Claude Code Bash tool now removes both `$TMUX` and `$TMUX_PANE` from the environment, the wrapper does not depend on environment variables. It (1) derives `<RUN_DIR>` as `dirname(dirname(prompt_path))` from the prompt path (paths.py SSOT), and (2) reads `<RUN_DIR>/state/lead-pane.id`, written once by the lead in its foreground pane, as the split anchor. This remains reliable for background dispatches, unlike active-pane guessing, even if the user changes panes. If the file is absent or the pane is stale, it falls back to `tmux display-message -p '#{pane_id}'` (the active pane). The trace split explicitly anchors to that caller pane with `-t`. The role is the wrapper's fifth optional positional argument and defaults to `worker`. The caller pane title is captured and restored by an EXIT trap, preventing stale titles across dispatches. Focus returns to the caller pane, and the trace pane remains after CLI exit so its scrollback is available. All paths silently degrade when tmux is unreachable, splitting fails, or tmux is outdated.
|
|
693
|
+
- **Run-scoped tagging for cleanup**: A trace pane's `tail -F` is a child of the tmux shell and survives Claude's exit. The wrapper tags each spawned pane with `tmux set-option -p @okstra_trace_run=<RUN_DIR>`, and `okstra-trace-cleanup.sh` discovers panes server-wide from that tag via `tmux list-panes -a` and runs `tmux kill-pane`. It requires neither tmux environment variables nor a pane-ID registry. Because the tag is run-scoped, it does not kill trace panes from other simultaneous okstra runs. Cleanup has two entry forms: the lead invokes it with `--run-dir <RUN_DIR>` to clean traces and worker-agent panes for that run, or the `hooks.SessionEnd` entry in `templates/reports/settings.template.json` invokes it with `--reap` to clean all trace panes tagged below `$CLAUDE_PROJECT_DIR/.okstra/` when no single run directory exists at session end. Missing tmux and stale pane IDs silently degrade.
|
|
694
|
+
- **Automatic cleanup on phase transitions, including worker-agent panes**: `okstra-trace-cleanup.sh --run-dir <RUN_DIR>` closes not only tagged trace panes but also worker-agent panes occupied by dispatched subagents. These harness-owned panes cannot be tagged, so the script identifies them within the lead session (`tmux list-panes -s -t <lead-pane>`) through a title allowlist: `claude-worker` / `codex-worker` / `antigravity-worker` / `report-writer-worker`. Implementation role titles such as `claude-executor` / `codex-verifier` / `agy-executor-tail`, and FleetView teammate prefixes `✳ ` / `⠂ `, are also treated as okstra panes. Session scoping and exclusion of the lead's own pane are determined by `<RUN_DIR>/state/lead-pane.id`; the lead pane is never killed even if its title matches. Immediately before dispatching workers for a new phase (before the `PROGRESS: phase-5.5-convergence` / `phase-6-synthesis` marker), the lead calls this script with `--run-dir` to clean previous-phase panes without prompting.
|
|
695
|
+
- **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.
|
|
696
|
+
- 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.
|
|
697
|
+
|
|
698
|
+
### Linked-worktree `.git/` write permissions (codex / antigravity)
|
|
699
|
+
|
|
700
|
+
- 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.
|
|
701
|
+
- The wrapper resolves the main repository's absolute `.git/` path with `git -C <worktree> rev-parse --git-common-dir` from inside the worktree, then forwards it to the sandbox by appending `--add-dir <main-repo>/.git` (Codex) or `--include-directories <main-repo>/.git` (Antigravity).
|
|
702
|
+
|
|
703
|
+
## Token usage and cost accounting
|
|
704
|
+
|
|
705
|
+
Tokens used in each run are collected from lead/worker session transcripts and written back to `leadUsage` / `workers[].usage` in `team-state.json`.
|
|
706
|
+
|
|
707
|
+
- Helper CLI: `scripts/okstra-token-usage.py`
|
|
708
|
+
- Collection sources:
|
|
709
|
+
- Claude lead/workers: per-message `message.usage` in `~/.claude/projects/<cwd-as-dashes>/<sessionId>.jsonl` or `~/.claude/projects/<cwd-as-dashes>/<lead-session>/subagents/agent-a<worker-name>-<hash>.jsonl`. Worker names are recovered from nested-subagent filenames, and only the directory for the current run's `team-state.lead.sessionId` is counted.
|
|
710
|
+
- Codex CLI: final `total_token_usage.total_tokens` in `~/.agent/sessions/Y/M/D/rollout-*.jsonl`
|
|
711
|
+
- Antigravity CLI: per-message `tokens.total` in `~/.antigravity/tmp/*/chats/session-*.json`
|
|
712
|
+
- Records billable-equivalent token math and USD cost estimates. It applies Anthropic billing ratios (`cache_creation_5m=1.25x`, `cache_creation_1h=2.0x`, `cache_read=0.1x`, `output=5x`). When the transcript provides separate `usage.cache_creation.ephemeral_5m_input_tokens` / `ephemeral_1h_input_tokens` values, they are counted separately.
|
|
713
|
+
- Pricing is centrally managed in `scripts/okstra_token_usage/pricing.py`. Update it when model prices change. Model IDs that fail price matching are exposed to the user in `usageSummary.unmatchedModels`, preventing silent-zero incidents.
|
|
714
|
+
- **Incremental scan cache (P6)**: To avoid rescanning session jsonl files, a per-file byte cursor and the extracted usage events before windowing are stored in `$OKSTRA_HOME/cache/token-usage/<transcript-dir>/<sessionId>.json` (`scripts/okstra_token_usage/cursor.py`). The run window (since/until) is reevaluated over events on every invocation, so even if a rerun narrows the window, the total matches a full scan. The cache is derived data; identifier mismatch, truncation, or corruption automatically falls back to a full rescan, and `okstra-token-usage.py --no-cache` forces a bypass.
|
|
715
|
+
- **Phase timeline (P0 instrumentation)**: The collector extracts `PROGRESS: phase-*` checkpoint lines (see "Progress reporting" in prompts/lead/okstra-lead-contract.md) from the lead session jsonl scoped to the run window, and records them in team-state as a `phaseTimeline` block (`{source, phases: [{phase, firstAt, lastAt, markerCount, wallMsToNext}]}`) (`scripts/okstra_token_usage/collect.py :: phase_timeline`). This provides measurement points for per-phase wall-clock time within the run and is consumed by the "Per-run phase breakdown" in the `okstra-inspect` time facet. Runs without markers explicitly report that measurement is unavailable with `phases: []`.
|
|
716
|
+
|
|
717
|
+
## Validators
|
|
718
|
+
|
|
719
|
+
Entry points that enforce whether phase artifacts may be published:
|
|
720
|
+
|
|
721
|
+
- `validators/validate-workflow.sh` — integrated phase-contract validation.
|
|
722
|
+
- `validators/validate-run.py` — run-level final-report body contract: requires a Verdict Card; enforces evidence anchors in all four `rationale` fields (`_validate_rationale_evidence`); rejects deprecated §6.1/§6.2/§5.5.8/§5.5.9 Open Questions; cross-checks Plan Body Verification gate × Approval markers; blocks Token Usage sentinel/zero values; requires worker-result audit sidecars; requires the incremental re-verification audit block (`_check_incremental_audit_block`—when data.json has `incrementalDecision.mode == "incremental"`, `### 0.1 Incremental Re-Verification Scope` plus `Re-verified stages` / `Carried-forward stages` rows are mandatory).
|
|
723
|
+
- `validators/validate-report-views.py` — checks form-control placement in the self-contained HTML view, absence of external URLs, stale source digests, and Response ID parity (`C-*` ↔ HTML).
|
|
724
|
+
- `validators/validate-brief.py` — enforces the brief schema (frontmatter, presence of `Reporter Confirmations`, root parent-id self rule, slug conventions, and so on). `bash validators/validate-brief.sh <brief.md>` is a thin wrapper.
|
|
725
|
+
|
|
726
|
+
Each validator blocks the phase with a `contract-violated` exit code when a contract is breached. Violations are applied when the next phase executes, leaving prior artifacts unchanged.
|
|
727
|
+
|
|
728
|
+
`contractValidation.status=failed` means the run artifact contract failed; it does not necessarily mean the implementation itself is incomplete. An implementation run derives `phaseOutcome.implementation` from `runs/implementation/stage-<N>/carry/stage-<N>.json`, `runs/implementation-planning/consumers.jsonl`, and the approved Stage Map together. If every Stage Map stage has pass-grade carry evidence, it can retain the contract failure as audit information while correcting `workflow.nextRecommendedPhase` to `final-verification`.
|
|
729
|
+
|
|
730
|
+
## Practical notes
|
|
731
|
+
|
|
732
|
+
- `okstra` is not the old brief-less workflow.
|
|
733
|
+
- The brief is the canonical analysis input. Include additional material inline or by path in the brief's `Evidence and Source Materials` section; there is no separate CLI option for supplementary material.
|
|
734
|
+
- The brief's `Configuration References and Expected Values` and `Deployment Manifests and Expected Values` sections are the canonical source for task-specific expected state.
|
|
735
|
+
- `task-type` also determines profile selection.
|
|
736
|
+
- `--render-only` is for dry-run validation, but it still creates the task bundle and run manifest.
|
|
737
|
+
- The default execution mode is interactive handoff, not Claude print-mode collection.
|
|
738
|
+
- The default final report template is rendered to the task bundle's `instruction-set/final-report-template.md`.
|
|
739
|
+
- The task bundle's `instruction-set/reference-expectations.md` is generated alongside it as the config/deployment expected-state reference.
|
|
740
|
+
- The current run session's resume helper is created at the resolved `<run-dir>/sessions/claude-resume-<task-type>-<seq>.sh`.
|
|
741
|
+
- The run directory is organized into typed subdirectories such as `manifests/`, `state/`, `prompts/`, `reports/`, `status/`, `sessions/`, and `worker-results/`; prompt snapshots are prepared under `prompts/` first.
|
|
742
|
+
- Claude creates workers and collects results.
|
|
743
|
+
- The standard workflow uses a `Claude lead` with default workers `Claude worker`, `Codex worker`, and `Report writer worker`; `Antigravity worker` is optional and included only when explicitly requested.
|
|
744
|
+
- Worker models can be overridden with `--lead-model`, `--claude-model`, `--codex-model`, `--antigravity-model`, and `--report-writer-model`; defaults are centrally managed through `OKSTRA_DEFAULT_*` environment variables. Fallback defaults are `Claude lead`/`Report writer worker`=`opus`, `Claude worker`=`opus`, `Codex worker`=`gpt-5.5`, and `Antigravity worker`=`auto`.
|
|
745
|
+
- For `--task-type implementation`, select the provider that takes the Executor role with `--executor <claude|codex|antigravity>` (or `OKSTRA_DEFAULT_EXECUTOR`, fallback `claude`). Only the Executor may mutate project files. The other two providers and the Executor's own provider are each dispatched as verifiers in separate CLI sessions (session isolation preserves the self-review safeguard). The Executor's model reuses the selected provider's worker-model flag (`--claude-model` / `--codex-model` / `--antigravity-model`). Provider / displayName / workerAgent / model are recorded in the run-manifest `teamContract.executor` block.
|
|
746
|
+
- Worktree cwd injection by Executor: Codex / Antigravity executors pin cwd to the worktree at the CLI layer through wrappers (`okstra-codex-exec.sh -C` / `okstra-antigravity-exec.sh --include-directories`). Because the Bash tool has no per-call cwd argument, the Claude executor prefixes cwd-sensitive toolchain invocations (`cargo`/`npm`/`pnpm`/`bun`/`pytest`/`make`/`go`) with `cd {{EXECUTOR_WORKTREE_PATH}} && <cmd>` in the same Bash invocation. Wrapping in `bash -lc`/`bash -c` is prohibited because it hides the leading `cd` token and defeats permission auto-allow. Prefer working-directory flags such as `git -C` or `cargo --manifest-path` when available. See the *Executor Worktree* block in `prompts/profiles/implementation.md` and the Executor exception in `agents/workers/claude-worker.md` for details.
|
|
747
|
+
- The project-level current-task convenience pointer is `.okstra/discovery/latest-task.json`.
|
|
748
|
+
- The project-level canonical task inventory is `.okstra/discovery/task-catalog.json`.
|
|
749
|
+
- At `okstra install` time, okstra skill assets are seeded to `~/.agents/skills/` by default. If `~/.claude` exists, `~/.claude/skills/` + `~/.claude/agents/` are seeded as well (per-project seeding is no longer performed).
|
|
750
|
+
- Seeded okstra Claude assets instruct Claude to dispatch workers into the session's implicit team with `Agent(name: ...)` (v2.1.178 removed `TeamCreate`/`TeamDelete`). Agent targets receive only skill Markdown.
|
|
751
|
+
- Claude, not scripts, makes the final judgment.
|
|
752
|
+
- A stable task key must be maintained to enable later bug tracking, corrections, and reverification.
|
|
753
|
+
- Worker errors are collected in the optional sidecar at the resolved `<run-dir>/logs/errors-<task-type>-<seq>.jsonl`, with the lead as the sole writer. For a stage-isolated run, `<run-dir>` includes `stage-<N>/`. The entry-point helper is `scripts/okstra-error-log.py`.
|
|
754
|
+
- Token-usage and cost accounting are handled by `scripts/okstra-token-usage.py` and the Node wrapper `okstra token-usage`.
|
|
755
|
+
- `okstra.sh` requires an absolute projectRoot to anchor worker CLI calls.
|
|
756
|
+
- `okstra wizard step` **requires** `--answer <val>`. To peek at the next prompt when it is not time to respond, use `--no-submit`.
|
|
757
|
+
- `/okstra-inspect history` supports task-manifest fallback / pagination / filters, and resolves `--base-ref` from the worktree registry.
|
|
758
|
+
- All writes to the user's project occur only inside `<PROJECT_ROOT>/.okstra/` (see the Artifact-home rule).
|
|
759
|
+
|
|
760
|
+
## Related documents
|
|
761
|
+
|
|
762
|
+
- `README.md`
|
|
763
|
+
- `templates/reports/task-brief.template.md`
|
|
764
|
+
- `templates/reports/final-report.template.md`
|
|
765
|
+
- `prompts/lead/okstra-lead-contract.md`
|
|
766
|
+
- `scripts/okstra-error-log.py`
|
|
767
|
+
- `scripts/okstra-token-usage.py`
|
|
768
|
+
|
|
769
|
+
|
|
770
|
+
---
|
|
771
|
+
|
|
772
|
+
## okstra Control Center — Operating model / concurrency / environment variables
|
|
773
|
+
|
|
774
|
+
### Operating model
|
|
775
|
+
|
|
776
|
+
- At startup, `okstra.sh` invokes the `record_start` hook once to record metadata and the invocation in the indexes.
|
|
777
|
+
- Finalization is handled by lazy reconciliation invoked from every `okstra-ctl` entry point (inferred from the presence of `final-report-*.md` in the target project).
|
|
778
|
+
- A batch rerun spawns one detached tmux session per target and returns immediately (fire-and-forget). The user connects to any session with the returned attach command.
|
|
779
|
+
- The default spawn threshold is 10. Change it with `--max-spawn N` or `OKSTRA_CTL_MAX_SPAWN`.
|
|
780
|
+
- runId format: `<project-id>/<task-group>/<task-id>/<task-type>/r<run-seq>` (for example, `sample-project/payment/fail/error-analysis/r07`). Input supports prefix-substring matching.
|
|
781
|
+
|
|
782
|
+
### Concurrency control (two-level mutex)
|
|
783
|
+
|
|
784
|
+
`okstra-ctl` and the `record_start` hook use two fcntl `LOCK_EX` locks with different scopes. Their responsibilities are separate, so no deadlock occurs even when both are held.
|
|
785
|
+
|
|
786
|
+
| Lock | Location | Scope | Held during | Purpose |
|
|
787
|
+
|---|---|---|---|---|
|
|
788
|
+
| central lock | `~/.okstra/.lock` | Global (index-wide) | Writes to `active.jsonl`/`recent.jsonl`/`projects/<id>/index.jsonl` by `record_start`; reconcile / reservation writes by ctl | Serializes read-modify-write operations on index jsonl files. Prevents concurrent record_start append and reconcile rotation from leaking into each other. |
|
|
789
|
+
| task lock | `~/.okstra/.locks/<projectId>-<taskGroup>-<taskId>-<taskType>.lock` | Per task-key + task-type mutex | Entire sequence prediction + tmux spawn section of `okstra-ctl rerun` | Prevents simultaneous reruns of the same task from receiving the same run sequence and colliding on manifests/directories. Acquired outside the central lock, so reruns of different tasks do not block each other. |
|
|
790
|
+
|
|
791
|
+
Acquisition order is always `task lock` → `central lock` (ctl rerun), or `central lock` alone (record_start, reconcile). The reverse order never occurs.
|
|
792
|
+
|
|
793
|
+
`task_lock_filename` normalizes each segment to an fs-safe slug, escapes `-` as `--`, and joins with `-`. This prevents tuples such as `('p','feature-8','email','x')` and `('p','feature','8-email','x')` from colliding on the same filename and unintentionally sharing a mutex ([scripts/okstra_ctl/locks.py](../scripts/okstra_ctl/locks.py)).
|
|
794
|
+
|
|
795
|
+
### Environment variables
|
|
796
|
+
|
|
797
|
+
- `OKSTRA_HOME`: overrides the central directory location (default `~/.okstra`).
|
|
798
|
+
- `OKSTRA_CTL_MAX_SPAWN`: default threshold for concurrent rerun spawns.
|
|
799
|
+
- `OKSTRA_CTL_SKIP_BACKFILL=1`: skips automatic backfill on first invocation.
|
|
800
|
+
- `OKSTRA_CTL_SKIP_RECONCILE=1`: skips lazy reconciliation (for tests/debugging).
|
|
801
|
+
- `OKSTRA_SKIP_INSTALL_CHECK=1`: skips installation-asset checks in `verify_installation` (for tests; workspace-existence validation remains enabled).
|
|
802
|
+
- `OKSTRA_RUN_SEQ_OVERRIDE`: forces the run sequence used by okstra.sh during a rerun (injected automatically inside okstra-ctl).
|