okstra 0.111.0 → 0.112.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 (55) 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/prompts/coding-preflight/overview.md +3 -1
  19. package/runtime/prompts/launch.template.md +1 -5
  20. package/runtime/prompts/lead/context-loader.md +2 -4
  21. package/runtime/prompts/lead/convergence.md +11 -240
  22. package/runtime/prompts/lead/okstra-lead-contract.md +70 -34
  23. package/runtime/prompts/lead/plan-body-verification.md +240 -0
  24. package/runtime/prompts/lead/report-writer.md +7 -7
  25. package/runtime/prompts/lead/team-contract.md +15 -17
  26. package/runtime/prompts/profiles/_common-contract.md +1 -37
  27. package/runtime/prompts/profiles/_implementation-executor.md +2 -2
  28. package/runtime/prompts/profiles/_implementation-verifier.md +1 -1
  29. package/runtime/prompts/profiles/final-verification.md +1 -1
  30. package/runtime/prompts/profiles/implementation-planning.md +2 -2
  31. package/runtime/prompts/profiles/implementation.md +1 -1
  32. package/runtime/python/okstra_ctl/path_hints.py +1 -0
  33. package/runtime/python/okstra_ctl/paths.py +3 -0
  34. package/runtime/python/okstra_ctl/render.py +8 -0
  35. package/runtime/python/okstra_ctl/set_work_status.py +147 -0
  36. package/runtime/python/okstra_ctl/team_reconcile.py +1 -1
  37. package/runtime/skills/okstra-brief/SKILL.md +32 -176
  38. package/runtime/skills/okstra-brief/references/reporter-confirmations.md +71 -0
  39. package/runtime/skills/okstra-brief/references/tracker-recursion.md +90 -0
  40. package/runtime/skills/okstra-container-build/SKILL.md +7 -20
  41. package/runtime/skills/okstra-graphify/SKILL.md +8 -8
  42. package/runtime/skills/okstra-inspect/SKILL.md +27 -43
  43. package/runtime/skills/okstra-rollup/SKILL.md +6 -6
  44. package/runtime/skills/okstra-run/SKILL.md +7 -16
  45. package/runtime/skills/okstra-schedule/SKILL.md +64 -419
  46. package/runtime/skills/okstra-setup/SKILL.md +25 -223
  47. package/runtime/skills/okstra-setup/references/project-config.md +188 -0
  48. package/runtime/templates/reports/schedule.template.md +2 -2
  49. package/runtime/templates/worker-prompt-preamble.md +1 -1
  50. package/runtime/validators/validate-run.py +7 -7
  51. package/src/cli-registry.mjs +14 -0
  52. package/src/commands/inspect/set-work-status.mjs +31 -0
  53. package/src/commands/lifecycle/check-project.mjs +68 -56
  54. package/src/commands/lifecycle/install.mjs +1 -0
  55. package/src/commands/lifecycle/preflight.mjs +82 -0
@@ -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