okstra 0.124.0 → 0.125.1

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 (35) hide show
  1. package/docs/architecture/storage-model.md +2 -0
  2. package/docs/architecture.md +6 -2
  3. package/docs/cli.md +2 -2
  4. package/docs/for-ai/skills/okstra-inspect.md +1 -0
  5. package/docs/for-ai/skills/okstra-pr-gen.md +2 -2
  6. package/docs/performance-improvement-plan-v2.md +2 -2
  7. package/docs/project-structure-overview.md +7 -3
  8. package/package.json +1 -1
  9. package/runtime/BUILD.json +2 -2
  10. package/runtime/bin/lib/okstra/usage.sh +1 -1
  11. package/runtime/bin/okstra-antigravity-exec.sh +10 -0
  12. package/runtime/bin/okstra-codex-exec.sh +12 -0
  13. package/runtime/prompts/lead/okstra-lead-contract.md +1 -1
  14. package/runtime/prompts/lead/report-writer.md +16 -13
  15. package/runtime/prompts/profiles/_implementation-verifier.md +26 -0
  16. package/runtime/prompts/profiles/implementation-planning.md +4 -4
  17. package/runtime/prompts/profiles/implementation.md +1 -0
  18. package/runtime/prompts/profiles/requirements-discovery.md +1 -2
  19. package/runtime/python/okstra_ctl/models.py +4 -2
  20. package/runtime/python/okstra_ctl/run.py +8 -2
  21. package/runtime/python/okstra_ctl/stage_fix_carry.py +112 -0
  22. package/runtime/schemas/final-report-v1.0.schema.json +6 -6
  23. package/runtime/skills/okstra-inspect/SKILL.md +23 -737
  24. package/runtime/skills/okstra-inspect/facets/cost.md +84 -0
  25. package/runtime/skills/okstra-inspect/facets/error-zip.md +41 -0
  26. package/runtime/skills/okstra-inspect/facets/errors.md +69 -0
  27. package/runtime/skills/okstra-inspect/facets/history.md +90 -0
  28. package/runtime/skills/okstra-inspect/facets/logs.md +89 -0
  29. package/runtime/skills/okstra-inspect/facets/recap.md +96 -0
  30. package/runtime/skills/okstra-inspect/facets/report.md +61 -0
  31. package/runtime/skills/okstra-inspect/facets/status.md +145 -0
  32. package/runtime/skills/okstra-inspect/facets/time.md +56 -0
  33. package/runtime/skills/okstra-pr-gen/SKILL.md +3 -3
  34. package/runtime/templates/project-docs/task-index.template.md +1 -1
  35. package/runtime/templates/worker-prompt-preamble.md +17 -3
