okstra 0.111.0 → 0.113.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.
Files changed (64) hide show
  1. package/README.kr.md +2 -2
  2. package/README.md +2 -2
  3. package/bin/okstra +7 -1
  4. package/docs/for-ai/README.md +2 -2
  5. package/docs/for-ai/skills/okstra-brief.md +2 -3
  6. package/docs/for-ai/skills/okstra-container-build.md +2 -3
  7. package/docs/for-ai/skills/okstra-inspect.md +5 -12
  8. package/docs/for-ai/skills/okstra-rollup.md +3 -4
  9. package/docs/for-ai/skills/okstra-run.md +3 -5
  10. package/docs/for-ai/skills/okstra-schedule.md +2 -7
  11. package/docs/for-ai/skills/okstra-setup.md +1 -1
  12. package/docs/kr/architecture/storage-model.md +1 -2
  13. package/docs/kr/architecture.md +2 -2
  14. package/docs/kr/cli.md +4 -2
  15. package/docs/project-structure-overview.md +5 -3
  16. package/package.json +1 -1
  17. package/runtime/BUILD.json +2 -2
  18. package/runtime/agents/workers/antigravity-worker.md +1 -1
  19. package/runtime/agents/workers/claude-worker.md +1 -1
  20. package/runtime/agents/workers/codex-worker.md +1 -1
  21. package/runtime/prompts/coding-preflight/overview.md +3 -1
  22. package/runtime/prompts/launch.template.md +1 -5
  23. package/runtime/prompts/lead/context-loader.md +2 -4
  24. package/runtime/prompts/lead/convergence.md +11 -240
  25. package/runtime/prompts/lead/okstra-lead-contract.md +70 -34
  26. package/runtime/prompts/lead/plan-body-verification.md +240 -0
  27. package/runtime/prompts/lead/report-writer.md +7 -7
  28. package/runtime/prompts/lead/team-contract.md +15 -17
  29. package/runtime/prompts/profiles/_common-contract.md +1 -37
  30. package/runtime/prompts/profiles/_implementation-executor.md +2 -2
  31. package/runtime/prompts/profiles/_implementation-self-check.md +1 -0
  32. package/runtime/prompts/profiles/_implementation-verifier.md +2 -2
  33. package/runtime/prompts/profiles/final-verification.md +6 -5
  34. package/runtime/prompts/profiles/implementation-planning.md +6 -4
  35. package/runtime/prompts/profiles/implementation.md +1 -1
  36. package/runtime/prompts/profiles/improvement-discovery.md +1 -0
  37. package/runtime/prompts/profiles/requirements-discovery.md +1 -0
  38. package/runtime/python/okstra_ctl/path_hints.py +1 -0
  39. package/runtime/python/okstra_ctl/paths.py +3 -0
  40. package/runtime/python/okstra_ctl/render.py +8 -0
  41. package/runtime/python/okstra_ctl/set_work_status.py +147 -0
  42. package/runtime/python/okstra_ctl/team_reconcile.py +1 -1
  43. package/runtime/schemas/final-report-v1.0.schema.json +6 -4
  44. package/runtime/skills/okstra-brief/SKILL.md +32 -176
  45. package/runtime/skills/okstra-brief/references/reporter-confirmations.md +71 -0
  46. package/runtime/skills/okstra-brief/references/tracker-recursion.md +90 -0
  47. package/runtime/skills/okstra-container-build/SKILL.md +7 -20
  48. package/runtime/skills/okstra-graphify/SKILL.md +8 -8
  49. package/runtime/skills/okstra-inspect/SKILL.md +27 -43
  50. package/runtime/skills/okstra-rollup/SKILL.md +6 -6
  51. package/runtime/skills/okstra-run/SKILL.md +7 -16
  52. package/runtime/skills/okstra-schedule/SKILL.md +64 -419
  53. package/runtime/skills/okstra-setup/SKILL.md +25 -223
  54. package/runtime/skills/okstra-setup/references/project-config.md +188 -0
  55. package/runtime/templates/reports/final-report.template.md +24 -1
  56. package/runtime/templates/reports/improvement-discovery-input.template.md +3 -2
  57. package/runtime/templates/reports/schedule.template.md +2 -2
  58. package/runtime/templates/worker-prompt-preamble.md +5 -1
  59. package/runtime/validators/validate-run.py +8 -7
  60. package/src/cli-registry.mjs +14 -0
  61. package/src/commands/inspect/set-work-status.mjs +31 -0
  62. package/src/commands/lifecycle/check-project.mjs +68 -56
  63. package/src/commands/lifecycle/install.mjs +1 -0
  64. package/src/commands/lifecycle/preflight.mjs +82 -0
