okstra 0.1.0 → 0.3.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.
@@ -0,0 +1,256 @@
1
+ ---
2
+ name: okstra-report-writer
3
+ description: Use when okstra is in Phase 6 or Phase 7 — writing the final synthesis report, persisting artifacts, or updating manifests.
4
+ user-invocable: false
5
+ ---
6
+
7
+ # OKSTRA Report Writer
8
+
9
+ ## File-author ownership (BLOCKING)
10
+
11
+ The final-report file at `runs/<task-type>/reports/final-report-<task-type>-<seq>.md` is authored by the `Report writer worker` subagent when that worker is in the run's roster. Claude lead reviews the file but does NOT write it itself in that case. Lead-authored fallback is permitted only after a real Report writer worker dispatch attempt with a recorded non-`completed` terminal status (`error` / `timeout` / `not-run`) and a logged reason (`okstra-error-log.py`).
12
+
13
+ If you are reading this skill **as the report-writer-worker subagent**, YOU are the one calling the `Write` tool against the result path. Do not return the report inline — the file on disk is the canonical artifact.
14
+
15
+ If you are reading this skill **as Claude lead**, your job in Phase 6 is to (a) prepare the report-writer prompt, (b) dispatch the Report writer worker per the Phase 6 dispatch template in SKILL.md, (c) review the produced file in Phase 7. Do not call `Write` against the final-report path yourself when Report writer worker is in the roster.
16
+
17
+ ## When to Use
18
+
19
+ - During Phase 6 of the OKSTRA skill (final report assembly)
20
+ - During Phase 7 of the OKSTRA skill (artifact persistence — verification only when Report writer worker is in roster)
21
+ - When verifying the structure of the final report
22
+
23
+ ## Phase 6 dispatch template (Report writer worker)
24
+
25
+ Lead dispatches the report-writer worker via the Agent tool. Lead does NOT write the final-report file when this worker is in the roster.
26
+
27
+ ```text
28
+ Agent(
29
+ description: "Author final report for <task-key>",
30
+ prompt: "<report-writer prompt: see this skill + Required reading clause + Available MCP Servers section>",
31
+ name: "report-writer",
32
+ subagent_type: "report-writer-worker",
33
+ team_name: "okstra-<task-key>", # omit if team is not alive — see Resume-safe dispatch
34
+ model: "opus",
35
+ mode: "auto"
36
+ )
37
+ ```
38
+
39
+ The prompt MUST include, in this order at the top:
40
+
41
+ 1. `**Project Root:** <absolute-path>`
42
+ 2. `**Prompt History Path:** <project-relative-path>` (under current run `prompts/`)
43
+ 3. `**Result Path:** runs/<task-type>/reports/final-report-<task-type>-<seq>.md` — canonical final-report file (user-facing)
44
+ 4. `**Worker Result Path:** runs/<task-type>/worker-results/report-writer-worker-<task-type>-<seq>.md` — mandatory validator-checked worker-results audit file
45
+ 5. `Assigned worker prompt history path: <absolute-path>`
46
+ 6. `**Model:** Report writer worker, <modelExecutionValue>` (resolved per Phase 5.5 anchor-header rules)
47
+ 7. The full `[Required reading]` clause (see [okstra-team-contract](../okstra-team-contract/SKILL.md)) including `final-report-template.md`.
48
+ 8. The verbatim `## Available MCP Servers` block from the task brief, if present.
49
+ 9. The convergence classifications (Full/Partial/Contested/Worker-Unique) and pointers to all worker result files under `worker-results/`.
50
+ 10. For implementation-planning runs: a literal block listing the 8 required English section headings the validator scans for (`Option Candidates`, `Trade-off`, `Recommended Option`, `Stepwise Execution Order`, `Dependency`, `Validation Checklist`, `Rollback`, `User Approval Request`). The writer must use these exact substrings as section headings (Korean translation in parentheses is allowed).
51
+ 11. An explicit instruction: `You are the author of TWO files: (a) the final-report file at <Result Path>, (b) the worker-results file at <Worker Result Path>. Write both directly using your Write tool. Do not return the report inline. The validator fails the run when (b) is missing.`
52
+
53
+ ### Resume-safe dispatch
54
+
55
+ A resumed lead session can ALWAYS dispatch a fresh Report writer worker. The Agent tool does not require a previously created Team to be alive:
56
+
57
+ - If `TeamCreate` for `okstra-<task-key>` still succeeds (or the team is still listed), include `team_name` in the dispatch.
58
+ - If `TeamCreate` reports the name is taken or the team is gone, omit `team_name` from the dispatch — the worker still runs as a background subagent and its session is still recoverable by `agentName: "report-writer"` in `okstra-token-usage.py`.
59
+ - Do NOT skip dispatch because of any team-related error. Record the team status in team-state and proceed without `team_name`.
60
+
61
+ ### Lead-authored fallback (only if dispatch failed)
62
+
63
+ Lead-authored fallback is permitted only if all of the following are true and recorded in team-state:
64
+
65
+ 1. A Report writer worker dispatch was actually attempted (Agent call was issued).
66
+ 2. The attempt recorded a terminal status of `error`, `timeout`, or `not-run` with a concrete reason (tool error message, timeout duration, or external blocker).
67
+ 3. The reason is logged via `okstra-error-log.py append-observed --error-type cli-failure ...` (or `tool-failure` if the failure was internal).
68
+
69
+ Speculative reasons such as "session resume constraint", "team object no longer exists", or "lead can do it faster" are NOT valid.
70
+
71
+ ## Phase 7 token-usage collector (BLOCKING)
72
+
73
+ At the start of Phase 7, run the token-usage collector with the final-report substitution flag. This step is BLOCKING — both the team-state aggregation AND the final-report placeholder substitution happen here, in one invocation:
74
+
75
+ ```bash
76
+ python3 scripts/okstra-token-usage.py \
77
+ <runDirectoryPath>/state/team-state-<task-type>-<seq>.json \
78
+ --write --summary \
79
+ --substitute-final-report <runDirectoryPath>/reports/final-report-<task-type>-<seq>.md
80
+ ```
81
+
82
+ This:
83
+
84
+ - Populates `leadUsage`, every `workers[].usage`, and `usageSummary` in team-state from session transcripts.
85
+ - Substitutes the 10 token-related placeholders (`{{LEAD_TOTAL_TOKENS}}`, `{{LEAD_BILLABLE_TOKENS}}`, `{{LEAD_COST_USD}}`, `{{WORKER_TOTAL_TOKENS}}`, `{{WORKER_BILLABLE_TOKENS}}`, `{{WORKER_COST_USD}}`, `{{GRAND_TOTAL_TOKENS}}`, `{{GRAND_BILLABLE_TOKENS}}`, `{{GRAND_COST_USD}}`, `{{CLI_COST_USD}}`) in the final-report file with concrete values from the freshly computed usageSummary.
86
+
87
+ Skipping `--substitute-final-report` is the recurring root cause of reports shipping with literal `{{LEAD_TOTAL_TOKENS}}` etc. in their Token Usage Summary table. Always pass the flag — never run the collector without it during Phase 7.
88
+
89
+ The final-report file MUST already exist before this step runs (it's authored by Report writer worker in Phase 6, or by Lead in the documented fallback case). The status file can be written after this step completes.
90
+
91
+ ## Final Report Structure
92
+
93
+ The final report follows the structure below. If `instruction-set/final-report-template.md` exists, that format takes precedence.
94
+
95
+ ### Report Header
96
+
97
+ ```markdown
98
+ # <task-key> - Multi-Agent Cross Verification Final Report
99
+ - Date: <ISO 8601 timestamp>
100
+ - Task Key: <task-key>
101
+ - Task Type: <task-type>
102
+ - Author: `<Report writer worker if in roster, else Claude lead>`
103
+ - Lead model: `<lead-model>`
104
+ - Preparation Method: Final report authored by Report writer worker (or lead-authored fallback — record the documented dispatch failure reason here when applicable)
105
+ ```
106
+
107
+ ### Agent-Specific Execution Status Table
108
+
109
+ ```markdown
110
+ | Agent | Role | Model | Status | 처리 토큰 | 환산 토큰 | 비용 (USD) | Duration | Summary of Key Findings |
111
+ |-------|------|-------|--------|-----------|-----------|------------|----------|------------------------|
112
+ | Claude Code | Claude lead | opus | completed | 10,479,327 | 1,769,798 | $26.55 | 59m 12s | Final synthesis status |
113
+ | Claude Code | Claude worker | sonnet | completed | 1,941,396 | 475,136 | $1.43 | 13m 33s | Key findings summary |
114
+ | Codex | Codex worker | gpt-5.5 | completed | 2,274,011 (CLI: 5,261,833) | 586,223 | $8.79 (+ CLI $4.20) | 22m 06s | Key findings summary |
115
+ | Gemini | Gemini worker | auto | completed | 3,107,795 | 746,623 | $11.20 | 22m 06s | Key findings summary |
116
+ | Claude Code | Report writer | opus | completed | 665,497 | 267,210 | $4.01 | 4m 20s | Report organization |
117
+ ```
118
+
119
+ Table Generation Rules:
120
+ - The first row is always `Claude lead` with data from `leadUsage`; subsequent rows follow `recommendedWorkers` / `resultContract.requiredWorkerRoles` order.
121
+ - Agent labels: Claude worker/Report writer → "Claude Code", Codex worker → "Codex", Gemini worker → "Gemini".
122
+ - **처리 토큰** = `usage.totalTokens` (input + output + cache_creation + cache_read; the raw volume processed).
123
+ - **환산 토큰** = `usage.billableEquivalentTokens` (cache reads weighted at 0.1×, cache_creation 1.25×, output 5×; useful as a single number for "how big was this session in cost terms").
124
+ - **비용 (USD)** = `usage.estimatedCostUsd`. For Codex/Gemini workers that actually invoked the CLI, append `(+ CLI $X.XX)` from `usage.cliEstimatedCostUsd`.
125
+ - For Codex/Gemini workers, append `(CLI: <cliTotalTokens>)` to the 처리 토큰 cell when `usage.cliTotalTokens` is set.
126
+ - Status values are retrieved from team-state; format duration as `Xm Ys` from `usage.durationMs`.
127
+ - Workers with status `not-run` or with `source: "unavailable"` show `--` for tokens/cost/duration; quote the `note` underneath the table if useful.
128
+
129
+ ### Token Usage Summary Section
130
+
131
+ Place this section immediately after the execution status table.
132
+
133
+ ```markdown
134
+ ### 토큰 사용량 요약
135
+
136
+ | 항목 | 처리 토큰 | 환산 토큰 (input 기준) | 비용 (USD) |
137
+ |------|-----------|------------------------|------------|
138
+ | Lead | 10,479,327 | 1,769,798 | $26.55 |
139
+ | Worker 합계 | 7,988,699 | 2,075,192 | $25.43 |
140
+ | **전체 합계** | **18,468,026** | **3,844,990** | **$51.97** |
141
+ | Codex/Gemini CLI 추가 비용 | | | $0.00 |
142
+
143
+ > **읽는 법**: "처리 토큰"은 모델이 실제로 처리한 raw 토큰 합계(input + output + cache_creation + cache_read). 긴 세션에서는 cache_read가 95% 이상을 차지해 숫자가 커 보입니다. "환산 토큰"은 cache_read를 0.1×, cache_creation을 1.25×, output을 5×로 가중한 input-등가 토큰으로, 비용 감각에 가깝습니다. 비용은 공시 가격(Anthropic/OpenAI/Google) 기준 추정치입니다.
144
+ ```
145
+
146
+ Token Summary Generation Rules:
147
+ - All values come from `usageSummary` (populated by `scripts/okstra-token-usage.py` at the start of Phase 7). Do not estimate or invent.
148
+ - **Lead** row: `usageSummary.leadTotalTokens` / `usageSummary.leadBillableEquivalentTokens` / `usageSummary.estimatedCostUsd.lead`.
149
+ - **Worker 합계** row: `usageSummary.workerTotalTokens` / `usageSummary.workerBillableEquivalentTokens` / `usageSummary.estimatedCostUsd.claudeWorkers`.
150
+ - **전체 합계** row: `usageSummary.grandTotalTokens` / `usageSummary.grandBillableEquivalentTokens` / sum of `lead + claudeWorkers`.
151
+ - **Codex/Gemini CLI 추가 비용** row: `usageSummary.estimatedCostUsd.cliWorkers`. If 0, still show the row so the reader sees that no CLI work was billed under those providers (or that CLI fallback occurred).
152
+ - Format tokens with comma separators (e.g., `32,500`); format USD with two decimals (e.g., `$1.43`).
153
+ - If `lead` or any `worker.usage` has `source: "unavailable"`, show `--` for that row and append a one-line note (`reason: <note>`).
154
+ - If pricing for a model is unknown, the script omits `estimatedCostUsd` for that block — show `N/A` in that column and add a note like `pricing missing for model <model>`.
155
+
156
+ ### Implementation-planning section heading contract (BLOCKING)
157
+
158
+ When the run's `task-type` is `implementation-planning`, the final report MUST contain section headings whose **lines include each of the 8 literal English substrings below**. The validator (`validators/validate-run.py`) does plain substring matching on the report text — 7-of-8 missing was a real, repeatedly observed failure mode caused by translating the headings to Korean.
159
+
160
+ | # | Required substring | Recommended heading form |
161
+ |---|--------------------|--------------------------|
162
+ | 1 | `Option Candidates` | `### Option Candidates (옵션 후보)` |
163
+ | 2 | `Trade-off` | `### Trade-off Matrix (트레이드오프 매트릭스)` |
164
+ | 3 | `Recommended Option` | `### Recommended Option (권장 옵션)` |
165
+ | 4 | `Stepwise Execution Order` | `### Stepwise Execution Order (단계별 실행 순서)` |
166
+ | 5 | `Dependency` | `### Dependency / Migration Risk (의존성·마이그레이션 위험)` |
167
+ | 6 | `Validation Checklist` | `### Validation Checklist (검증 체크리스트)` |
168
+ | 7 | `Rollback` | `### Rollback Strategy (롤백 전략)` |
169
+ | 8 | `User Approval Request` | `### User Approval Request (사용자 승인 요청)` |
170
+
171
+ The Korean translation in parentheses is optional but the English keyword is mandatory. The body of each section is written in Korean per the writing rules below. For non-`implementation-planning` runs, omit this entire block — these headings are NOT validator-checked for other task-types.
172
+
173
+ The final-report template `okstra-final-report.template.md` Section 4.5 already encodes this contract — copy that block verbatim and fill in.
174
+
175
+ ### Mandatory worker-results file (BLOCKING)
176
+
177
+ You (the report-writer-worker subagent) MUST also write a worker-results audit file at the path the lead provides as `**Worker Result Path:**`, defaulting to:
178
+
179
+ ```
180
+ runs/<task-type>/worker-results/report-writer-worker-<task-type>-<seq>.md
181
+ ```
182
+
183
+ This file is checked by the validator whenever the role's terminal status is `completed`. Without it the run fails with `report-writer is completed but worker result file is missing`.
184
+
185
+ The file content is short: it begins with the standard worker-result header from `okstra-team-contract`, then names the canonical final-report path you wrote, lists the input artifacts you reconciled, and records any structural deviations from `final-report-template.md`. Do NOT duplicate the full final-report body here — it's an audit pointer, not a second copy.
186
+
187
+ Skipping this file because "the real report is in `reports/`" is wrong. Both files are required.
188
+
189
+ ### Main Body Section
190
+
191
+ Section numbering matches `okstra-final-report.template.md`. Section 0 is the carry-in reconciliation that runs first when a clarification response was provided; sections 1–7 follow the template's main body order.
192
+
193
+ 0. **Clarification Response Carried In** - if `{{CLARIFICATION_RESPONSE_RELATIVE_PATH}}` is non-empty, read `instruction-set/clarification-response.md`, reconcile every prior `Q*` row, and record the outcome (`resolved`/`obsolete`) plus the new evidence in this section before drafting the verdict
194
+ 1. **Problem or Verification Summary** - Key summary based on the brief and data (3–5 bullet points)
195
+ 2. **Cross Verification Results** (Use 4 categories when convergence is enabled, per `okstra-convergence`)
196
+ - Full Consensus: Findings agreed upon by all workers
197
+ - Partial Consensus: Agreed upon by a majority of workers; dissenting opinions are specified
198
+ - Contested: No consensus after max rounds; each worker’s position specified
199
+ - Worker-Unique: Verified only by the discoverer; verification history specified
200
+ - In runs with convergence disabled, maintain the existing Consensus/Differences format
201
+ 3. **Final Verdict** - Conclusion based on comprehensive evidence; direction provided
202
+ 4. **Evidence and Detailed Analysis**
203
+ - Key Evidence: File path, line number, actual evidence
204
+ - If explicit expected values are present in `reference-expectations.md`, specify whether they match or differ from the expected values in config files / deployment manifests
205
+ - Supporting evidence or alternative interpretations
206
+ 5. **Missing Information and Risks** - Uncertain/I don't know items
207
+ 6. **Clarification Requests for the Next Run** - structured Q&A table the user fills inline before reruns
208
+ - Required for `task-type` `error-analysis` and `requirements-discovery` whenever blocking uncertainty remains
209
+ - Optional for other task-types; explicitly state "no clarification needed" when none
210
+ - Follow the table format from `final-report-template.md` exactly (columns: Question ID, Blocking, Why this matters, Question, Expected answer shape, Status, Answer)
211
+ - Use stable `Q1`, `Q2`, ... ids and never delete prior ids on rerun; mark them `resolved` or `obsolete` instead
212
+ 7. **Recommended Next Steps** - Actions by Priority
213
+
214
+ ### Writing Guidelines
215
+
216
+ - Write in Markdown (actively use tables, bullet points, and code blocks)
217
+ - Write the final report body in Korean.
218
+ - Keep technical identifiers such as file paths, code symbols, model names, and status values in their original form when needed.
219
+ - If only one worker is usable, perform a reduced-confidence synthesis
220
+ - If evidence is insufficient, explicitly state "I don't know"
221
+ - If expected values are present in `reference-expectations.md`, list matches, gaps, and missing evidence separately
222
+ - If `reference-expectations.md` is explicitly empty, report the absence of expected states as missing information
223
+ - If there are no substantive differences between workers, state "No difference"
224
+ - Write the actual analysis text instead of a meta-description
225
+ - Do not make unfounded assertions
226
+ - Include findings from all four categories. Do not omit "contested" or "worker-unique" findings
227
+ - Include the convergence round history and a summary of votes by worker for each finding
228
+ - The report writer worker does not participate in the re-verification vote. It is responsible only for drafting the final report
229
+
230
+ ## Artifact Persistence Checklist
231
+
232
+ Persistence steps that must be performed in Phase 7:
233
+
234
+ - [ ] 1. **Draft final report**: Save to `runs/<task-type>/reports/final-report-<task-type>-<seq>.md`
235
+ - [ ] 2. **Update team state**: Update `runs/<task-type>/state/team-state-<task-type>-<seq>.json`
236
+ - Final status, start/end times, and result file paths for each worker
237
+ - Overall run status
238
+ - [ ] 3. **Update run manifest**: Update `runs/<task-type>/manifests/run-manifest-<task-type>-<seq>.json`
239
+ - [ ] 4. **Update task-manifest.json**: Reflect task-level status and workflow lifecycle metadata
240
+ - Update `workCategory` if the run produced a confident classification
241
+ - Update `workflow.currentPhase`, `workflow.currentPhaseState`, `workflow.lastCompletedPhase`, and `workflow.phaseStates`
242
+ - Update `workflow.nextRecommendedPhase`, `workflow.awaitingApproval`, and `workflow.routingStatus`
243
+ - Update `workflow.lastSafeCheckpoint` to the best resume point for the current task
244
+ - [ ] 5. **Update task-index.md**: Refresh human-readable summary
245
+ - [ ] 6. **Generate final status file**: `runs/<task-type>/status/final-<task-type>-<seq>.status` (if necessary)
246
+ - [ ] 7. **Save convergence state**: `runs/<task-type>/state/convergence-<task-type>-<seq>.json` (when convergence is enabled)
247
+
248
+ ### Response after Persistence
249
+
250
+ Provide a concise report in Korean covering the following:
251
+ - Completion status
252
+ - Final report path
253
+ - Team-state path
254
+ - Validator results
255
+ - Resume command path
256
+ - Remaining blockers (if any)
@@ -0,0 +1,223 @@
1
+ ---
2
+ name: okstra-run
3
+ description: Use when the user wants to start an okstra task (cross-verification run) directly from the current Claude Code session — without spawning a new claude process. Equivalent in effect to `okstra.sh --task-type ...` but driven through interactive prompts. Trigger words include "okstra run", "okstra start", "start okstra", "begin okstra task", "run okstra in this session", "okstra here".
4
+ ---
5
+
6
+ # OKSTRA Run (in-session)
7
+
8
+ Launch an okstra task — gather inputs interactively, render the full task bundle through the single python entrypoint, then take over as `Claude lead` in the current session.
9
+
10
+ **Single authority**: this skill and `okstra.sh` both call the exact same python function `okstra_ctl.run.prepare_task_bundle()`. The skill does NOT shell out to `okstra.sh` — that would create a second orchestration path and reintroduce env-var leakage between the parent claude session and child bash.
11
+
12
+ ## When to Use
13
+
14
+ - The user is already inside a Claude Code session and asks to start an okstra task ("run okstra here", "start an error-analysis on this branch", "okstra implementation-planning for INV-1234").
15
+ - Continue an existing task (next phase) without leaving the current claude session.
16
+
17
+ ## When NOT to Use
18
+
19
+ - User explicitly asks to spawn a new terminal / new claude — use `okstra-history` Step 4 (resume command) or instruct them to run `okstra.sh` in another terminal.
20
+ - User wants status only — use `okstra-status`.
21
+ - User wants past runs — use `okstra-history`.
22
+
23
+ ## Authority Files (disk-only — no env var caching for per-run identity)
24
+
25
+ Every step reads disk afresh. The `OKSTRA_*` env vars below identify the
26
+ **runtime installation** (stable across runs) — they are NOT per-task identity.
27
+
28
+ - `~/.okstra/version` — okstra runtime version stamp
29
+ - `<PROJECT_ROOT>/.project-docs/okstra/project.json`
30
+ - `<PROJECT_ROOT>/.project-docs/okstra/discovery/{task-catalog,latest-task}.json`
31
+ - `<task-root>/task-manifest.json`
32
+
33
+ ## Step 0: Resolve okstra runtime paths
34
+
35
+ Do NOT hard-code or guess any okstra path. Every run loads them fresh from
36
+ the single authority — `okstra`:
37
+
38
+ ```bash
39
+ # 1) Ensure okstra runtime is fresh (idempotent, cached when up-to-date)
40
+ npx -y okstra@latest ensure-installed >/dev/null 2>&1 || {
41
+ echo "FAIL: okstra not installed; run: npx okstra@latest install" >&2
42
+ exit 1
43
+ }
44
+
45
+ # 2) Load all runtime paths into the shell as OKSTRA_* exports
46
+ eval "$(npx -y okstra@latest paths --shell)"
47
+ export PYTHONPATH="$OKSTRA_PYTHONPATH"
48
+ ```
49
+
50
+ After Step 0 the following are guaranteed:
51
+
52
+ | Variable | Meaning |
53
+ |---|---|
54
+ | `$OKSTRA_WORKSPACE` | passed to python as `workspace_root` (prompts/, templates/, validators/, agents/ root) |
55
+ | `$OKSTRA_AGENTS_DIR` | source dir of worker `*.md` (subagent definitions) |
56
+ | `$OKSTRA_PYTHONPATH` | already exported as `PYTHONPATH` |
57
+ | `$OKSTRA_BIN` | bash entrypoints (`okstra.sh`, codex/gemini exec wrappers) |
58
+ | `$OKSTRA_HOME` | `~/.okstra` (recent.jsonl, locks, projects/, archive/) |
59
+
60
+ ## Step 1: Resolve PROJECT_ROOT and projectId
61
+
62
+ ```bash
63
+ python3 - <<'PY'
64
+ import sys, json
65
+ from okstra_project import resolve_project_root, ResolverError
66
+ try:
67
+ pr = resolve_project_root(explicit_root="", cwd=".")
68
+ except ResolverError as e:
69
+ print(f"FAIL\t{e}"); raise SystemExit(0)
70
+ print(f"OK\t{pr}")
71
+ PY
72
+ ```
73
+
74
+ - If `OK`: read `<PROJECT_ROOT>/.project-docs/okstra/project.json` and extract `projectId`.
75
+ - If `FAIL`: ask the user (`AskUserQuestion`, free text) for an absolute project-root path; rerun the resolver with `explicit_root=<their input>`.
76
+
77
+ ## Step 2: Choose task — existing vs new
78
+
79
+ ```bash
80
+ python3 -c "
81
+ import json, sys
82
+ from pathlib import Path
83
+ from okstra_project import list_project_tasks, read_latest_task
84
+ pr = Path(sys.argv[1])
85
+ tasks = list_project_tasks(pr)
86
+ latest = read_latest_task(pr)
87
+ print(json.dumps({'tasks': tasks, 'latest': latest}))
88
+ " "$PROJECT_ROOT"
89
+ ```
90
+
91
+ Use `AskUserQuestion`:
92
+
93
+ - **Label**: "Which task?"
94
+ - **Options**: each existing task with label `"<taskKey> · <currentPhase or taskType> · next: <nextRecommendedPhase>"`; mark the `latest` entry with `(latest)`. Final option: `"Start a brand-new task"`. Limit to 8 candidates per page; add `"More..."` if more exist.
95
+
96
+ For an existing pick, read its `task-manifest.json` to capture `taskType` and `workflow.nextRecommendedPhase`.
97
+
98
+ ## Step 3: For new tasks — collect identity
99
+
100
+ Skip if continuing existing.
101
+
102
+ `AskUserQuestion` (free text, one at a time):
103
+
104
+ 1. `"Task group (e.g. backend-api, INV-1234, refactor)"` → `task_group`
105
+ 2. `"Task id (e.g. login-error-analysis, dev-9043)"` → `task_id`
106
+
107
+ Validate that slugified `task_group` and `task_id` each contain at least one alphanumeric character. Re-ask if not.
108
+
109
+ ## Step 4: Choose task-type
110
+
111
+ `AskUserQuestion` with five fixed options:
112
+
113
+ | Option | Description |
114
+ |---|---|
115
+ | `requirements-discovery` | Classify request and route to next safe phase |
116
+ | `error-analysis` | Evidence-based root-cause analysis (no code changes) |
117
+ | `implementation-planning` | Plan options + request user approval |
118
+ | `implementation` | Execute approved plan (requires `--approved-plan`) |
119
+ | `final-verification` | Acceptance + residual-risk review |
120
+
121
+ For existing tasks, present `nextRecommendedPhase` as the first option (recommended default).
122
+
123
+ If `implementation` chosen, ask one more `AskUserQuestion`:
124
+ - `"Path to the approved final-report.md (must contain APPROVED marker)"` — the underlying python `prepare_task_bundle` re-validates the marker, but you can pre-check with `grep`.
125
+
126
+ ## Step 5: Brief path
127
+
128
+ - New task: `AskUserQuestion` (free text) `"Path to the task brief markdown (relative to project root)"`. Verify file exists; re-ask on failure.
129
+ - Existing task: default to the manifest's `taskBriefPath`. Show it; ask whether to keep or change.
130
+
131
+ ## Step 6 (optional): Directive / workers / models / related / clarification
132
+
133
+ Single `AskUserQuestion` first: `"Use default workers and models, or customize?"`
134
+
135
+ - `Use defaults` → all overrides remain empty.
136
+ - `Customize` → ask each in turn (free text, blank = use default):
137
+ - workers CSV (subset of `claude,codex,gemini,report-writer`)
138
+ - `lead-model`, `claude-model`, `codex-model`, `gemini-model`, `report-writer-model`
139
+ - `directive`
140
+ - `related-tasks` CSV
141
+ - `clarification-response` path (relevant for follow-up `requirements-discovery` / `error-analysis` runs)
142
+
143
+ ## Step 7: Call `prepare_task_bundle` directly
144
+
145
+ This is the single line that materializes the entire task bundle. **Pass `render_only=True`** — the current claude session itself takes over as lead; we do not exec a new claude.
146
+
147
+ ```bash
148
+ python3 - <<PY
149
+ import os
150
+ from pathlib import Path
151
+ from okstra_ctl.run import PrepareInputs, prepare_task_bundle
152
+ from okstra_ctl.path_resolve import resolve_user_file
153
+
154
+ project_root = Path("<project-root>")
155
+ brief_abs = resolve_user_file("<brief-path-from-user>", project_root)
156
+ clarification_abs = resolve_user_file("<clarification-or-empty>", project_root) if "<clarification-or-empty>" else None
157
+
158
+ out = prepare_task_bundle(PrepareInputs(
159
+ workspace_root=Path(os.environ["OKSTRA_WORKSPACE"]),
160
+ project_root=project_root,
161
+ project_id="<project-id>",
162
+ task_group="<task-group>",
163
+ task_id="<task-id>",
164
+ task_type="<task-type>",
165
+ brief_path=brief_abs,
166
+ directive="<directive or empty>",
167
+ workers_override="<workers csv or empty>",
168
+ lead_model="...", claude_model="...", codex_model="...",
169
+ gemini_model="...", report_writer_model="...",
170
+ related_tasks_raw="...",
171
+ approved_plan_path="<approved-plan-or-empty>",
172
+ clarification_response_path=str(clarification_abs) if clarification_abs else "",
173
+ render_only=True,
174
+ ))
175
+
176
+ # Print key paths so the next step can read them.
177
+ ctx = out.ctx
178
+ print("TASK_ROOT", ctx["TASK_ROOT"])
179
+ print("INSTRUCTION_SET_DIR", ctx["INSTRUCTION_SET_DIR"])
180
+ print("LEAD_PROMPT", str(Path(ctx["INSTRUCTION_SET_DIR"]) / "claude-execution-prompt.md"))
181
+ PY
182
+ ```
183
+
184
+ The python function is mutex-protected (`~/.okstra/.locks/<task-key>.lock`), writes `run-context-*.json` + `run-inputs-*.json` + all manifests + discovery files, and registers the run in `~/.okstra/recent.jsonl` with status `prepared`.
185
+
186
+ ## Step 8: Take over as Claude lead
187
+
188
+ Read these files (do not paraphrase) and enter `Claude lead` mode:
189
+
190
+ 1. `<INSTRUCTION_SET_DIR>/claude-execution-prompt.md` — the lead prompt
191
+ 2. `<INSTRUCTION_SET_DIR>/analysis-profile.md` — per-task-type allowed outputs / forbidden actions
192
+ 3. `<INSTRUCTION_SET_DIR>/analysis-material.md` — task brief + directive
193
+ 4. `<INSTRUCTION_SET_DIR>/reference-expectations.md`
194
+ 5. `<INSTRUCTION_SET_DIR>/final-report-template.md`
195
+
196
+ Then proceed through the phases exactly as the lead prompt directs (Phase 1 context → Phase 2+ worker dispatch → final synthesis → final report).
197
+
198
+ Inform the user with one short line:
199
+ > Took over as Claude lead for `<taskKey>` (`<task-type>`). Run dir: `<RUN_DIR_RELATIVE_PATH>`. Beginning Phase 1 (context loading).
200
+
201
+ ## Concurrency
202
+
203
+ - `prepare_task_bundle` serializes per-task via `~/.okstra/.locks/<task-key>.lock`. Concurrent skill invocations on the same task wait; different tasks proceed in parallel.
204
+ - The skill must NOT call `okstra.sh` or any other bash entrypoint that would re-implement the orchestration. The python function is the single authority.
205
+ - No env var carries identity across steps — every step re-reads disk authority.
206
+
207
+ ## Failure Modes
208
+
209
+ | Symptom | Cause | Fix |
210
+ |---|---|---|
211
+ | `okstra runtime missing: ...` | First run on this machine, or stale install | `npx okstra@latest install` once, retry. |
212
+ | `OKSTRA_PYTHONPATH unbound` / `ModuleNotFoundError: okstra_project` | Step 0 was skipped or env vars dropped | Re-run Step 0; never invoke python without exporting `PYTHONPATH=$OKSTRA_PYTHONPATH`. |
213
+ | `task root not found for <key>` | catalog entry stale or task-key typo | Re-run Step 2; show available keys from `list_project_tasks` |
214
+ | `PROJECT_ROOT 를 해석할 수 없습니다` | cwd outside okstra project, no git toplevel | Ask user for absolute path |
215
+ | `approved plan has no recognised user-approval marker` | `implementation` without proper approval | Ask user to add `APPROVED` to the plan, or pick a different task-type |
216
+ | `task brief not found` | brief-path doesn't resolve relative to cwd or project-root | Re-ask Step 5 |
217
+ | record_start failed | `~/.okstra` lock or disk issue | Non-fatal — bundle is valid; warn and continue |
218
+
219
+ ## Output Rules
220
+
221
+ - Echo each `AskUserQuestion` outcome on one short line so user sees what was captured.
222
+ - Never invent identity; re-ask if blank.
223
+ - After Step 8, begin the lead workflow without re-summarizing the skill itself.