@@ -0,0 +1,145 @@
1
+ # okstra-inspect facet — status
2
+
3
+ Loaded lazily by the dispatch table in `SKILL.md` (core). Shared rules — Step 0 preflight, the standard task-key resolution rule (0/1/N), the no-task fallback, and Output Rules — live in the core file and still apply here.
4
+
5
+ ## status
6
+
7
+ Trigger phrases: "okstra status", "task status", "current phase", "next phase", "what is pending", "resume point", "okstra status set", "okstra mark", "<task-id> done", "<task-id> in-progress", "<task-id> in progress", "<task-id> complete".
8
+
9
+ ### status.1 — Overall project status
10
+
11
+ Read `.okstra/discovery/task-catalog.json`. The catalog is the authoritative source — every field listed below (including `workStatus`, `workStatusUpdatedAt`, `workStatusNote`) is projected directly from each `task-manifest.json` by `scripts/okstra_ctl/render.py :: render_task_catalog_discovery`. Do NOT re-open individual manifests for the overview.
12
+
13
+ | Field | Description |
14
+ |------|------|
15
+ | `taskKey` | `<project-id>:<task-group>:<task-id>` |
16
+ | `taskType` | latest task type |
17
+ | `workCategory` | bugfix / feature / improvement / refactor / ops / unknown. Display `unknown` as-is, but flag with `(unset)` annotation so the reader knows the requirements-discovery classification was skipped or no `--work-category` flag was passed. |
18
+ | `currentStatus` | task-level status |
19
+ | `currentPhase` | lifecycle current phase |
20
+ | `currentPhaseState` | lifecycle phase state |
21
+ | `nextRecommendedPhase` | next recommended phase |
22
+ | `routingStatus` | routing decision status |
23
+ | `awaitingApproval` | whether awaiting approval |
24
+ | `latestRunStatus` | latest run status |
25
+ | `latestReportPath` | latest report path |
26
+ | `latestResumeCommandPath` | latest resume command |
27
+ | `workStatus` | user-managed work status (todo / in-progress / blocked / done; default in-progress) |
28
+ | `updatedAt` | last update time |
29
+
30
+ Sort by `updatedAt` desc, then `taskKey`.
31
+
32
+ The overview table is intentionally narrow so it renders cleanly in a terminal. Only six columns are shown; for any task that needs a closer look (phase state, routing, approval gate, last run status, resume path, etc.) tell the user to run `/okstra-inspect status <task-key>` for the detail view in `status.2`.
33
+
34
+ If `awaitingApproval` is true OR `routingStatus == "pending"`, append a `*` to the `Next` cell and explain the marker once below the table.
35
+
36
+ ```markdown
37
+ ## okstra Status — <project-id>
38
+
39
+ | # | Task Key | Category | Phase | workStatus | Next |
40
+ |---|----------|----------|-------|------------|------|
41
+ | 1 | proj:group:id | bugfix | error-analysis | in-progress | implementation-planning |
42
+ | 2 | proj:group:id2 | feature | requirements-discovery | done | pending-routing-decision* |
43
+
44
+ `*` = awaiting user approval or pending routing decision. Run `/okstra-inspect status <task-key>` for details.
45
+ ```
46
+
47
+ ### status.2 — Specific task status
48
+
49
+ Given a specific `task-key` or `task-group + task-id`:
50
+
51
+ 1. If possible, quickly look it up in `task-catalog.json`.
52
+ 2. If necessary, read `.okstra/tasks/<task-group>/<task-id>/task-manifest.json` directly.
53
+ 3. If you need the latest run information, read `history/timeline.json` along with the latest run manifest.
54
+
55
+ Required fields: `taskKey`, `taskType`, `workCategory`, `currentStatus`, `latestRunStatus`, `workflow.{currentPhase, currentPhaseState, phaseStates, lastCompletedPhase, nextRecommendedPhase, awaitingApproval, routingStatus, lastSafeCheckpoint}`, `workStatus`, `workStatusUpdatedAt`, `workStatusNote`, `latestReportPath`, `latestResumeCommandPath`, `historyTimelinePath`.
56
+
57
+ ```markdown
58
+ ## okstra Task Status — <task-key>
59
+
60
+ - Work category: `<category>`
61
+ - Current phase: `<phase>`
62
+ - Current phase state: `<phase-state>`
63
+ - Last completed phase: `<phase-or-->`
64
+ - Next recommended phase: `<phase>`
65
+ - Awaiting approval: `<yes|no>`
66
+ - Routing status: `<routing-status>`
67
+ - Task status: `<task-status>`
68
+ - Latest run status: `<run-status>`
69
+ - Latest report: `<relative-path-or-->`
70
+ - Resume command: `<relative-path-or-->`
71
+ - workStatus: `<todo|in-progress|blocked|done>` (updated `<workStatusUpdatedAt-or-->`)
72
+ - workStatus note: `<workStatusNote-or-->`
73
+
74
+ ### Phase States
75
+
76
+ - `requirements-discovery`: `<state>`
77
+ - `error-analysis`: `<state>`
78
+ - `implementation-planning`: `<state>`
79
+ - `implementation`: `<state>`
80
+ - `final-verification`: `<state>`
81
+ - `release-handoff`: `<state>`
82
+
83
+ ### Safe Resume Checkpoint
84
+
85
+ - Label: `<checkpoint-label>`
86
+ - Run manifest: `<relative-path-or-->`
87
+ - Team state: `<relative-path-or-->`
88
+ - Report: `<relative-path-or-->`
89
+ - Resume command: `<relative-path-or-->`
90
+ ```
91
+
92
+ ### status.3 — Resume / next-step guidance
93
+
94
+ The status response always includes one of:
95
+
96
+ 1. **Resume current run** — if `latestResumeCommandPath` exists, display that path.
97
+ 2. **Restart current phase** — task can be re-run with the same `task-key` and current `taskType`.
98
+ 3. **Start next phase** — if `workflow.nextRecommendedPhase` is one of `error-analysis`, `implementation-planning`, `implementation`, `final-verification`, `release-handoff`, that phase is proposed. If `nextRecommendedPhase` is `pending-release-handoff`, surface as verdict-gated and propose `release-handoff` only when the cited verdict is `accepted`.
99
+ 4. **Need more information** — if `nextRecommendedPhase` is `pending-routing-decision` or `routingStatus` is `pending`.
100
+ 5. **Task complete (terminal)** — if `nextRecommendedPhase` is `done-or-follow-up`, the task lifecycle has reached its terminal signal. This is **not** a "next phase" — do not propose a new okstra run. Surface the latest report and ask the user whether any follow-up task should be opened separately.
101
+
102
+ ### status.4 — Update workStatus (write)
103
+
104
+ Recognize requests to change a task's `workStatus` and update the corresponding `task-manifest.json`.
105
+
106
+ **Trigger patterns** (recognize both):
107
+
108
+ Natural language: "change DEV-6827 to done", "mark PROD-1623 as blocked", "set DEV-9047 in progress", "Mark DEV-6827 as done".
109
+
110
+ Explicit phrasing (recognized user utterances — normalize each to a `okstra set-work-status` call below):
111
+ - `okstra status set <task-id> <status>`
112
+ - `okstra status set <task-group> <task-id> <status>` (disambiguation)
113
+ - `okstra mark <task-id> <status>`
114
+ - `okstra status set <task-id> <status> --note "<note>"`
115
+
116
+ Accepted `<status>` values: `todo`, `in-progress`, `blocked`, `done`.
117
+
118
+ **Procedure:** run the update through the CLI (one Bash call, literal `okstra` token) — never edit `task-manifest.json` by hand:
119
+
120
+ ```bash
121
+ okstra set-work-status <token> <status> --project-root <projectRoot> --json
122
+ ```
123
+
124
+ - `<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).
125
+ - 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> cannot be found.` An invalid `<status>` makes the CLI exit 2 with the allowed-values list — surface it verbatim; nothing was modified.
126
+
127
+ Confirm in Korean (the block below shows the message shape only — render the actual confirmation text in Korean):
128
+ ```
129
+ ✓ <TASK-ID> workStatus: <previousWorkStatus> → <workStatus>
130
+ ✓ task-manifest.json updated
131
+ ```
132
+ `<previousWorkStatus>` = `(none)` when the JSON's `previousWorkStatus` is empty.
133
+
134
+ **Default value convention:** if `workStatus` is missing or empty, infer the display value from lifecycle state (DO NOT default to a static `in-progress`):
135
+
136
+ | Manifest state | Inferred display |
137
+ |---|---|
138
+ | `currentStatus == "completed"` AND `workflow.nextRecommendedPhase == "done-or-follow-up"` | `done` (inferred) |
139
+ | `currentStatus == "completed"` AND `workflow.currentPhaseState == "completed"` | `phase-done` (inferred) |
140
+ | `currentStatus == "contract-violated"` OR `workflow.currentPhaseState == "blocked"` | `blocked` (inferred) |
141
+ | anything else | `in-progress` (default) |
142
+
143
+ Annotate inferred values with `(inferred)` or `(default)`. Do not back-fill on read; only write when the user explicitly issues an update.
144
+
145
+ **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-gen`) re-read each manifest directly.
@@ -0,0 +1,56 @@
1
+ # okstra-inspect facet — time
2
+
3
+ Loaded lazily by the dispatch table in `SKILL.md` (core). Shared rules — Step 0 preflight, the standard task-key resolution rule (0/1/N), the no-task fallback, and Output Rules — live in the core file and still apply here.
4
+
5
+ ## time
6
+
7
+ Trigger phrases: "work time", "elapsed time", "time summary", "duration", "elapsed", "how long did it take", "time analysis".
8
+
9
+ Aggregate elapsed work time for a task, grouped by **task type** and broken down by **worker** (lead + each worker). The `time-report` CLI reads both data sources (`history/timeline.json` runs + each run's `team-state-*.json` usage blocks) and does **all** aggregation — cross-run sums, CPU-sum vs wall-clock, timestamp parsing, unavailable detection. You only resolve the task-key, call it, and render. **Never recompute durations by hand.**
10
+
11
+ ### time.1 — Resolve the task-key
12
+
13
+ Apply the standard task-key resolution rule from `SKILL.md` (core): full task-key → use directly; bare token → the resolver CLI and the 0/1/N branch. If no okstra history exists, say `No okstra history found. Run /okstra-run first.`
14
+
15
+ ### time.2 — Fetch aggregated data
16
+
17
+ ```bash
18
+ okstra time-report <task-key> --project-root <projectRoot> --json
19
+ ```
20
+
21
+ Returns (all durations are **raw milliseconds**):
22
+ - `byTaskType[]` — `{taskType, runs, leadMs, workersMs, cpuSumMs}`, plus `grandTotal`
23
+ - `perWorker` — `{<taskType>: [{workerId, agents[], runs, totalMs, avgMs}]}`; only workers with a nonzero run appear, and `agents[]` lists agent labels that differ from `workerId`
24
+ - `perRunWallClock[]` — `{runTimestamp, taskType, wallClockMs}` (max `endedAt` − min `startedAt` per run)
25
+ - `phaseTimelines[]` — `{runTimestamp, taskType, phases:[{phase, firstAt, wallMsToNext}]}`
26
+ - `unavailable[]` — `{runTimestamp, taskType, reason}` for runs with no Phase-7 durations (never summed into totals)
27
+
28
+ ### time.3 — Render
29
+
30
+ Convert every `*Ms` to `HH:MM:SS` (zero-pad; never show raw ms). Task types in `byTaskType` are already in chronological (first-appearance) order.
31
+
32
+ - **By task type** — `| Task type | Runs | CPU sum | Lead | Workers |` from `byTaskType`, plus a `grandTotal` row. `CPU sum` (= Lead + Workers) overlaps because workers run inside the lead's window — it is *not* wall-clock. Surface wall-clock only when the user explicitly asks, from `perRunWallClock`.
33
+ - **Per worker** (per task type) — `| Worker | Runs | Total | Avg/run |` from `perWorker`. Render the worker as bare `workerId` when `agents` is empty, else `workerId (agent1, agent2)`.
34
+ - **Phase breakdown** — "by stage"/"per stage"/"which stage took longest" in okstra most often means the **lifecycle stage (task-type)** view, which the *By task type* table above already answers — lead with that table, do not treat the request as unanswerable. Render the intra-run phase timeline only when the user clearly means within-a-run phases ("which phase", "Phase 1~7", "phase timeline"): one table per run from `phaseTimelines`: `| Phase | Start | Wall to next |` using `firstAt`/`wallMsToNext` (`null` → `--`). When `phaseTimelines` is empty, do **not** headline "not measurable" — the By-task-type table is the stage answer; mention the missing intra-run markers only as a trailing footnote.
35
+ - If `unavailable[]` is non-empty, append a trailing note listing each run with its reason. Never fold them into totals.
36
+ - Show the resolved `<task-key>` in the heading.
37
+
38
+ ```markdown
39
+ ## Time summary — <task-key>
40
+
41
+ ### By task type
42
+
43
+ | Task type | Runs | CPU sum | Lead | Workers |
44
+ |------------------------|------|-----------|----------|----------|
45
+ | requirements-discovery | 2 | 00:33:12 | 00:12:08 | 00:21:04 |
46
+ | **Grand total** | 6 | **03:03:06** | 01:05:49 | 01:57:17 |
47
+
48
+ ### Per worker — requirements-discovery
49
+
50
+ | Worker | Runs | Total | Avg/run |
51
+ |----------------------|------|----------|----------|
52
+ | lead | 2 | 00:12:08 | 00:06:04 |
53
+ | claude (sonnet-eval) | 2 | 00:09:12 | 00:04:36 |
54
+
55
+ > Unavailable: 1 run (implementation / 2026-04-30_03-03-48) — Phase 7 not reached
56
+ ```
@@ -33,7 +33,7 @@ Present a 3-option picker (`AskUserQuestion`):
33
33
 
34
34
  1. `Generate PR` — generate a PR body from a branch diff.
35
35
  2. `Register template` — save a new PR body template.
36
- 3. `Enter manually` — always the last option (okstra picker convention).
36
+ 3. `Enter directly` — always the last option (okstra picker convention).
37
37
 
38
38
  ## Mode A — Generate PR
39
39
 
@@ -44,7 +44,7 @@ okstra pr template list --json
44
44
  ```