@@ -16,18 +16,15 @@ Single entry point for the okstra user-test container runtime. okstra provisions
16
16
  | `stop-watcher` | Reap the watcher/tail panes only — the containers keep running. |
17
17
  | `down` | Tear down the containers (label query) and reap orphan watcher panes; `--all` covers every container group in the project. |
18
18
 
19
- ## Step 0: Verify okstra runtime + project setup (shared)
19
+ ## Step 0: Preflight (shared)
20
20
 
21
- Before any sub-command, 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 `&&`, and do **not** introduce a `$OKSTRA_CMD` variable or an `npx -y okstra@latest` fallback — those leading tokens defeat the permission match and force a confirmation prompt on every call. The LLM (you) inspects each command's output and decides what to do next in natural language — never in shell.
21
+ Before any sub-command, run one Bash tool call, starting with the literal token `okstra` (never wrapped in `if`/`eval`/`export`/`$(...)`/`VAR=...`/`||`/`&&`/`npx` a non-literal leading token defeats the `Bash(okstra:*)` permission match):
22
22
 
23
- 1. `okstra ensure-installed --runtime claude-code`
24
- If this exits non-zero, tell the user: "okstra not installed — run `/okstra-setup` first." Then stop. Do **not** try to invoke `npx -y okstra@latest ...` as a fallback.
25
-
26
- 2. `okstra check-project --json`
27
- Reads the project from the current working directory. Parse the JSON from stdout. The shape is `{ok, projectRoot, projectJsonPath, projectId}`.
23
+ ```bash
24
+ okstra preflight --runtime claude-code --json
25
+ ```
28
26
 
29
- - `ok: false` → tell the user: "this project has no okstra setup. Run `/okstra-setup` first." Then stop.
30
- - `ok: true` → carry `projectRoot` as a literal string and pass it as `--project-root <projectRoot>` to every `okstra container` call below.
27
+ Parse the stdout JSON. `ok: true` → carry `projectRoot` as a literal string and pass it as `--project-root <projectRoot>` to every `okstra container` call below. `ok: false` → tell the user to run `/okstra-setup` first, then stop. If the call fails with `unknown command: preflight`, the `okstra` binary on PATH predates this skill tell the user to update it (`npm i -g okstra@latest`), then stop (`/okstra-setup` does not update the binary).
31
28
 
32
29
  Docker itself must be installed and running for `up`/`status`/`down` to work. If a sub-command fails with a docker connection error, tell the user to start Docker (Desktop / daemon) and retry — do not try to start docker yourself.
33
30
 
@@ -35,7 +32,7 @@ Subsequent `okstra container <subcmd>` calls self-bootstrap their Python path, s
35
32
 
36
33
  ## Step 1: Dispatch by intent
37
34
 
38
- Classify the user's request into one sub-command using the trigger table above.
35
+ Classify the user's request into one sub-command using the sub-command table above.
39
36
 
40
37
  - Clear verbs route directly: "띄워/올려/up" → `up`; "상태/status" → `status`; "로그/logs" → `logs`; "watcher 멈춰/stop-watcher" → `stop-watcher`; "내려/down" → `down`.
41
38
  - If the request is ambiguous (e.g. "okstra container 좀 봐줘"), present a numbered picker. Recommend the 1–2 most likely facets first, and make the **last option always "직접 입력"** so the user can name any facet:
@@ -61,8 +58,6 @@ Every sub-command needs a **task-key** (`<project-id>:<task-group>:<task-id>`)
61
58
 
62
59
  ## up
63
60
 
64
- Trigger phrases: "okstra container up", "컨테이너 띄워", "컨테이너 올려", "유저 테스트 환경 띄워", "docker compose 올려줘", "이 task 컨테이너로 띄워".
65
-
66
61
  Brings up the task's container group: integrates the implementation stages into the task worktree, synthesizes the compose env override, runs `docker compose up -d`, polls healthchecks, and attaches a tmux watcher pane.
67
62
 
68
63
  **Preconditions** (state them if unmet, do not guess):
@@ -84,8 +79,6 @@ After a successful `up`, tell the user how to reach the running build (the compo
84
79
 
85
80
  ## status
86
81
 
87
- Trigger phrases: "okstra container status", "컨테이너 상태", "컨테이너 떠 있어?", "container status".
88
-
89
82
  Reports the running containers (queried by run-trace label — the source of truth for "is it up") plus the watcher metadata recorded in the registry.
90
83
 
91
84
  ```bash
@@ -106,8 +99,6 @@ If `containers` is empty, say the group is not running and offer `up`. Treat the
106
99
 
107
100
  ## logs
108
101
 
109
- Trigger phrases: "okstra container logs", "컨테이너 로그", "container logs", "로그 어디서 봐".
110
-
111
102
  The live log stream lives in the tmux watcher pane, not in a file. This sub-command points at the watcher findings directory and the per-service watcher state.
112
103
 
113
104
  ```bash
@@ -126,8 +117,6 @@ Parse the stdout JSON (`{watchersDir, watchers}`). Report the `watchersDir` host
126
117
 
127
118
  ## stop-watcher
128
119
 
129
- Trigger phrases: "okstra container stop-watcher", "watcher 멈춰", "감시 종료", "stop watcher", "watcher 만 꺼줘".
130
-
131
120
  Reaps the watcher/tail tmux panes for the task **without stopping the containers**. Use when the user wants to silence the monitor but keep the build running.
132
121
 
133
122
  ```bash
@@ -140,8 +129,6 @@ Parse the stdout JSON (`{reapedPanes, note}`). Confirm which panes were reaped a
140
129
 
141
130
  ## down
142
131
 
143
- Trigger phrases: "okstra container down", "컨테이너 내려", "컨테이너 종료", "container down", "전부 내려줘".
144
-
145
132
  Tears down the container group (removes containers found by the run-trace label) and reaps orphan watcher panes.
146
133
 
147
134
  Single task:
@@ -20,17 +20,17 @@ Only `.okstra/**/*.md` (final reports, `decisions/*.md`, `glossary.md`, briefs)
20
20
  | `wiki` | Agent-crawlable wiki (`index.md` + one article per community). |
21
21
  | `mcp` | Start a stdio MCP server exposing the graph to other agents (opt-in — additionally needs `pip install mcp`). |
22
22
 
23
- ## Step 0: Verify okstra runtime + project setup (shared)
23
+ ## Step 0: Preflight (shared)
24
24
 
25
- Before any sub-command, run each command below as a **separate Bash tool call**. Each starts with the literal token `okstra` so the `Bash(okstra:*)` permission match succeeds. Do **not** wrap them in `if`, `eval`, `export`, `$(...)`, `VAR=...`, `||`, `&&`, and do **not** introduce an `$OKSTRA_CMD` variable or an `npx -y okstra@latest` fallback — leading tokens defeat the permission match. You (the LLM) inspect each command's output and decide the next step in natural language, never in shell.
25
+ Before any sub-command, run one Bash tool call, starting with the literal token `okstra` (never wrapped in `if`/`eval`/`export`/`$(...)`/`VAR=...`/`||`/`&&`/`npx` a non-literal leading token defeats the `Bash(okstra:*)` permission match):
26
26
 
27
- 1. `okstra ensure-installed --runtime claude-code`
28
- If this exits non-zero, tell the user: "okstra not installed — run `/okstra-setup` first." Then stop. Do **not** try `npx -y okstra@latest ...` as a fallback.
27
+ ```bash
28
+ okstra preflight --runtime claude-code --json
29
+ ```
29
30
 
30
- 2. `okstra check-project --json`
31
- Resolves PROJECT_ROOT from the Bash call's cwd, looks for `.okstra/project.json`, and prints `{ok, projectRoot, projectJsonPath, projectId}` (plus a `stage` on failure). Parse the JSON from stdout.
32
- - `ok: true` → carry `projectRoot` as a literal string; it is the `--project-root` value for every sub-command below.
33
- - `ok: false` → before concluding "no setup", ask whether the user pointed at a specific project directory. If so, re-run `okstra check-project --cwd <that-dir> --json` (the leading `okstra` token keeps the permission match). Only if this **also** returns `ok:false` do you tell the user: "this project has no okstra setup. Run `/okstra-setup` first." Then stop.
31
+ Parse the stdout JSON:
32
+ - `ok: true` carry `projectRoot` as a literal string; it is the `--project-root` value for every sub-command below.
33
+ - `ok: false` → before concluding "no setup", ask whether the user pointed at a specific project directory. If so, re-run `okstra preflight --runtime claude-code --cwd <that-dir> --json`. Only if this **also** returns `ok:false` do you tell the user: "this project has no okstra setup. Run `/okstra-setup` first." Then stop. If the call fails with `unknown command: preflight`, the `okstra` binary on PATH predates this skill — tell the user to update it (`npm i -g okstra@latest`), then stop (`/okstra-setup` does not update the binary).
34
34
 
35
35
  Every `okstra graphify` call below passes `--project-root <projectRoot>` — `--project-root` is REQUIRED and there is no cwd injection; a bare `okstra graphify build` fails with a usage error.
36
36
 
@@ -20,23 +20,19 @@ Single read-side entry point for okstra runtime inspection plus the one status m
20
20
  | `error-zip` | Collect cross-project okstra error logs into an anonymized zip (report + raw) and summarize clusters. |
21
21
  | `recap` | Summarize a task's run-to-run phase transitions, then answer free-form questions over its `.okstra` artifacts. Appends each summary/Q&A to `recap/recap-log.jsonl`. |
22
22
 
23
- ## Step 0: Verify okstra runtime + project setup (shared)
23
+ ## Step 0: Preflight (shared)
24
24
 
25
- Before any sub-command, 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 `&&`, and do **not** introduce a `$OKSTRA_CMD` variable or an `npx -y okstra@latest` fallback — those leading tokens defeat the permission match and force a confirmation prompt on every call. The LLM (you) inspects each command's output and decides what to do next in natural language — never in shell.
25
+ Before any sub-command, run one Bash tool call, starting with the literal token `okstra` (never wrapped in `if`/`eval`/`export`/`$(...)`/`VAR=...`/`||`/`&&`/`npx` a non-literal leading token defeats the `Bash(okstra:*)` permission match):
26
26
 
27
- 1. `okstra ensure-installed --runtime claude-code`
28
- If this exits non-zero, tell the user: "okstra not installed — run `/okstra-setup` first." Then stop. Do **not** try to invoke `npx -y okstra@latest ...` as a fallback.
29
-
30
- 2. `okstra check-project --json`
31
- Resolves PROJECT_ROOT from the directory the Bash call runs in, looks for `.okstra/project.json`, and prints `{ok, projectRoot, projectJsonPath, projectId}` (plus a `stage` on failure). Parse the JSON from stdout.
27
+ ```bash
28
+ okstra preflight --runtime claude-code --json
29
+ ```
32
30
 
33
- `check-project` only sees the cwd of the Bash call. When the session cwd already *is* the target project — the common case — the bare form is right. But when the user is asking about a project that is **not** the cwd (a sibling repo, a monorepo subdir, or a project named explicitly in the request), the bare form resolves to the wrong project or none and returns `ok:false`. That is a false negative, not a missing setup do not hard-stop on it.
31
+ The project check only sees the cwd of the Bash call. When the user is asking about a project that is **not** the cwd (a sibling repo, a monorepo subdir, or a project named explicitly in the request), the bare form resolves to the wrong project or none and returns `ok:false` a false negative, not a missing setup; do not hard-stop on it.
34
32
 
35
- Branch on the result:
36
- - `ok: true` → carry `projectRoot` as a literal string; it is the base for every sub-command step below.
37
- - `ok: false` (or exit code 2 / a `stage` like `project_root_unresolved`) → before concluding "no setup", ask whether the user pointed at a specific project directory. If they did, re-run targeting it:
38
- `okstra check-project --cwd <that-dir> --json`
39
- `--cwd` is the sanctioned way to target a project without a leading `cd`/`export`: the command still starts with the literal `okstra` token, so the `Bash(okstra:*)` permission match holds (a leading `cd` is exactly what would break it). Only if this **also** returns `ok:false` do you tell the user: "this project has no okstra setup. Run `/okstra-setup` first." Then stop.
33
+ Branch on the stdout JSON:
34
+ - `ok: true` → carry `projectRoot` as a literal string; it is the base for every sub-command step below.
35
+ - `ok: false` → before concluding "no setup", ask whether the user pointed at a specific project directory. If they did, re-run targeting it: `okstra preflight --runtime claude-code --cwd <that-dir> --json` (`--cwd` is the sanctioned way to target a project — a leading `cd` would break the permission match). Only if this **also** returns `ok:false` do you tell the user: "this project has no okstra setup. Run `/okstra-setup` first." Then stop. If the call fails with `unknown command: preflight`, the `okstra` binary on PATH predates this skill — tell the user to update it (`npm i -g okstra@latest`), then stop (`/okstra-setup` does not update the binary).
40
36
 
41
37
  Carry the resolved `projectRoot` into the sub-commands: read file artifacts under `<projectRoot>/.okstra/...`, and for sub-command CLIs that accept it (e.g. `recap`, `context-cost`) pass `--cwd <projectRoot>` / `--project-root <projectRoot>` so they target the same project rather than the Bash cwd. Subsequent `okstra <subcmd>` calls self-bootstrap their Python path, so this skill never needs `okstra paths --shell` / `export PYTHONPATH=...`.
42
38
 
@@ -155,7 +151,7 @@ Recognize requests to change a task's `workStatus` and update the corresponding
155
151
 
156
152
  Natural language: "DEV-6827 done으로 바꿔줘", "PROD-1623을 blocked로 표시", "DEV-9047 진행중", "Mark DEV-6827 as done".
157
153
 
158
- Explicit phrasing (recognized user utterances — these are **not** okstra CLI subcommands; `status.4` edits the manifest directly):
154
+ Explicit phrasing (recognized user utterances — normalize each to a `okstra set-work-status` call below):
159
155
  - `okstra status set <task-id> <status>`
160
156
  - `okstra status set <task-group> <task-id> <status>` (disambiguation)
161
157
  - `okstra mark <task-id> <status>`
@@ -163,31 +159,21 @@ Explicit phrasing (recognized user utterances — these are **not** okstra CLI s
163
159
 
164
160
  Accepted `<status>` values: `todo`, `in-progress`, `blocked`, `done`.
165
161
 
166
- **Procedure:**
162
+ **Procedure:** run the update through the CLI (one Bash call, literal `okstra` token) — never edit `task-manifest.json` by hand:
167
163
 
168
- 1. **Validate status value.** If not in the enum, output an error and the allowed values list. Do not modify any file.
169
- 2. **Resolve the task** with the shared resolver. The token may be a task-id or a task-group (matched on both axes; a group expands to its member tasks). `--task-group` additionally scopes the task-id match case-insensitively:
170
- ```bash
171
- okstra resolve-task-key <token> [--task-group <task-group>] --project-root <projectRoot> --json
172
- ```
173
- Branch on `matches[]`: singleproceed. Multiple → list candidates and ask the user to retry with the explicit form (`okstra status set <task-group> <TASK-ID> <status>`). None → `<TASK-ID>를 찾을 수 없습니다.` and stop.
174
- 3. **Open the matching `task-manifest.json`** at `.okstra/tasks/<task-group-segment>/<task-id-segment>/task-manifest.json`. Assemble the path from the catalog entry's `taskGroupPathSegment` and `taskIdPathSegment` fields (filesystem-safe segments emitted by the renderer) — NOT from the raw user-supplied strings, which may differ in case or contain characters normalized when the manifest was created. Prefer the `taskManifestPath` field directly when present.
175
- 4. **Update fields at the manifest root:**
176
- - `workStatus` ← new status value
177
- - `workStatusUpdatedAt` current ISO-8601 UTC timestamp (`2026-05-01T10:23:45Z`)
178
- - `workStatusNote`: if `--note` provided, set to its value; if not provided, leave any existing value untouched (do not delete, do not blank). If the field did not exist before, do not create it.
179
-
180
- **Manifest preservation (critical):**
181
- - Use a targeted in-place edit (Edit tool with old_string/new_string anchors).
182
- - Do NOT round-trip the file through `JSON.parse` + `JSON.stringify` — that reorders keys, drops trailing newlines, normalizes spacing.
183
- - Preserve existing key order, indentation, and trailing newline exactly.
184
-
185
- 5. **Confirm in Korean:**
186
- ```
187
- ✓ <TASK-ID> workStatus: <previous> → <new>
188
- ✓ task-manifest.json 업데이트됨
189
- ```
190
- `<previous>` = `(없음)` if the field was absent before.
164
+ ```bash
165
+ okstra set-work-status <token> <status> --project-root <projectRoot> --json
166
+ ```
167
+
168
+ - `<token>` is a full task-key or a bare task-id. Add `--task-group <group>` to scope a duplicated id, `--note "<note>"` to set `workStatusNote` (flag omitted → any existing note is left untouched).
169
+ - Branch on the stdout JSON: `ok: true`confirm below. `stage: "ambiguous"` → list `matches[]` (with `_matchedVia`) via a 3-option picker and retry with the chosen full task-key. `stage: "not-found"` → `<TASK-ID>를 찾을 수 없습니다.` An invalid `<status>` makes the CLI exit 2 with the allowed-values list — surface it verbatim; nothing was modified.
170
+
171
+ Confirm in Korean:
172
+ ```
173
+ ✓ <TASK-ID> workStatus: <previousWorkStatus> <workStatus>
174
+ ✓ task-manifest.json 업데이트됨
175
+ ```
176
+ `<previousWorkStatus>` = `(없음)` when the JSON's `previousWorkStatus` is empty.
191
177
 
192
178
  **Default value convention:** if `workStatus` is missing or empty, infer the display value from lifecycle state (DO NOT default to a static `in-progress`):
193
179
 
@@ -200,7 +186,7 @@ Accepted `<status>` values: `todo`, `in-progress`, `blocked`, `done`.
200
186
 
201
187
  Annotate inferred values with `(inferred)` or `(default)`. Do not back-fill on read; only write when the user explicitly issues an update.
202
188
 
203
- **Catalog sync note:** this sub-command updates `task-manifest.json` only. `discovery/task-catalog.json` may become stale until regenerated. Downstream consumers (e.g. `okstra-schedule`) should re-read each manifest directly.
189
+ **Catalog sync note:** the CLI updates `task-manifest.json` only. `discovery/task-catalog.json` may be stale until the next run regenerates it; downstream consumers (e.g. `okstra-schedule`) re-read each manifest directly.
204
190
 
205
191
  ---
206
192
 
@@ -258,7 +244,6 @@ When a user selects a specific task:
258
244
  Builds a fresh run — new run-seq, new manifest, new report — using parameters from a previous `run-manifest-*.json`. Does NOT touch old artifacts; use `history.4` to continue an interrupted session.
259
245
 
260
246
  1. Pick the source run-manifest: `runManifestPath` from `history.2`, or task's `latestRunManifestPath` from `history.1`. Note: `latestRunManifestPath` is projected from the timeline's latest run, so it is empty when the task has no recorded run yet (timeline absent) — in that case fall back to a `history.2` per-run `runManifestPath`, or ask the user.
261
- **Migrated-task fallback (do not bail out on empty paths).** Tasks migrated from the old `.project-docs/okstra/...` layout often have empty `latestRunManifestPath` / per-run `runManifestPath` in the catalog and timeline even though the manifests exist on disk. Before asking the user, glob `<projectRoot>/.okstra/tasks/<group-seg>/<id-seg>/runs/**/manifests/run-manifest-*.json` and pick the latest by the `YYYY-MM-DD_HH-MM-SS` timestamp in the filename. Only if that glob is also empty do you ask the user.
262
247
  2. Read the manifest and extract required arguments:
263
248
  - `projectId` → `--project-id`
264
249
  - `taskGroup` → `--task-group`
@@ -289,9 +274,8 @@ Continues an existing Claude session for an unfinished run. Does NOT create a ne
289
274
 
290
275
  1. Read `latestResumeCommandPath` from `history.1` (or `resumeCommandPath` from a `history.2` timeline entry).
291
276
  2. Verify the file exists on disk.
292
- 3. **Migrated-task fallback (do not declare "no resume" on an empty catalog path).** If the catalog/timeline path is empty or points at a non-existent `.project-docs/okstra/...` location, glob the on-disk scripts before concluding absent: `<projectRoot>/.okstra/tasks/<group-seg>/<id-seg>/runs/**/sessions/claude-resume-*.sh`, pick the latest by the `YYYY-MM-DD_HH-MM-SS` timestamp in the filename, and confirm it exists.
293
- 4. If a script is found: `bash <resume-command-path>`.
294
- 5. If the glob is also empty: `No resume script available for this run. Use 'history.3' to start a fresh run instead.`
277
+ 3. If it exists: `bash <resume-command-path>`.
278
+ 4. If the path is empty or the file is missing: `No resume script available for this run. Use 'history.3' to start a fresh run instead.`
295
279
 
296
280
  ---
297
281
 
@@ -10,15 +10,15 @@ Cross-task roll-up: collect every catalog task's run results (optionally scoped
10
10
 
11
11
  This skill is read-only. It never mutates task artifacts.
12
12
 
13
- ## Step 0: Verify okstra runtime + project setup
13
+ ## Step 0: Preflight
14
14
 
15
- Run each command as a **separate Bash tool call**, each starting with the literal token `okstra` so the `Bash(okstra:*)` permission match succeeds. Do **not** wrap any of them in `if`, `eval`, `$(...)`, `VAR=...`, `||`, `&&`, or an `npx` fallback those defeat the permission match.
15
+ Run one Bash tool call, starting with the literal token `okstra` (never wrapped in `if`/`eval`/`$(...)`/`VAR=...`/`||`/`&&`/`npx` a non-literal leading token defeats the `Bash(okstra:*)` permission match):
16
16
 
17
- 1. `okstra ensure-installed --runtime claude-code`
18
- Non-zero exit → tell the user: "okstra not installed — run `/okstra-setup` first." Then stop.
17
+ ```bash
18
+ okstra preflight --runtime claude-code --json
19
+ ```
19
20
 
20
- 2. `okstra check-project --json`
21
- Parse `{ok, projectRoot, ...}` from stdout. `ok: false` → "this project has no okstra setup. Run `/okstra-setup` first." Then stop. `ok: true` → carry `projectRoot` as a literal string.
21
+ Parse the stdout JSON. `ok: true` → carry `projectRoot` as a literal string. `ok: false` → tell the user to run `/okstra-setup` first, then stop. If the call fails with `unknown command: preflight`, the `okstra` binary on PATH predates this skill — tell the user to update it (`npm i -g okstra@latest`), then stop (`/okstra-setup` does not update the binary).
22
22
 
23
23
  ## Step 1: Resolve scope
24
24
 
@@ -54,22 +54,15 @@ The final `confirm` step is a normal `pick` step with three options — `Proceed
54
54
 
55
55
  Never invent additional questions. Never reorder. **Never drop, hide, or merge a `pick` / `pick_group` option** — render every `options[]` entry as its own selectable `AskUserQuestion` choice, including entries that carry a `(default)` / `(recommended)` suffix. Do NOT collapse a multi-option pick into a "recommended + 직접 입력 / Other" shortlist: the wizard's `options[]` array IS the complete, authoritative choice set. Example: if a pick's `options[]` carries N entries, render all N as selectable choices — never abbreviate a multi-option step down to one recommended value. The run-prompt recommendation rule (1–2 추천 + 직접 입력) applies ONLY to prompts this skill authors itself (e.g. the conformance-waiver picker), never to wizard-provided `options[]`. Never use `AskUserQuestion` for `text` prompts — the wizard explicitly chose `text` to avoid the picker-Other re-render lag.
56
56
 
57
- ## Step 1: Verify okstra runtime + project setup
57
+ ## Step 1: Preflight
58
58
 
59
- 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.
59
+ Run one Bash tool call (Bash invocation rule from the top of this file applies):
60
60
 
61
- 1. `okstra ensure-installed --runtime claude-code`
62
- If this exits non-zero, tell the user: "okstra runtime missing — run `/okstra-setup` first." Then stop. Do **not** try to invoke `npx -y okstra@latest ...` as a fallback.
63
-
64
- 2. `okstra paths --json`
65
- 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.
66
-
67
- 3. `okstra check-project --json`
68
- Reads the project from the current working directory. Parse the JSON from stdout. If `ok` is `false`, tell the user: "this project has no okstra setup. Run `/okstra-setup` first." Then stop.
69
-
70
- Parse `projectRoot` and `projectId` from the successful `check-project --json` output and carry them as literal strings into Step 2.
61
+ ```bash
62
+ okstra preflight --runtime claude-code --json
63
+ ```
71
64
 
72
- > 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 installedrun `/okstra-setup` first." 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.
65
+ Parse the stdout JSON. `ok: true` carry `projectRoot` and `projectId` as literal strings into Step 2. `ok: false` (or `okstra` not on `PATH` at all) tell the user: "okstra not set up — run `/okstra-setup` first." Then stop. If the call fails with `unknown command: preflight`, the `okstra` binary on PATH predates this skill tell the user to update it (`npm i -g okstra@latest`), then stop (`/okstra-setup` does not update the binary). Do **not** try to invoke `npx -y okstra@latest ...` as a fallback — `npx` is not on the literal-token allow-list and will force a confirmation prompt on every wizard call afterward. Every subsequent `okstra <subcmd>` call self-bootstraps its Python path, so never `export PYTHONPATH=...`.
73
66
 
74
67
  ## Step 2: Initialize the wizard
75
68
 
@@ -170,9 +163,7 @@ If an action has an unknown `command`, `key`, or `scope`, stop and report the wi
170
163
 
171
164
  Build the `okstra render-bundle` invocation from `outcome.renderArgs`, passing each key as `--<key>` and the value verbatim (including empty strings — they are intentional `use phase default` markers).
172
165
 
173
- **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.
174
-
175
- **Escaping rule**: inside a double-quoted value, escape any literal `"` as `\"`. Do not collapse `--key ""` into `--key` even when the value is empty.
166
+ Step 3's empty-answer and escaping rules apply verbatim: every flag whose value is the empty string MUST still be passed explicitly as `--<key> ""` (e.g. `--workers ""`, `--directive ""`) — `render-bundle` distinguishes "flag absent" from "flag present with empty value", and the wizard's intent is always the latter.
176
167
 
177
168
  The okstra-run skill is the Claude Code execution front door, so it marks the host explicitly with `--runtime claude-code` / `--lead-runtime claude-code`; bare `okstra run` cannot invoke Claude Code `TeamCreate` / `Agent(...)` from a terminal.
178
169