okstra 0.26.0 → 0.28.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.kr.md +15 -0
- package/README.md +15 -0
- package/docs/kr/architecture.md +2 -6
- package/docs/kr/cli.md +40 -6
- package/docs/kr/performance-improvement-plan-v2.md +23 -0
- package/docs/kr/performance-improvement-plan.md +22 -0
- package/package.json +1 -1
- package/runtime/BUILD.json +2 -2
- package/runtime/agents/workers/claude-worker.md +4 -3
- package/runtime/agents/workers/codex-worker.md +4 -3
- package/runtime/agents/workers/gemini-worker.md +4 -3
- package/runtime/agents/workers/report-writer-worker.md +7 -2
- package/runtime/bin/okstra.sh +0 -1
- package/runtime/prompts/launch.template.md +1 -1
- package/runtime/prompts/profiles/_common-contract.md +36 -4
- package/runtime/prompts/profiles/error-analysis.md +12 -0
- package/runtime/prompts/profiles/implementation-planning.md +20 -0
- package/runtime/prompts/profiles/requirements-discovery.md +20 -0
- package/runtime/python/lib/okstra/cli.sh +1 -7
- package/runtime/python/lib/okstra/globals.sh +0 -1
- package/runtime/python/lib/okstra/usage.sh +1 -4
- package/runtime/python/okstra_ctl/render.py +3 -0
- package/runtime/python/okstra_ctl/run.py +0 -6
- package/runtime/python/okstra_ctl/run_context.py +1 -1
- package/runtime/python/okstra_ctl/wizard.py +25 -2
- package/runtime/python/okstra_token_usage/blocks.py +5 -1
- package/runtime/python/okstra_token_usage/claude.py +16 -1
- package/runtime/python/okstra_token_usage/cli.py +9 -2
- package/runtime/python/okstra_token_usage/collect.py +17 -3
- package/runtime/python/okstra_token_usage/pricing.py +159 -24
- package/runtime/python/okstra_token_usage/report.py +32 -3
- package/runtime/skills/okstra-brief/SKILL.md +532 -65
- package/runtime/skills/okstra-context-loader/SKILL.md +25 -11
- package/runtime/skills/okstra-convergence/SKILL.md +38 -14
- package/runtime/skills/okstra-history/SKILL.md +68 -37
- package/runtime/skills/okstra-logs/SKILL.md +26 -4
- package/runtime/skills/okstra-report-finder/SKILL.md +49 -22
- package/runtime/skills/okstra-report-writer/SKILL.md +62 -65
- package/runtime/skills/okstra-run/SKILL.md +35 -34
- package/runtime/skills/okstra-schedule/SKILL.md +51 -20
- package/runtime/skills/okstra-setup/SKILL.md +31 -12
- package/runtime/skills/okstra-status/SKILL.md +20 -8
- package/runtime/skills/okstra-team-contract/SKILL.md +41 -25
- package/runtime/skills/okstra-time-summary/SKILL.md +53 -16
- package/runtime/templates/reports/final-report.template.md +227 -207
- package/runtime/templates/reports/settings.template.json +7 -4
- package/runtime/validators/lib/fixtures.sh +47 -2
- package/runtime/validators/lib/validate-assets.sh +50 -24
- package/runtime/validators/validate-brief.py +385 -0
- package/runtime/validators/validate-brief.sh +35 -0
- package/runtime/validators/validate-run.py +313 -1
- package/runtime/validators/validate-workflow.sh +7 -33
|
@@ -8,7 +8,7 @@ user-invocable: false
|
|
|
8
8
|
|
|
9
9
|
## File-author ownership (BLOCKING)
|
|
10
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`).
|
|
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`). **Except for `release-handoff`**, which has no worker roster — the Claude lead authors the final-report directly by design (see "Release-handoff section contract" below), and the fallback rules in this section do not apply.
|
|
12
12
|
|
|
13
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
14
|
|
|
@@ -60,7 +60,7 @@ A resumed lead session can ALWAYS dispatch a fresh Report writer worker. The Age
|
|
|
60
60
|
|
|
61
61
|
### Lead-authored fallback (only if dispatch failed)
|
|
62
62
|
|
|
63
|
-
|
|
63
|
+
Except for `release-handoff` (which is single-lead by design and never dispatches a Report writer worker — see "Release-handoff section contract" below), lead-authored fallback is permitted only if all of the following are true and recorded in team-state:
|
|
64
64
|
|
|
65
65
|
1. A Report writer worker dispatch was actually attempted (Agent call was issued).
|
|
66
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).
|
|
@@ -68,50 +68,43 @@ Lead-authored fallback is permitted only if all of the following are true and re
|
|
|
68
68
|
|
|
69
69
|
Speculative reasons such as "session resume constraint", "team object no longer exists", or "lead can do it faster" are NOT valid.
|
|
70
70
|
|
|
71
|
-
## Phase 7
|
|
71
|
+
## Phase 6 → Phase 7 execution sequence (BLOCKING order)
|
|
72
72
|
|
|
73
|
-
|
|
73
|
+
The four steps below MUST execute in this exact order. Reordering them is the recurring root cause of reports shipping with unsubstituted `{{LEAD_TOTAL_TOKENS}}` placeholders, Section 6 missing the follow-up entries, or Section 7 rows never spawning.
|
|
74
74
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
<runDirectoryPath>/reports/final-report-<task-type>-<seq>.md \
|
|
78
|
-
--project-root <project_root> \
|
|
79
|
-
--task-group <task-group> \
|
|
80
|
-
--parent-task-key <task-key>
|
|
81
|
-
```
|
|
82
|
-
|
|
83
|
-
Behaviour contract:
|
|
84
|
-
|
|
85
|
-
- The script is **idempotent**: rows whose target directory already exists are reported as `existing` and skipped without modification. Re-running the spawner across reruns of the same parent task is safe.
|
|
86
|
-
- Rows with `Auto-spawn? != yes` are reported as `skipped` and never written to disk. Surface them in the final-report's Section 6 if the user should still take manual action.
|
|
87
|
-
- A row with an invalid `Origin`, `Suggested task-type`, missing `Title`, or missing `Reason / Why deferred` causes the script to exit `1`. The report-writer worker MUST refuse to ship a final-report whose Section 7 contains such rows. Either fix the row or change `Auto-spawn?` to `no` and document why in Section 6.
|
|
88
|
-
- For `task-type` ∈ {`implementation`, `final-verification`, `release-handoff`}, Section 7 must be present in the final report. An empty section is acceptable and is expressed as the single line `- 후속 작업 없음.` under the heading. The spawner treats a missing or empty section as a no-op (exit `0`).
|
|
89
|
-
|
|
90
|
-
After the spawner completes, the report-writer worker MUST update Section 6 ("Recommended Next Steps") to list every newly created task-key together with its entry command, so the user can pick the follow-up up immediately:
|
|
91
|
-
|
|
92
|
-
```
|
|
93
|
-
- Follow-up: `<task-group>/<new-task-id>` — Claude Code 세션 안 `/okstra-run task-key=<task-group>/<new-task-id> task-type=<suggested>` / 별도 터미널 `scripts/okstra.sh --task-key <task-group>/<new-task-id> --task-type <suggested>`
|
|
94
|
-
```
|
|
95
|
-
|
|
96
|
-
## Phase 7 token-usage collector (BLOCKING)
|
|
75
|
+
1. **Phase 6 — Report writer worker drafts the final-report file** at `runs/<task-type>/reports/final-report-<task-type>-<seq>.md`. Token placeholders are left verbatim; Section 6 lists prioritized actions but does NOT yet include auto-spawned follow-ups (they don't exist yet).
|
|
76
|
+
2. **Phase 7 step 1 — Token-usage collector with `--substitute-final-report`** (BLOCKING). One invocation aggregates `leadUsage` / `workers[].usage` / `usageSummary` into team-state AND substitutes the 10 placeholders in the final-report file. Skipping the flag ships literal `{{...}}` in the Token Usage Summary table.
|
|
97
77
|
|
|
98
|
-
|
|
78
|
+
```bash
|
|
79
|
+
python3 scripts/okstra-token-usage.py \
|
|
80
|
+
<runDirectoryPath>/state/team-state-<task-type>-<seq>.json \
|
|
81
|
+
--write --summary \
|
|
82
|
+
--substitute-final-report <runDirectoryPath>/reports/final-report-<task-type>-<seq>.md
|
|
83
|
+
```
|
|
99
84
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
<runDirectoryPath>/state/team-state-<task-type>-<seq>.json \
|
|
103
|
-
--write --summary \
|
|
104
|
-
--substitute-final-report <runDirectoryPath>/reports/final-report-<task-type>-<seq>.md
|
|
105
|
-
```
|
|
85
|
+
The 10 substituted 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}}`. The final-report file MUST already exist (Phase 6 output).
|
|
86
|
+
3. **Phase 7 step 2 — Follow-up task spawner** (BLOCKING when Section 7 is non-empty). Turns the report's `## 7. Follow-up Tasks (후속 작업)` rows into `tasks/<task-group>/<new-task-id>/` stubs.
|
|
106
87
|
|
|
107
|
-
|
|
88
|
+
```bash
|
|
89
|
+
python3 scripts/okstra-spawn-followups.py \
|
|
90
|
+
<runDirectoryPath>/reports/final-report-<task-type>-<seq>.md \
|
|
91
|
+
--project-root <project_root> \
|
|
92
|
+
--task-group <task-group> \
|
|
93
|
+
--parent-task-key <task-key>
|
|
94
|
+
```
|
|
108
95
|
|
|
109
|
-
|
|
110
|
-
-
|
|
96
|
+
Behaviour contract:
|
|
97
|
+
- Idempotent: rows whose target dir exists are reported as `existing` and skipped. Reruns of the same parent task are safe.
|
|
98
|
+
- Rows with `Auto-spawn? != yes` are reported as `skipped` and never written; surface them in Section 6 if manual action is still needed.
|
|
99
|
+
- An invalid `Origin`, `Suggested task-type`, missing `Title`, or missing `Reason / Why deferred` exits `1`. The report-writer MUST refuse to ship a Section 7 with such rows.
|
|
100
|
+
- **Canonical spawn rule (single source of truth):** the spawner runs when `task-type` ∈ {`implementation`, `final-verification`, `release-handoff`}, OR when Section 7 is non-empty for any other task-type. For the listed task-types Section 7 must be present in the report; an empty section renders as `- 후속 작업 없음.`. Missing / empty sections are no-ops (exit `0`). All other references to this rule (including the Persistence Checklist) defer to this statement.
|
|
101
|
+
4. **Phase 7 step 3 — Update Section 6** after the spawner. The report-writer MUST append one row per newly spawned task-key with its entry command:
|
|
111
102
|
|
|
112
|
-
|
|
103
|
+
```
|
|
104
|
+
- Follow-up: `<task-group>/<new-task-id>` — Claude Code 세션 안 `/okstra-run task-key=<task-group>/<new-task-id> task-type=<suggested>` / 별도 터미널 `scripts/okstra.sh --task-key <task-group>/<new-task-id> --task-type <suggested>`
|
|
105
|
+
```
|
|
113
106
|
|
|
114
|
-
The
|
|
107
|
+
The status file is written after step 3 completes.
|
|
115
108
|
|
|
116
109
|
## Final Report Structure
|
|
117
110
|
|
|
@@ -181,7 +174,7 @@ Token Summary Generation Rules:
|
|
|
181
174
|
|
|
182
175
|
### Implementation-planning section heading contract (BLOCKING)
|
|
183
176
|
|
|
184
|
-
When the run's `task-type` is `implementation-planning`, the final report MUST contain section headings whose **lines include each of the
|
|
177
|
+
When the run's `task-type` is `implementation-planning`, the final report MUST contain section headings whose **lines include each of the 9 literal English substrings below**. The validator (`validators/validate-run.py`) does plain substring matching on the report text — missing headings was a real, repeatedly observed failure mode caused by translating the headings to Korean.
|
|
185
178
|
|
|
186
179
|
| # | Required substring | Recommended heading form |
|
|
187
180
|
|---|--------------------|--------------------------|
|
|
@@ -192,12 +185,27 @@ When the run's `task-type` is `implementation-planning`, the final report MUST c
|
|
|
192
185
|
| 5 | `Dependency` | `### Dependency / Migration Risk (의존성·마이그레이션 위험)` |
|
|
193
186
|
| 6 | `Validation Checklist` | `### Validation Checklist (검증 체크리스트)` |
|
|
194
187
|
| 7 | `Rollback` | `### Rollback Strategy (롤백 전략)` |
|
|
195
|
-
| 8 | `User Approval Request` |
|
|
188
|
+
| 8 | `User Approval Request` | Satisfied by the top-of-report `## User Approval Request (사용자 승인 게이트)` block. Do NOT recreate a `### 4.5.8 User Approval Request` body stub — the validator now fails reports that contain one. |
|
|
189
|
+
| 9 | `Plan Body Verification` + `Gate result:` | `### Plan Body Verification (계획 본문 검증)` containing a `Gate result:` line — copy `okstra-final-report.template.md §4.5.9` verbatim. Validator checks both substrings. |
|
|
196
190
|
|
|
197
191
|
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.
|
|
198
192
|
|
|
199
193
|
The final-report template `okstra-final-report.template.md` Section 4.5 already encodes this contract — copy that block verbatim and fill in.
|
|
200
194
|
|
|
195
|
+
### Final-verification verdict token contract (BLOCKING)
|
|
196
|
+
|
|
197
|
+
When the run's `task-type` is `final-verification`, the report's `## 2. Final Verdict` table MUST contain a `Verdict Token` row whose value is **exactly one of** the literal strings below. The `release-handoff` profile reads this row as its entry gate; any other value blocks the next phase.
|
|
198
|
+
|
|
199
|
+
| # | Required substring | Meaning |
|
|
200
|
+
|---|--------------------|---------|
|
|
201
|
+
| 1 | `accepted` | All acceptance criteria pass; `release-handoff` may proceed. |
|
|
202
|
+
| 2 | `conditional-accept` | Acceptance passes with caveats; user must resolve listed conditions before `release-handoff`. |
|
|
203
|
+
| 3 | `blocked` | Acceptance failed; routing returns to `error-analysis` or `implementation-planning`. |
|
|
204
|
+
|
|
205
|
+
For every other task-type, set the `Verdict Token` cell to `not-applicable`. Do NOT omit the row — the template renders it for all task-types and downstream tooling expects the field to exist.
|
|
206
|
+
|
|
207
|
+
The final-report template `okstra-final-report.template.md` Section 2 already encodes this contract — copy that block verbatim and fill in.
|
|
208
|
+
|
|
201
209
|
### Release-handoff section contract (release-handoff runs only)
|
|
202
210
|
|
|
203
211
|
When the run's `task-type` is `release-handoff`, the final report MUST include Section `## 4.6 Release Handoff Deliverables` with all seven sub-sections (`4.6.1` Source Verification Report, `4.6.2` Feature Branch & Working-Tree State, `4.6.3` User Selections, `4.6.4` Executed Commands, `4.6.5` Commit List, `4.6.6` Pull Request Outcome, `4.6.7` Routing Recommendation). Every entry is dictated by the lead's recorded git/gh command log and the user's verbatim answers to the H1/H2/H3 menu prompts. H1 choices are `local only`, `push + PR`, or `skip`; release-handoff records existing implementation commits and MUST NOT create new commits. If the user picked `skip` (H1) or `cancel` (H3), keep 4.6.3 populated but leave 4.6.4–4.6.6 explicitly empty per the template's empty-state lines.
|
|
@@ -216,35 +224,24 @@ runs/<task-type>/worker-results/report-writer-worker-<task-type>-<seq>.md
|
|
|
216
224
|
|
|
217
225
|
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`.
|
|
218
226
|
|
|
219
|
-
|
|
227
|
+
**Frontmatter + header schema** — both the worker-results audit file AND the final-report file are governed by `okstra-team-contract` ("Result Frontmatter" and the standard worker-result header sections). That document is the single source of truth; do NOT restate the field list here. Use `workerId: "report-writer"` for both files and copy every other frontmatter value verbatim from `analysis-material.md`. The body of this audit file is short: name the canonical final-report path you wrote, list the input artifacts you reconciled, and record 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.
|
|
220
228
|
|
|
221
229
|
Skipping this file because "the real report is in `reports/`" is wrong. Both files are required.
|
|
222
230
|
|
|
223
231
|
### Main Body Section
|
|
224
232
|
|
|
225
|
-
Section numbering
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
4. **Evidence and Detailed Analysis**
|
|
238
|
-
- Key Evidence: File path, line number, actual evidence
|
|
239
|
-
- 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
|
|
240
|
-
- Supporting evidence or alternative interpretations
|
|
241
|
-
5. **Missing Information and Risks** - Uncertain/I don't know items
|
|
242
|
-
6. **Clarification Items** - single unified table (`C-001`, `C-002`, ...) the user fills inline before reruns. Columns: `ID`, `Ticket ID`, `Kind` (`material` / `decision` / `data-point`), `Statement`, `Expected form`, `Blocks` (`approval` / `next-phase` / `none`), `Status`, `User input`. Replaces the legacy `4.5.9 Open Questions` / `5.1` / `5.2` triple; never create those sub-sections — same item appearing in two places is the failure mode this table prevents.
|
|
243
|
-
- Required for `task-type` `error-analysis` and `requirements-discovery` whenever blocking uncertainty remains
|
|
244
|
-
- Optional for other task-types; explicitly state "no clarification needed" when none
|
|
245
|
-
- Follow the table format from `final-report-template.md` exactly (columns: Question ID, Blocking, Why this matters, Question, Expected answer shape, Status, Answer)
|
|
246
|
-
- Use stable `Q1`, `Q2`, ... ids and never delete prior ids on rerun; mark them `resolved` or `obsolete` instead
|
|
247
|
-
7. **Recommended Next Steps** - Actions by Priority
|
|
233
|
+
Section numbering follows `templates/reports/final-report.template.md` exactly — that file is the single source of truth. Below is a one-line summary of each section's writer obligation; consult the template for full body structure.
|
|
234
|
+
|
|
235
|
+
**Verdict Card (top-of-report, mandatory).** Render `## Verdict Card` between the report header and the (conditional) Approval block. Its `Verdict Token` / `Direction` / `Next Step` cells MUST byte-match the corresponding cells in `## 2. Final Verdict` and the first item of `## 6.`. Divergence is `contract-violated`.
|
|
236
|
+
|
|
237
|
+
0. **Clarification Response Carried In** — render this `## 0.` heading ONLY when `{{CLARIFICATION_RESPONSE_RELATIVE_PATH}}` is non-empty. Walk every `C-*` row of the prior report's `## 5. Clarification Items` table, reconcile against new evidence, and record the outcome (`resolved` / `obsolete`) with citation before drafting the verdict. When no carry-in path was provided, OMIT the `## 0.` heading entirely — the validator fails an empty Section 0 stub.
|
|
238
|
+
1. **Cross Verification Results** — 4 categories (Full / Partial / Contested / Worker-Unique) when convergence is enabled, per `okstra-convergence`. Prepend the Round History sub-table (columns: `Round | inputQueueSize | resolvedCount | carriedForwardCount | dispatches | skippedWorkers`) plus a `round2SkippedReason: <value>` note, pulled verbatim from `convergence-<task-type>-<seq>.json`. Empty contested list renders as `- 합의 미달 항목 없음.`. Convergence-disabled runs use the legacy Consensus/Differences format and omit the round table.
|
|
239
|
+
2. **Final Verdict** — `Direction` ∈ `continue-investigation` / `begin-implementation` / `approve` / `reject` / `hold`. **Verdict Token** is `not-applicable` for every task-type except `final-verification` — see "Final-verification verdict token contract" below for that case.
|
|
240
|
+
3. **Evidence and Detailed Analysis** — primary evidence rows (file path, line, snippet); secondary evidence / alternate interpretations. If `reference-expectations.md` lists explicit expected values, record match/gap per row.
|
|
241
|
+
4. **Missing Information and Risks** — uncertain / "I don't know" items. `implementation-planning` adds §4.5 (see heading contract below); `release-handoff` adds §4.6.
|
|
242
|
+
5. **Clarification Items** — single unified `C-*` table; column schema, ID convention, and rerun behaviour are owned by `_common-contract.md §Clarification request policy` (8-column SSOT). The deprecated `4.5.9 Open Questions` / `5.1 추가 자료 요청` / `5.2 사용자 확인 질문` sub-sections are removed; the validator fails reports that reintroduce them.
|
|
243
|
+
6. **Recommended Next Steps** — prioritized actions. After Phase 7's follow-up spawner runs, append a row per newly created task-key (see "Phase 6 → Phase 7 execution sequence" above).
|
|
244
|
+
7. **Follow-up Tasks** — auto-spawn-eligible table. Each row drives `okstra-spawn-followups.py`; see template §7 for the row schema.
|
|
248
245
|
|
|
249
246
|
### Writing Guidelines
|
|
250
247
|
|
|
@@ -280,7 +277,7 @@ Persistence steps that must be performed in Phase 7:
|
|
|
280
277
|
- [ ] 5. **Update task-index.md**: Refresh human-readable summary
|
|
281
278
|
- [ ] 6. **Generate final status file**: `runs/<task-type>/status/final-<task-type>-<seq>.status` (if necessary)
|
|
282
279
|
- [ ] 7. **Save convergence state**: `runs/<task-type>/state/convergence-<task-type>-<seq>.json` (when convergence is enabled)
|
|
283
|
-
- [ ] 8. **Spawn follow-up task stubs**: run `scripts/okstra-spawn-followups.py` against the final-report
|
|
280
|
+
- [ ] 8. **Spawn follow-up task stubs**: run `scripts/okstra-spawn-followups.py` against the final-report per the canonical spawn rule defined in "Phase 7 follow-up task spawner" above. Do not restate the trigger condition here — that section is the single source of truth. The script is idempotent across reruns.
|
|
284
281
|
|
|
285
282
|
### Response after Persistence
|
|
286
283
|
|
|
@@ -18,7 +18,7 @@ Launch an okstra task — gather inputs interactively via the **wizard state mac
|
|
|
18
18
|
|
|
19
19
|
## When NOT to Use
|
|
20
20
|
|
|
21
|
-
- User explicitly asks to spawn a new terminal / new claude — use `okstra-history` Step 4 (resume command) or instruct them to run `okstra
|
|
21
|
+
- User explicitly asks to spawn a new terminal / new claude — use `okstra-history` Step 4 (resume command) or instruct them to run `okstra` in another terminal.
|
|
22
22
|
- User wants status only — use `okstra-status`.
|
|
23
23
|
- User wants past runs — use `okstra-history`.
|
|
24
24
|
|
|
@@ -48,29 +48,26 @@ Never invent additional questions. Never reorder. Never use `AskUserQuestion` fo
|
|
|
48
48
|
|
|
49
49
|
## Step 1: Verify okstra runtime + project setup
|
|
50
50
|
|
|
51
|
-
|
|
52
|
-
if command -v okstra >/dev/null 2>&1; then
|
|
53
|
-
okstra ensure-installed >/dev/null 2>&1 || { echo "FAIL: okstra ensure-installed failed" >&2; exit 1; }
|
|
54
|
-
eval "$(okstra paths --shell)"
|
|
55
|
-
export PYTHONPATH="$OKSTRA_PYTHONPATH"
|
|
56
|
-
okstra check-project --json || { echo "FAIL: this project has no okstra setup. Tell the user to run /okstra-setup first." >&2; exit 1; }
|
|
57
|
-
else
|
|
58
|
-
npx -y okstra@latest ensure-installed >/dev/null 2>&1 || { echo "FAIL: okstra not installed; tell the user to run: npx okstra@latest install" >&2; exit 1; }
|
|
59
|
-
eval "$(npx -y okstra@latest paths --shell)"
|
|
60
|
-
export PYTHONPATH="$OKSTRA_PYTHONPATH"
|
|
61
|
-
npx -y okstra@latest check-project --json || { echo "FAIL: this project has no okstra setup. Tell the user to run /okstra-setup first." >&2; exit 1; }
|
|
62
|
-
fi
|
|
63
|
-
```
|
|
51
|
+
Run each of the following commands as a **separate Bash tool call**. Each command starts with the literal token `okstra` so the `Bash(okstra:*)` permission match succeeds. Do **not** wrap any of them in `if`, `eval`, `export`, `$(...)`, `VAR=...`, `||`, or `&&` — those leading tokens defeat the permission match and force a confirmation prompt on every call. The LLM (you) inspects each command's JSON output and decides what to do next in natural language — never in shell.
|
|
64
52
|
|
|
65
|
-
|
|
53
|
+
1. `okstra ensure-installed`
|
|
54
|
+
If this exits non-zero, tell the user: "okstra runtime missing — run `npx okstra@latest install` once and retry." Then stop.
|
|
66
55
|
|
|
67
|
-
|
|
56
|
+
2. `okstra paths --json`
|
|
57
|
+
Read `pythonPath` and other path fields from the JSON output. **Do not** `export PYTHONPATH=...` from this skill — every subsequent `okstra <subcmd>` call already self-bootstraps its Python path. Keep the parsed values in mind only as diagnostic context.
|
|
68
58
|
|
|
69
|
-
|
|
59
|
+
3. `okstra check-project --json`
|
|
60
|
+
Reads the project from the current working directory. Parse the JSON from stdout. If `ok` is `false`, ask the user with a **plain text prompt** for an absolute project-root path, then rerun as a separate tool call (still literal-token-first):
|
|
61
|
+
`okstra check-project --cwd /abs/path/from/user --json`
|
|
62
|
+
Substitute the literal absolute path the user gave you (no `$(pwd)`, no shell variables). Re-prompt with plain text on continued failure.
|
|
63
|
+
|
|
64
|
+
Parse `projectRoot` and `projectId` from the successful `check-project --json` output and carry them as literal strings into Step 2.
|
|
70
65
|
|
|
71
|
-
>
|
|
66
|
+
> If the `okstra` binary is not on `PATH` at all, none of the commands above will run. In that case tell the user verbatim: "okstra not installed — run `npx okstra@latest install` once, then retry this skill." Do **not** try to invoke `npx -y okstra@latest ...` from this skill — `npx` is not on the literal-token allow-list and will force a confirmation prompt on every wizard call afterward.
|
|
72
67
|
|
|
73
|
-
|
|
68
|
+
## Step 2: Initialize the wizard
|
|
69
|
+
|
|
70
|
+
First, generate a state-file path (Bash invocation rule from the top of this file applies to every command below):
|
|
74
71
|
|
|
75
72
|
```bash
|
|
76
73
|
okstra wizard new-state-file
|
|
@@ -101,6 +98,14 @@ Repeat until `next.kind == "done"`:
|
|
|
101
98
|
okstra wizard step --state-file /var/folders/.../okstra-wizard.AbCd.json --answer preprod
|
|
102
99
|
```
|
|
103
100
|
If the answer contains spaces or shell metacharacters, wrap it in double quotes around the literal string only — never inside `"$VAR"`.
|
|
101
|
+
|
|
102
|
+
**MANDATORY: empty answers must pass `--answer ""` explicitly.** If the user's reply is the empty string, the call MUST still include the flag with an empty literal value:
|
|
103
|
+
```bash
|
|
104
|
+
okstra wizard step --state-file /var/folders/.../okstra-wizard.AbCd.json --answer ""
|
|
105
|
+
```
|
|
106
|
+
Omitting `--answer` entirely is forbidden. The wizard interprets a missing `--answer` flag as "re-emit the current prompt" (a `get-current-prompt` style no-op), not as "submit empty" — so dropping the flag will loop the same prompt forever. Submitting `--answer ""` is the only way to advance past an intentionally-blank step (e.g. "use phase default").
|
|
107
|
+
|
|
108
|
+
**Escaping rule**: if the literal answer contains `"`, escape each occurrence as `\"` inside the double-quoted argument. Empty values must still be `--answer ""` — the flag itself is mandatory, even when the value is empty.
|
|
104
109
|
3. **Handle result**:
|
|
105
110
|
- `ok: true` → echo `result.echo` to the user on one short line, then loop with `result.next`.
|
|
106
111
|
- `ok: false` → show `result.error` to the user verbatim, then loop with `result.current` (re-prompt the same step).
|
|
@@ -126,8 +131,6 @@ When `next.step == "confirm"`, before relaying the picker, fetch the human-reada
|
|
|
126
131
|
okstra wizard confirmation --state-file /var/folders/.../okstra-wizard.AbCd.json
|
|
127
132
|
```
|
|
128
133
|
|
|
129
|
-
(Substitute the literal state-file path captured in Step 2 — no `$STATE_FILE`.)
|
|
130
|
-
|
|
131
134
|
Output: `{ok: true, text: "선택 확인:\n task-type : ...\n ..."}`. Print `text` to the user, then render the `confirm` picker (Proceed / Edit).
|
|
132
135
|
|
|
133
136
|
## Step 5: Render the task bundle
|
|
@@ -138,10 +141,12 @@ When `next.kind == "done"`, fetch the final args:
|
|
|
138
141
|
okstra wizard render-args --state-file /var/folders/.../okstra-wizard.AbCd.json
|
|
139
142
|
```
|
|
140
143
|
|
|
141
|
-
(Again: literal state-file path, no `$STATE_FILE`.)
|
|
142
|
-
|
|
143
144
|
Output: `{ok: true, args: {"project-root": "...", "task-type": "...", ...}}`. Build the `okstra render-bundle` invocation from `args`, passing each key as `--<key>` and the value verbatim (including empty strings — they are intentional `use phase default` markers).
|
|
144
145
|
|
|
146
|
+
**Empty-value rule (same as Step 3)**: every flag whose value is the empty string MUST still be passed explicitly as `--<key> ""`. For example: `--workers ""`, `--directive ""`, `--related-tasks ""`. Omitting the flag is forbidden — `render-bundle` distinguishes "flag absent" from "flag present with empty value", and the wizard's intent is always the latter.
|
|
147
|
+
|
|
148
|
+
**Escaping rule**: inside a double-quoted value, escape any literal `"` as `\"`. Do not collapse `--key ""` into `--key` even when the value is empty.
|
|
149
|
+
|
|
145
150
|
```bash
|
|
146
151
|
okstra render-bundle \
|
|
147
152
|
--project-root "<args.project-root>" \
|
|
@@ -173,13 +178,7 @@ You can delete the literal state-file path after this point — its job is done.
|
|
|
173
178
|
|
|
174
179
|
## Step 6: Take over as Claude lead
|
|
175
180
|
|
|
176
|
-
Read
|
|
177
|
-
|
|
178
|
-
1. `<INSTRUCTION_SET_DIR>/claude-execution-prompt.md` — the lead prompt
|
|
179
|
-
2. `<INSTRUCTION_SET_DIR>/analysis-profile.md` — per-task-type allowed outputs / forbidden actions
|
|
180
|
-
3. `<INSTRUCTION_SET_DIR>/analysis-material.md` — task brief + directive
|
|
181
|
-
4. `<INSTRUCTION_SET_DIR>/reference-expectations.md`
|
|
182
|
-
5. `<INSTRUCTION_SET_DIR>/final-report-template.md`
|
|
181
|
+
Read `<INSTRUCTION_SET_DIR>/claude-execution-prompt.md` verbatim and enter `Claude lead` mode. The lead prompt itself enumerates every other instruction-set file to load (`analysis-profile.md`, `analysis-material.md`, `reference-expectations.md`, `final-report-template.md`, the run manifest, the team-state artifact, etc.) — follow its order, do not preempt it.
|
|
183
182
|
|
|
184
183
|
Then proceed through the phases exactly as the lead prompt directs (Phase 1 context → Phase 2+ worker dispatch → final synthesis → final report).
|
|
185
184
|
|
|
@@ -197,15 +196,17 @@ okstra config set pr-template-path "<path>" --scope project
|
|
|
197
196
|
okstra config set pr-template-path "<path>" --scope global
|
|
198
197
|
```
|
|
199
198
|
|
|
200
|
-
The scope is exposed
|
|
199
|
+
The scope is held in the wizard state but is not yet exposed by any `okstra wizard` subcommand. Until the subcommand below ships, read the JSON state file directly with the `Read` tool (literal path captured in Step 2) and inspect the `pr_template_scope` field — it is a plain serialized `WizardState`. Do not shell out (`python3 -c`, `jq`, etc.); the literal-token Bash rule rejects them.
|
|
200
|
+
|
|
201
|
+
## Out-of-scope backlog
|
|
201
202
|
|
|
202
|
-
|
|
203
|
+
- **`okstra wizard pr-template-scope --state-file PATH`**: add a thin subcommand to `scripts/okstra_ctl/wizard.py` that prints `{ok: true, scope: "once" | "project" | "global"}` so this skill can drop the `Read`-the-raw-state-file detour. The subcommand should reuse the existing `load_state_file` path; no schema changes required.
|
|
203
204
|
|
|
204
205
|
## Concurrency
|
|
205
206
|
|
|
206
207
|
- `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.
|
|
207
|
-
- Each wizard run owns its own
|
|
208
|
-
- The skill must NOT call `okstra.sh` or any other bash entrypoint that would re-implement the orchestration. The wizard + `render-bundle` is the single authority.
|
|
208
|
+
- Each wizard run owns its own state file (one per `okstra wizard new-state-file`); two parallel skill invocations do not collide.
|
|
209
|
+
- The skill must NOT call `okstra.sh` (or any other bash entrypoint) that would re-implement the orchestration. The wizard + `render-bundle` is the single authority.
|
|
209
210
|
|
|
210
211
|
## Failure Modes
|
|
211
212
|
|
|
@@ -10,7 +10,7 @@ model: opus
|
|
|
10
10
|
|
|
11
11
|
Generate a consolidated work schedule for all non-done tasks in a given `task-group`. The skill reads each task's `task-manifest.json` and `latestReport`, classifies tasks into phases by priority and risk, and writes a single Markdown plan file under `.project-docs/okstra/tasks/<task-group>/schedule/`.
|
|
12
12
|
|
|
13
|
-
The
|
|
13
|
+
The skill runs as a single Claude lead synthesis (lightweight mode). A `--cross-verify` multi-agent variant was previously sketched here but never specified end-to-end; it has been dropped pre-1.0 and is tracked as a follow-up if multi-agent schedule verification is needed later.
|
|
14
14
|
|
|
15
15
|
## When to Use
|
|
16
16
|
|
|
@@ -30,12 +30,12 @@ The default mode is lightweight (single Claude lead synthesis). The `--cross-ver
|
|
|
30
30
|
|
|
31
31
|
**Explicit command**:
|
|
32
32
|
- `okstra schedule <task-group>`
|
|
33
|
-
- `okstra schedule <task-group> --cross-verify`
|
|
34
33
|
- `okstra schedule <task-group> --title "<custom title>"`
|
|
34
|
+
- `okstra schedule <task-group> --directive-file <abs-path>` (optional; see "Directive override" below)
|
|
35
35
|
|
|
36
36
|
If `--title` is omitted, derive a default title from `task-group` (e.g. `uploadFont` → `uploadFont — Work Schedule`).
|
|
37
37
|
|
|
38
|
-
##
|
|
38
|
+
## Preflight: Verify okstra runtime + project setup
|
|
39
39
|
|
|
40
40
|
Run before anything else in this skill:
|
|
41
41
|
|
|
@@ -81,17 +81,19 @@ This skill performs cross-task synthesis (multi-task classification, dependency
|
|
|
81
81
|
### Step 1: Resolve task-group and collect tasks
|
|
82
82
|
|
|
83
83
|
1. Read `.project-docs/okstra/discovery/task-catalog.json`.
|
|
84
|
-
2.
|
|
84
|
+
2. **Normalise the user-supplied `<task-group>` argument:** lowercase it, then strip every character that is not `[a-z0-9]` (drop spaces, hyphens, underscores, dots, etc.). Apply the same transform to each entry's `taskGroupPathSegment`. Match when the two normalised forms are equal. This is the single comparison rule — do NOT also fall back to the raw `taskGroup` field.
|
|
85
85
|
3. If no tasks found, output `해당 task-group을 찾을 수 없습니다.` and stop.
|
|
86
86
|
4. For each matched task, read `.project-docs/okstra/tasks/<task-group-segment>/<task-id-segment>/task-manifest.json` directly. Catalog data may be stale; the manifest is authoritative.
|
|
87
87
|
5. **Derive `<project-id>`** for the schedule header: prefer `task-catalog.json`'s top-level `projectId` field if present, otherwise use the first matched manifest's `projectId` field. Do not invent a value.
|
|
88
88
|
|
|
89
89
|
### Step 2: Filter by workStatus
|
|
90
90
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
91
|
+
Since the `feat(scripts/render): project workStatus fields into task-catalog entries` change (commit `c44c36b`), `workStatus` is also surfaced directly inside each catalog entry — Step 1 still re-reads each `task-manifest.json` because the manifest is authoritative, but no extra fetch is needed beyond that.
|
|
92
|
+
|
|
93
|
+
For inference rules when `workStatus` is missing or empty, **defer to the inference table in `skills/okstra-status/SKILL.md` ("Step 4 → Inferring workStatus")** instead of duplicating it here. Apply that table to derive a working value, then filter:
|
|
94
|
+
|
|
95
|
+
- If the resolved value is `done` (set by the user OR inferred via `currentStatus == "completed"` + terminal next-phase) → exclude.
|
|
96
|
+
- Otherwise (`todo` / `in-progress` / `blocked` / `phase-done` / explicit user value / inferred non-done) → include.
|
|
95
97
|
|
|
96
98
|
If after filtering 0 tasks remain, output:
|
|
97
99
|
```
|
|
@@ -133,20 +135,35 @@ If the report file does not exist or cannot be parsed:
|
|
|
133
135
|
If parsing fails for a specific section:
|
|
134
136
|
- Mark the entry with `[PARSE-ERROR: <section>]` and continue.
|
|
135
137
|
|
|
136
|
-
### Step 4:
|
|
138
|
+
### Step 4: Synthesis
|
|
137
139
|
|
|
138
|
-
|
|
139
|
-
- **`--cross-verify`**: Invoke the parent `okstra` skill flow with the schedule synthesis itself as the analysis target. The schedule generation becomes the cross-verified deliverable.
|
|
140
|
+
Claude lead synthesises the schedule directly using collected data. Proceed to Step 5.
|
|
140
141
|
|
|
141
142
|
### Step 5: Phase classification heuristic
|
|
142
143
|
|
|
143
|
-
Classify each task into one of three phases based on report data
|
|
144
|
+
Classify each task into one of three phases based on report data.
|
|
145
|
+
|
|
146
|
+
**`workCategory` accepted values** (de-facto enum, from `scripts/okstra_ctl/worktree.py::_WORK_CATEGORY_PREFIX` plus the `unknown` fallback emitted by `render.py`):
|
|
147
|
+
|
|
148
|
+
| workCategory | Default phase |
|
|
149
|
+
|--------------|---------------|
|
|
150
|
+
| `bugfix` | Phase 1 (when risk is High/Med-High); otherwise Phase 2 |
|
|
151
|
+
| `feature` | Phase 2 |
|
|
152
|
+
| `improvement` | Phase 2 |
|
|
153
|
+
| `refactor` | Phase 3 |
|
|
154
|
+
| `ops` | Phase 3 |
|
|
155
|
+
| `docs` / `doc` | Phase 2 |
|
|
156
|
+
| `unknown` (or unmatched / missing) | **Phase 2**, with a one-line rationale `> _workCategory '<raw-value>' 미정의 — Phase 2로 기본 분류._` at the top of that phase section |
|
|
157
|
+
|
|
158
|
+
Priority overrides category:
|
|
159
|
+
|
|
160
|
+
- **Phase 1 (안정성/Critical)**: priority `P0`, OR `workCategory == "bugfix"` with High / Med-High risk
|
|
161
|
+
- **Phase 2 (개선/기능)**: priority `P1` or `P2`, OR `workCategory in {"feature", "improvement", "docs", "doc"}`, OR fallback per the table above
|
|
162
|
+
- **Phase 3 (확장/아키텍처)**: priority `P3`, OR `workCategory in {"refactor", "ops"}`, OR multi-repo + infrastructure scope
|
|
144
163
|
|
|
145
|
-
|
|
146
|
-
- **Phase 2 (개선/기능)**: priority `P1` or `P2`, `workCategory in {"improvement", "feature"}`
|
|
147
|
-
- **Phase 3 (확장/아키텍처)**: priority `P3`, OR multi-repo + infrastructure scope
|
|
164
|
+
When the classification is genuinely ambiguous after applying the table + priority override, place the task in the closest phase and add a one-line rationale at the top of that phase section.
|
|
148
165
|
|
|
149
|
-
|
|
166
|
+
> Note: enum codification (turning this de-facto list into a `validators/`-enforced contract) is out of scope for this skill — file as a follow-up if needed.
|
|
150
167
|
|
|
151
168
|
### Step 6: Write the schedule file
|
|
152
169
|
|
|
@@ -168,7 +185,7 @@ After writing the file, reply briefly:
|
|
|
168
185
|
- 포함 task: N개
|
|
169
186
|
- 제외(done) task: M개
|
|
170
187
|
- 예상 소요: X.X ~ Y.Y days (Effort 합산)
|
|
171
|
-
- 모드: lightweight
|
|
188
|
+
- 모드: lightweight
|
|
172
189
|
```
|
|
173
190
|
|
|
174
191
|
## Audience (READ FIRST — drives everything below)
|
|
@@ -312,7 +329,17 @@ When skipping, follow the skip-reason note rule below — but the skip should be
|
|
|
312
329
|
|
|
313
330
|
#### Directive override (highest priority)
|
|
314
331
|
|
|
315
|
-
Before applying the heuristics above, **check
|
|
332
|
+
Before applying the heuristics above, **check the schedule-level directive source** for a `## Directive` section.
|
|
333
|
+
|
|
334
|
+
**Resolution order (first hit wins):**
|
|
335
|
+
|
|
336
|
+
1. Absolute path passed via the `--directive-file <abs-path>` argument when invoking the skill.
|
|
337
|
+
2. `<PROJECT_ROOT>/.project-docs/okstra/tasks/<task-group-segment>/schedule/instruction-set/analysis-material.md` (the canonical schedule-level instruction-set location — okstra writes here when a schedule run is dispatched with `--directive`).
|
|
338
|
+
3. **No directive file** — fall through and apply the default heuristic without any override. This is the normal case; do not warn, do not block.
|
|
339
|
+
|
|
340
|
+
If a directive source is found and contains a `## Directive` section that affects Gantt rendering — e.g. "render a Gantt even with single XL task", "no Gantt needed" — that directive **overrides the heuristic and the skip-reason rule** for the affected section. When following a Directive override that contradicts the default heuristic, append a one-line note inside the rendered (or skipped) section: `> _Per Directive directive: <verbatim short excerpt>._` so the reader can trace why the section appeared/disappeared against the default. The Directive may also pre-supply day allocations, phase weights, or sub-task decompositions — use those verbatim as bar lengths in the Gantt.
|
|
341
|
+
|
|
342
|
+
A directive file that exists but contains no `## Directive` heading is treated as "no directive" — fall through to the heuristic, no warning required.
|
|
316
343
|
|
|
317
344
|
`## Gantt Chart` is the only `##` section that MAY be added beyond the 11 mandatory ones. Any other extra `##` heading is forbidden.
|
|
318
345
|
|
|
@@ -415,6 +442,10 @@ Required shapes:
|
|
|
415
442
|
| Skipping `## Gantt Chart` because the data is "wide range / single task / part-day allocation pending" | Per the render-by-default rule, these are reasons to render an **estimate-tagged** chart, not to skip. Skip is only legitimate when day data literally does not exist (all-XXL or no effort sizing anywhere) |
|
|
416
443
|
| Rendering Gantt as a mermaid (`` ```mermaid `` / `gantt` block) or any other graph DSL (PlantUML, Graphviz, etc.) | This skill renders ASCII only. Mermaid output is forbidden — use the ASCII Gantt format described above. Validators may reject mermaid blocks under this heading |
|
|
417
444
|
|
|
445
|
+
## Known Validator Gaps (out of scope here)
|
|
446
|
+
|
|
447
|
+
- The ambiguous-classification rationale required by Step 5 (`> _workCategory '<raw>' 미정의 …_` / nearest-phase rationale) is **not** currently enforced by `validators/validate-schedule.py`. The skill is responsible for emitting it; closing the validator gap requires a validator change and is tracked as a follow-up.
|
|
448
|
+
|
|
418
449
|
## Self-Validation Before Reporting Completion
|
|
419
450
|
|
|
420
451
|
After writing the file and before printing the completion message in Step 7, you MUST:
|
|
@@ -596,13 +627,13 @@ Markdown bullet list of next concrete engineering actions, one item per line: `-
|
|
|
596
627
|
|
|
597
628
|
| Case | Handling |
|
|
598
629
|
|------|----------|
|
|
599
|
-
| `workStatus` field absent or empty |
|
|
630
|
+
| `workStatus` field absent or empty | Resolve via the okstra-status inference table; include unless the resolved value is `done` |
|
|
600
631
|
| Filtered task count is 0 | Emit "모든 task가 done" message; do NOT create a file |
|
|
601
632
|
| `latestReportPath` missing or unreadable | Tag entry with `[NEEDS-OKSTRA-RUN]`; include manifest metadata only |
|
|
602
633
|
| Report parsing fails for a specific section | Tag with `[PARSE-ERROR: <section>]`; continue with the rest |
|
|
603
634
|
| `task-group` argument matches no tasks | Output "해당 task-group을 찾을 수 없습니다." and stop |
|
|
604
635
|
| Catalog and manifest disagree on `workStatus` | Manifest wins (catalog may be stale) |
|
|
605
|
-
| Multiple `task-group` casings |
|
|
636
|
+
| Multiple `task-group` casings / punctuation variants | Normalise both sides (lowercase + strip non-`[a-z0-9]`) then compare against `taskGroupPathSegment` only. Use the manifest's `taskGroupPathSegment` verbatim for path output. |
|
|
606
637
|
|
|
607
638
|
## Output Rules
|
|
608
639
|
|