45
45
 
46
46
  - If `templates` is non-empty, present a picker: 1–2 recommended templates from
47
- the list, plus `Default template` (the bundled default), plus `Enter manually`
47
+ the list, plus `Default template` (the bundled default), plus `Enter directly`
48
48
  last.
49
49
  - If empty, tell the user the bundled default template will be used.
50
50
 
@@ -56,7 +56,7 @@ Carry the chosen template name as `<template>` (`default` for the bundled one).
56
56
  okstra pr branches --json
57
57
  ```
58
58
 
59
- Present a 3-option base picker from `recommended` (top entries) plus `Enter manually`
59
+ Present a 3-option base picker from `recommended` (top entries) plus `Enter directly`
60
60
  last. Carry the choice as `<base>`.
61
61
 
62
62
  ### A3. Build the generation bundle and fill the template
@@ -69,4 +69,4 @@ taskType: "{{FM_TASK_TYPE}}"
69
69
 
70
70
  ## Notes
71
71
 
72
- - 문서는 사람이 빠르게 훑어보기 위한 요약입니다. 정본·상세 metadata `task-manifest.json` 을 참조하세요.
72
+ - This document is a summary for humans to skim quickly. For the canonical, detailed metadata, refer to `task-manifest.json`.
@@ -43,9 +43,17 @@ Different recipients need different files. Do NOT include `final-report-template
43
43
 
44
44
  ## Error reporting (all workers)
45
45
 
46
- If any tool call you make (Bash, Read, Edit, MCP, etc.) returns a non-zero exit code, raises an exception, or otherwise fails its intended effect, append a single entry to your worker errors sidecar at the absolute path the lead provided as `**Errors sidecar path:** <abs-path>`.
46
+ Record a tool call only when its failure **blocked the step you intended** a test you needed to run did not start, a file you needed to read was missing, a config resolved against the wrong tree, an edit was rejected. When that happens, append a single entry to your worker errors sidecar at the absolute path the lead provided as `**Errors sidecar path:** <abs-path>`.
47
47
 
48
- If the sidecar file does not exist, create it with `{"schemaVersion": 1, "errors": []}` then append.
48
+ A non-zero exit code is NOT by itself a failure to record. Many tools use non-zero to report a normal, expected result. Do **NOT** record an entry when:
49
+
50
+ - a search/probe tool (`rg`, `grep`, `find`, `ls`, `test`, `git check-ignore`) exits non-zero solely because it found **no matches**, and you proceed unaffected;
51
+ - you probe an **optional / expected-absent** path (`graphify-out/`, `.project-docs/`, `.scratch/`, an optional lint config, a review pack) and it is absent — detecting absence was the point of the probe;
52
+ - output was truncated but you re-ran and read the content end-to-end.
53
+
54
+ The test: if the non-zero exit changed nothing about what you could do next, it is a normal result, not a `tool-failure`. When in doubt about whether a failure blocked you, record it — under-recording a real blocker is worse than one noisy entry. These benign non-zero exits are the single largest source of error-log noise; keeping them out is what makes the log a signal.
55
+
56
+ If the sidecar file does not exist and you have a real entry to record, create it with `{"schemaVersion": 1, "errors": []}` then append.
49
57
 
50
58
  ### Entry schema
51
59
 
@@ -109,7 +117,13 @@ For the **improvement-discovery phase** specifically, the dispatched prompt MUST
109
117
 
110
118
  - `**Phase 1.5 Grilling Log:** <absolute-path>` — the lead's Phase 1.5 reflect-back log (`<RUN_DIR>/state/phase-1.5-grilling.md`, written before dispatch). Its `Resolved scope` / `Resolved lenses` blocks are the authoritative scope and lens definition for this run. Read the file at this absolute path; do NOT re-derive it from `<RUN_DIR>`, and do NOT re-interpret the brief's raw `scan-scope` / `priority-lenses`. The presence of this anchor is itself the signal that this is an improvement-discovery run — no separate task-type detection is required.
111
119
 
112
- When a worker reads any project-relative path from the prompt, it MUST resolve it against `Project Root` (e.g. `<Project Root>/<Result Path>`) — never use bare relative paths that depend on cwd.
120
+ ### Path anchoring (BLOCKING the single largest source of worker tool-failures)
121
+
122
+ Every `.okstra/...` path is anchored at `**Project Root:**`, **never** at your cwd. When your run has a worktree (`**Worktree:**` is present), your cwd is that worktree — and the stage/task worktree does **not** contain the project's `.okstra/` directory. So a bare `Read`/`cat .okstra/tasks/...` from cwd resolves inside the worktree and fails "no such file". This is the same trap whether the path came from the prompt, a manifest field, a prior report's citation, or your own reasoning.
123
+
124
+ - Resolve any project-relative path (`.okstra/...`, `<Result Path>`, `<Prompt History Path>`, a prior-report `path:line` citation) against `**Project Root:**`: `<Project Root>/.okstra/...`. Never use the bare relative form.
125
+ - Mutating build/test commands still run from the worktree cwd (`cd <Worktree> && ...`) — but reads of okstra artifacts (`.okstra/**`) always go through `<Project Root>`, even while cwd is the worktree.
126
+ - If a `.okstra/...` read fails "no such file / does not exist in the worktree", do not retry the same relative path — re-anchor it to `<Project Root>` and read the absolute path.
113
127
 
114
128
  ---
115
129