okstra 0.124.0 → 0.125.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/docs/architecture/storage-model.md +2 -0
- package/docs/architecture.md +5 -1
- package/docs/cli.md +1 -1
- package/docs/for-ai/skills/okstra-inspect.md +1 -0
- package/docs/for-ai/skills/okstra-pr-gen.md +2 -2
- package/docs/performance-improvement-plan-v2.md +2 -2
- package/package.json +1 -1
- package/runtime/BUILD.json +2 -2
- package/runtime/bin/lib/okstra/usage.sh +1 -1
- package/runtime/prompts/lead/okstra-lead-contract.md +1 -1
- package/runtime/prompts/lead/report-writer.md +16 -13
- package/runtime/prompts/profiles/_implementation-verifier.md +26 -0
- package/runtime/prompts/profiles/implementation-planning.md +4 -4
- package/runtime/prompts/profiles/implementation.md +1 -0
- package/runtime/prompts/profiles/requirements-discovery.md +1 -2
- package/runtime/python/okstra_ctl/models.py +4 -2
- package/runtime/python/okstra_ctl/run.py +8 -2
- package/runtime/python/okstra_ctl/stage_fix_carry.py +112 -0
- package/runtime/schemas/final-report-v1.0.schema.json +6 -6
- package/runtime/skills/okstra-inspect/SKILL.md +23 -737
- package/runtime/skills/okstra-inspect/facets/cost.md +84 -0
- package/runtime/skills/okstra-inspect/facets/error-zip.md +41 -0
- package/runtime/skills/okstra-inspect/facets/errors.md +69 -0
- package/runtime/skills/okstra-inspect/facets/history.md +90 -0
- package/runtime/skills/okstra-inspect/facets/logs.md +89 -0
- package/runtime/skills/okstra-inspect/facets/recap.md +96 -0
- package/runtime/skills/okstra-inspect/facets/report.md +61 -0
- package/runtime/skills/okstra-inspect/facets/status.md +145 -0
- package/runtime/skills/okstra-inspect/facets/time.md +56 -0
- package/runtime/skills/okstra-pr-gen/SKILL.md +3 -3
- package/runtime/templates/project-docs/task-index.template.md +1 -1
|
@@ -6,19 +6,19 @@ description: >-
|
|
|
6
6
|
|
|
7
7
|
# OKSTRA Inspect
|
|
8
8
|
|
|
9
|
-
Single read-side entry point for okstra runtime inspection plus the one status mutation that belongs here (`workStatus`) and read-derived artifact rendering (`errors` report).
|
|
9
|
+
Single read-side entry point for okstra runtime inspection plus the one status mutation that belongs here (`workStatus`) and read-derived artifact rendering (`errors` report). Each sub-command's full procedure lives in a lazily loaded facet file — after dispatch, Read exactly the one facet you need.
|
|
10
10
|
|
|
11
|
-
| Sub-command | What it does |
|
|
12
|
-
|
|
13
|
-
| `status` | Task / phase status, blockers, approval state. Also writes `workStatus` on user request. |
|
|
14
|
-
| `history` | List past okstra runs; assemble re-run or resume command. |
|
|
15
|
-
| `report` | Resolve final-report path for a task-key. Optionally read it. |
|
|
16
|
-
| `time` | Per-task-type and per-worker duration breakdown for a task. |
|
|
17
|
-
| `logs` | Inventory codex/antigravity wrapper `.log` sidecars; emit cleanup commands. |
|
|
18
|
-
| `cost` | Estimate file/read context cost for a task bundle. |
|
|
19
|
-
| `errors` | Aggregate okstra-run error logs for a task into a timestamped markdown report; print a summary. |
|
|
20
|
-
| `error-zip` | Collect cross-project okstra error logs into an anonymized zip (report + raw) and summarize clusters. |
|
|
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`, and writes agent-authored notes to `notes/` for feeding into later runs. |
|
|
11
|
+
| Sub-command | Facet file | What it does |
|
|
12
|
+
|---|---|---|
|
|
13
|
+
| `status` | `facets/status.md` | Task / phase status, blockers, approval state. Also writes `workStatus` on user request. |
|
|
14
|
+
| `history` | `facets/history.md` | List past okstra runs; assemble re-run or resume command. |
|
|
15
|
+
| `report` | `facets/report.md` | Resolve final-report path for a task-key. Optionally read it. |
|
|
16
|
+
| `time` | `facets/time.md` | Per-task-type and per-worker duration breakdown for a task. |
|
|
17
|
+
| `logs` | `facets/logs.md` | Inventory codex/antigravity wrapper `.log` sidecars; emit cleanup commands. |
|
|
18
|
+
| `cost` | `facets/cost.md` | Estimate file/read context cost for a task bundle. |
|
|
19
|
+
| `errors` | `facets/errors.md` | Aggregate okstra-run error logs for a task into a timestamped markdown report; print a summary. |
|
|
20
|
+
| `error-zip` | `facets/error-zip.md` | Collect cross-project okstra error logs into an anonymized zip (report + raw) and summarize clusters. |
|
|
21
|
+
| `recap` | `facets/recap.md` | 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`, and writes agent-authored notes to `notes/` for feeding into later runs. |
|
|
22
22
|
|
|
23
23
|
## Step 0: Preflight (shared)
|
|
24
24
|
|
|
@@ -48,748 +48,34 @@ Every subsequent `okstra <subcmd>` call self-bootstraps its Python path, so this
|
|
|
48
48
|
|
|
49
49
|
## Step 1: Dispatch by intent
|
|
50
50
|
|
|
51
|
-
Classify the user's request into one sub-command using the trigger table above. If ambiguous (e.g. "show me okstra"), ask which facet — do not silently default. After routing, the chosen
|
|
52
|
-
|
|
53
|
-
When you ask which facet, the option list is **authoritative**: enumerate every sub-command in the `Sub-command | What it does` table above as a numbered text list, in table order, each with its one-line description, and let the user pick by number or name. Never present a hand-picked subset — the AskUserQuestion 4-option cap is not a reason to drop facets; render the full menu as text in the question body so no facet (e.g. a newly added one) is ever hidden. The table is the single source of truth for this menu; adding a row there is all it takes for the facet to appear here.
|
|
54
|
-
|
|
55
|
-
When the user chains multiple facets in one message (e.g. "status, and then time for DEV-9047"), execute them sequentially — Step 0 runs once, each sub-command section runs once.
|
|
56
|
-
|
|
57
|
-
---
|
|
58
|
-
|
|
59
|
-
## status
|
|
60
|
-
|
|
61
|
-
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".
|
|
62
|
-
|
|
63
|
-
### status.1 — Overall project status
|
|
64
|
-
|
|
65
|
-
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.
|
|
66
|
-
|
|
67
|
-
| Field | Description |
|
|
68
|
-
|------|------|
|
|
69
|
-
| `taskKey` | `<project-id>:<task-group>:<task-id>` |
|
|
70
|
-
| `taskType` | latest task type |
|
|
71
|
-
| `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. |
|
|
72
|
-
| `currentStatus` | task-level status |
|
|
73
|
-
| `currentPhase` | lifecycle current phase |
|
|
74
|
-
| `currentPhaseState` | lifecycle phase state |
|
|
75
|
-
| `nextRecommendedPhase` | next recommended phase |
|
|
76
|
-
| `routingStatus` | routing decision status |
|
|
77
|
-
| `awaitingApproval` | whether awaiting approval |
|
|
78
|
-
| `latestRunStatus` | latest run status |
|
|
79
|
-
| `latestReportPath` | latest report path |
|
|
80
|
-
| `latestResumeCommandPath` | latest resume command |
|
|
81
|
-
| `workStatus` | user-managed work status (todo / in-progress / blocked / done; default in-progress) |
|
|
82
|
-
| `updatedAt` | last update time |
|
|
83
|
-
|
|
84
|
-
Sort by `updatedAt` desc, then `taskKey`.
|
|
85
|
-
|
|
86
|
-
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`.
|
|
87
|
-
|
|
88
|
-
If `awaitingApproval` is true OR `routingStatus == "pending"`, append a `*` to the `Next` cell and explain the marker once below the table.
|
|
89
|
-
|
|
90
|
-
```markdown
|
|
91
|
-
## okstra Status — <project-id>
|
|
92
|
-
|
|
93
|
-
| # | Task Key | Category | Phase | workStatus | Next |
|
|
94
|
-
|---|----------|----------|-------|------------|------|
|
|
95
|
-
| 1 | proj:group:id | bugfix | error-analysis | in-progress | implementation-planning |
|
|
96
|
-
| 2 | proj:group:id2 | feature | requirements-discovery | done | pending-routing-decision* |
|
|
97
|
-
|
|
98
|
-
`*` = awaiting user approval or pending routing decision. Run `/okstra-inspect status <task-key>` for details.
|
|
99
|
-
```
|
|
100
|
-
|
|
101
|
-
### status.2 — Specific task status
|
|
102
|
-
|
|
103
|
-
Given a specific `task-key` or `task-group + task-id`:
|
|
104
|
-
|
|
105
|
-
1. If possible, quickly look it up in `task-catalog.json`.
|
|
106
|
-
2. If necessary, read `.okstra/tasks/<task-group>/<task-id>/task-manifest.json` directly.
|
|
107
|
-
3. If you need the latest run information, read `history/timeline.json` along with the latest run manifest.
|
|
108
|
-
|
|
109
|
-
Required fields: `taskKey`, `taskType`, `workCategory`, `currentStatus`, `latestRunStatus`, `workflow.{currentPhase, currentPhaseState, phaseStates, lastCompletedPhase, nextRecommendedPhase, awaitingApproval, routingStatus, lastSafeCheckpoint}`, `workStatus`, `workStatusUpdatedAt`, `workStatusNote`, `latestReportPath`, `latestResumeCommandPath`, `historyTimelinePath`.
|
|
110
|
-
|
|
111
|
-
```markdown
|
|
112
|
-
## okstra Task Status — <task-key>
|
|
51
|
+
Classify the user's request into one sub-command using the trigger table above. If ambiguous (e.g. "show me okstra"), ask which facet — do not silently default. After routing, **Read the chosen row's facet file** (path relative to this skill's base directory) and follow it for the rest of the response. Load exactly one facet per sub-command — never preload the others.
|
|
113
52
|
|
|
114
|
-
-
|
|
115
|
-
- Current phase: `<phase>`
|
|
116
|
-
- Current phase state: `<phase-state>`
|
|
117
|
-
- Last completed phase: `<phase-or-->`
|
|
118
|
-
- Next recommended phase: `<phase>`
|
|
119
|
-
- Awaiting approval: `<yes|no>`
|
|
120
|
-
- Routing status: `<routing-status>`
|
|
121
|
-
- Task status: `<task-status>`
|
|
122
|
-
- Latest run status: `<run-status>`
|
|
123
|
-
- Latest report: `<relative-path-or-->`
|
|
124
|
-
- Resume command: `<relative-path-or-->`
|
|
125
|
-
- workStatus: `<todo|in-progress|blocked|done>` (updated `<workStatusUpdatedAt-or-->`)
|
|
126
|
-
- workStatus note: `<workStatusNote-or-->`
|
|
53
|
+
When you ask which facet, the option list is **authoritative**: enumerate every sub-command in the dispatch table above as a numbered text list, in table order, each with its one-line description, and let the user pick by number or name. Never present a hand-picked subset — the AskUserQuestion 4-option cap is not a reason to drop facets; render the full menu as text in the question body so no facet (e.g. a newly added one) is ever hidden. The table is the single source of truth for this menu; adding a row there (plus its facet file) is all it takes for the facet to appear here.
|
|
127
54
|
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
- `requirements-discovery`: `<state>`
|
|
131
|
-
- `error-analysis`: `<state>`
|
|
132
|
-
- `implementation-planning`: `<state>`
|
|
133
|
-
- `implementation`: `<state>`
|
|
134
|
-
- `final-verification`: `<state>`
|
|
135
|
-
- `release-handoff`: `<state>`
|
|
136
|
-
|
|
137
|
-
### Safe Resume Checkpoint
|
|
138
|
-
|
|
139
|
-
- Label: `<checkpoint-label>`
|
|
140
|
-
- Run manifest: `<relative-path-or-->`
|
|
141
|
-
- Team state: `<relative-path-or-->`
|
|
142
|
-
- Report: `<relative-path-or-->`
|
|
143
|
-
- Resume command: `<relative-path-or-->`
|
|
144
|
-
```
|
|
55
|
+
When the user chains multiple facets in one message (e.g. "status, and then time for DEV-9047"), execute them sequentially — Step 0 runs once, then load and run each facet in turn.
|
|
145
56
|
|
|
146
|
-
|
|
57
|
+
## Shared rules (referenced by facets)
|
|
147
58
|
|
|
148
|
-
|
|
59
|
+
### Standard task-key resolution (0/1/N)
|
|
149
60
|
|
|
150
|
-
|
|
151
|
-
2. **Restart current phase** — task can be re-run with the same `task-key` and current `taskType`.
|
|
152
|
-
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`.
|
|
153
|
-
4. **Need more information** — if `nextRecommendedPhase` is `pending-routing-decision` or `routingStatus` is `pending`.
|
|
154
|
-
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.
|
|
155
|
-
|
|
156
|
-
### status.4 — Update workStatus (write)
|
|
157
|
-
|
|
158
|
-
Recognize requests to change a task's `workStatus` and update the corresponding `task-manifest.json`.
|
|
159
|
-
|
|
160
|
-
**Trigger patterns** (recognize both):
|
|
161
|
-
|
|
162
|
-
Natural language: "change DEV-6827 to done", "mark PROD-1623 as blocked", "set DEV-9047 in progress", "Mark DEV-6827 as done".
|
|
163
|
-
|
|
164
|
-
Explicit phrasing (recognized user utterances — normalize each to a `okstra set-work-status` call below):
|
|
165
|
-
- `okstra status set <task-id> <status>`
|
|
166
|
-
- `okstra status set <task-group> <task-id> <status>` (disambiguation)
|
|
167
|
-
- `okstra mark <task-id> <status>`
|
|
168
|
-
- `okstra status set <task-id> <status> --note "<note>"`
|
|
169
|
-
|
|
170
|
-
Accepted `<status>` values: `todo`, `in-progress`, `blocked`, `done`.
|
|
171
|
-
|
|
172
|
-
**Procedure:** run the update through the CLI (one Bash call, literal `okstra` token) — never edit `task-manifest.json` by hand:
|
|
173
|
-
|
|
174
|
-
```bash
|
|
175
|
-
okstra set-work-status <token> <status> --project-root <projectRoot> --json
|
|
176
|
-
```
|
|
177
|
-
|
|
178
|
-
- `<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).
|
|
179
|
-
- 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.
|
|
180
|
-
|
|
181
|
-
Confirm in Korean:
|
|
182
|
-
```
|
|
183
|
-
✓ <TASK-ID> workStatus: <previousWorkStatus> → <workStatus>
|
|
184
|
-
✓ task-manifest.json updated
|
|
185
|
-
```
|
|
186
|
-
`<previousWorkStatus>` = `(none)` when the JSON's `previousWorkStatus` is empty.
|
|
187
|
-
|
|
188
|
-
**Default value convention:** if `workStatus` is missing or empty, infer the display value from lifecycle state (DO NOT default to a static `in-progress`):
|
|
189
|
-
|
|
190
|
-
| Manifest state | Inferred display |
|
|
191
|
-
|---|---|
|
|
192
|
-
| `currentStatus == "completed"` AND `workflow.nextRecommendedPhase == "done-or-follow-up"` | `done` (inferred) |
|
|
193
|
-
| `currentStatus == "completed"` AND `workflow.currentPhaseState == "completed"` | `phase-done` (inferred) |
|
|
194
|
-
| `currentStatus == "contract-violated"` OR `workflow.currentPhaseState == "blocked"` | `blocked` (inferred) |
|
|
195
|
-
| anything else | `in-progress` (default) |
|
|
196
|
-
|
|
197
|
-
Annotate inferred values with `(inferred)` or `(default)`. Do not back-fill on read; only write when the user explicitly issues an update.
|
|
198
|
-
|
|
199
|
-
**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.
|
|
200
|
-
|
|
201
|
-
---
|
|
202
|
-
|
|
203
|
-
## history
|
|
204
|
-
|
|
205
|
-
Trigger phrases: "okstra history", "past runs", "run history", "re-run", "list tasks", "run again", "resume", "continue".
|
|
206
|
-
|
|
207
|
-
**Re-run vs Resume — decide upfront.** Re-run = start a fresh run (new run-seq, new manifest, new report) reusing an old run's parameters → `history.3`. Resume = continue an interrupted Claude session for an existing run, no new run-seq → `history.4`. If the user is ambiguous, ask — defaulting to the wrong one either wastes a fresh run-seq or silently abandons a recoverable session.
|
|
208
|
-
|
|
209
|
-
### history.1 — Read the task catalog
|
|
210
|
-
|
|
211
|
-
1. Read `.okstra/discovery/task-catalog.json`.
|
|
212
|
-
2. Apply filters from user input (all optional, AND-combined):
|
|
213
|
-
- `--task-type <type>` → keep entries whose `taskType` matches.
|
|
214
|
-
- `--latest-run-status <status>` → keep entries whose `latestRunStatus` matches (`completed`, `contract-violated`, `error`).
|
|
215
|
-
- `--task-group <group>` → keep entries whose `taskGroup` matches.
|
|
216
|
-
3. Sort by `updatedAt` desc.
|
|
217
|
-
4. Page: default `--limit 20`. If truncated, add `... <N> more (pass --limit <N> to see all)`.
|
|
218
|
-
5. Extract: `taskKey`, `taskType`, `currentStatus`, `latestRunStatus`, `latestRunManifestPath`, `updatedAt`, `latestReportPath`, `latestResumeCommandPath`, `historyTimelinePath`.
|
|
219
|
-
|
|
220
|
-
```markdown
|
|
221
|
-
## okstra Task History — <project-id>
|
|
222
|
-
|
|
223
|
-
| # | Task Key | Type | currentStatus | latestRunStatus | Last Run | Report |
|
|
224
|
-
|---|----------|------|---------------|------------------|----------|--------|
|
|
225
|
-
| 1 | proj:group:id | error-analysis | completed | completed | 2026-04-05 22:59 | .project-docs/.../final-report-*.md |
|
|
226
|
-
| 2 | proj:group:id2 | final-verification | todo | error | 2026-04-04 15:30 | -- |
|
|
227
|
-
```
|
|
228
|
-
|
|
229
|
-
**Catalog absent — fallback.** Do NOT bail out. Manifests on disk are the source of truth.
|
|
230
|
-
|
|
231
|
-
1. Glob `<projectRoot>/.okstra/tasks/*/*/task-manifest.json`.
|
|
232
|
-
2. For each manifest, read the same fields as above.
|
|
233
|
-
3. Apply the same filters/sort/limit and print the same table, prefixed with: `note: task-catalog.json missing; reconstructed from task manifests on disk.`
|
|
234
|
-
4. Only if the glob yields zero manifests: `There is no okstra execution history yet.`
|
|
235
|
-
|
|
236
|
-
### history.2 — Run history by task
|
|
237
|
-
|
|
238
|
-
When a user selects a specific task:
|
|
239
|
-
|
|
240
|
-
1. Retrieve `historyTimelinePath`, read `runs` array.
|
|
241
|
-
2. Extract: `runTimestamp`, `runDateTimeSegment`, `taskType`, `status`, `runManifestPath`, `reportPath`, `resumeCommandPath`, `relatedTasks`.
|
|
242
|
-
|
|
243
|
-
```markdown
|
|
244
|
-
## Runs for <task-key>
|
|
245
|
-
|
|
246
|
-
| # | Timestamp | Type | Status | Report |
|
|
247
|
-
|---|-----------|------|--------|--------|
|
|
248
|
-
| 1 | 2026-04-05 22:59 | error-analysis | completed | .../final-report-*.md |
|
|
249
|
-
| 2 | 2026-04-04 15:30 | error-analysis | error | -- |
|
|
250
|
-
```
|
|
251
|
-
|
|
252
|
-
### history.3 — Re-run (NEW run from old parameters)
|
|
253
|
-
|
|
254
|
-
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.
|
|
255
|
-
|
|
256
|
-
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.
|
|
257
|
-
2. Read the manifest and extract required arguments:
|
|
258
|
-
- `projectId` → `--project-id`
|
|
259
|
-
- `taskGroup` → `--task-group`
|
|
260
|
-
- `taskId` → `--task-id`
|
|
261
|
-
- `taskType` → `--task-type`
|
|
262
|
-
- `taskBriefPath` → `--task-brief`
|
|
263
|
-
3. Optional arguments (include only when present in source):
|
|
264
|
-
- `recommendedWorkers` → `--workers` (comma-separated)
|
|
265
|
-
- `relatedTasks` → `--related-tasks`
|
|
266
|
-
- model overrides → `--claude-model`, `--codex-model`, `--antigravity-model`
|
|
267
|
-
- for `taskType: implementation`: `teamContract.executor.provider` → `--executor <claude|codex|antigravity>` when different from `claude`.
|
|
268
|
-
4. **`taskType: implementation` only — resolve `--base-ref`:** base ref is NOT in the run-manifest; it lives in the worktree registry at `~/.okstra/worktrees/registry.json`. If a worktree is already registered, existing branch & base are reused — omit `--base-ref` unless the user explicitly wants a different starting point. If no worktree is registered (cleaned up), `--base-ref` is mandatory — ask the user before running.
|
|
269
|
-
5. Display the assembled command:
|
|
270
|
-
```bash
|
|
271
|
-
~/.okstra/bin/okstra.sh \
|
|
272
|
-
--project-id <project-id> \
|
|
273
|
-
--task-group <task-group> \
|
|
274
|
-
--task-id <task-id> \
|
|
275
|
-
--task-type <task-type> \
|
|
276
|
-
--task-brief <brief-path> \
|
|
277
|
-
--workers <worker-list>
|
|
278
|
-
```
|
|
279
|
-
6. Once the user confirms, execute it.
|
|
280
|
-
|
|
281
|
-
### history.4 — Resume (continue an interrupted run)
|
|
282
|
-
|
|
283
|
-
Continues an existing Claude session for an unfinished run. Does NOT create a new run-seq — for a fresh dispatch use `history.3`.
|
|
284
|
-
|
|
285
|
-
1. Read `latestResumeCommandPath` from `history.1` (or `resumeCommandPath` from a `history.2` timeline entry).
|
|
286
|
-
2. Verify the file exists on disk.
|
|
287
|
-
3. If it exists: `bash <resume-command-path>`.
|
|
288
|
-
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.`
|
|
289
|
-
|
|
290
|
-
---
|
|
291
|
-
|
|
292
|
-
## report
|
|
293
|
-
|
|
294
|
-
Trigger phrases: "find report", "show report for", "read the okstra report", "continue from report".
|
|
295
|
-
|
|
296
|
-
### report.1 — Resolve report path
|
|
297
|
-
|
|
298
|
-
task-key format: `<project-id>:<task-group>:<task-id>`.
|
|
299
|
-
|
|
300
|
-
**Normalization:** task-key matching is lowercase. Disk segments are slugified (lowercase + non-alphanumeric runs → `-`) per `scripts/okstra_ctl/ids.py:88` (`slugify_task_segment`, the SSOT; `interactive.sh` consumes it via import). Catalog lookup is case-insensitive; file path assembly uses slugified segments.
|
|
301
|
-
|
|
302
|
-
Lookup methods (in priority order):
|
|
303
|
-
|
|
304
|
-
A. **`task-catalog.json` (fast):** read `.okstra/discovery/task-catalog.json`, match `taskKey` lowercase. `latestReportPath` is task-type-agnostic "most recent report".
|
|
305
|
-
|
|
306
|
-
B. **`task-manifest.json` (direct):** if catalog missing, slugify task-group / task-id, read `.okstra/tasks/<group-segment>/<task-id-segment>/task-manifest.json`, use `latestReportPath` (task-type-agnostic).
|
|
307
|
-
|
|
308
|
-
C. **`timeline.json` (specific run):** for a specific date or run, read `.okstra/tasks/<group-segment>/<id-segment>/history/timeline.json`, filter `runs[]` by `runTimestamp` / `status` / `taskType`, use `runs[].reportPath`.
|
|
309
|
-
|
|
310
|
-
D. **Specific task-type (fallback):** `latestReportPath` is task-type-agnostic. For a specific task-type's latest report, look under `.okstra/tasks/<group-segment>/<id-segment>/runs/<task-type-segment>/reports/`, filename pattern `final-report-<task-type-segment>-<NNN>.md` per `scripts/okstra_ctl/sequence.py:30`. Highest seq is latest. Stage-isolated runs (`implementation`, single-stage `final-verification`) keep their reports one level deeper at `runs/<task-type-segment>/stage-<N>/reports/` — scan those subdirectories too; seq is independent per stage. Cross-verify with `timeline.json`'s `runs[].taskType` filter.
|
|
311
|
-
|
|
312
|
-
### report.2 — Confirm existence
|
|
313
|
-
|
|
314
|
-
1. Verify `latestReportPath` is non-empty AND the file exists on disk. Either signal indicates report presence (tolerant).
|
|
315
|
-
2. If present, display the path and ask the user whether to read it.
|
|
316
|
-
3. If absent, check `task-manifest.json` signals:
|
|
317
|
-
- `latestReportPath` empty/missing AND `currentStatus != completed` AND `workStatus != done` AND `workflow.routingStatus` not completion-like → `This task is not yet complete (currentStatus: <currentStatus>, workStatus: <workStatus>).`
|
|
318
|
-
- Any signal indicates completion but the file is missing → `Report file does not exist: <path>`
|
|
319
|
-
|
|
320
|
-
`workStatus` enum: `todo | in-progress | blocked | done`. `currentStatus`: `completed` / `contract-violated` etc. `"completed"` string does NOT exist in `workStatus` — do not confuse the two.
|
|
321
|
-
|
|
322
|
-
### report.3 — Read + next-step guidance
|
|
323
|
-
|
|
324
|
-
Match the depth of read to the request — final reports routinely run 300+ lines / 50K+ tokens, so ingesting the whole file just to answer "just the gist" is wasteful:
|
|
325
|
-
|
|
326
|
-
- **Summary / verdict intent** ("summary", "just the key points", "conclusion", "did it pass?", "verdict"): do **not** read the whole report first. Read the `final-<task-type-segment>-<NNN>.status` sidecar under `runs/<task-type-segment>/status/` (stage-isolated: `runs/<task-type-segment>/stage-<N>/status/`) for the machine verdict, then read only the report's leading summary block (the first "Overall Verdict" / "Executive" / verdict heading and its body) to quote the gist. Offer to read the full report if the user wants detail.
|
|
327
|
-
- **Full-read intent** ("the whole thing", "read it all", "full body"): ingest the resolved report file.
|
|
328
|
-
|
|
329
|
-
After reading, surface follow-up options:
|
|
330
|
-
|
|
331
|
-
1. **Proceed to implementation:** based on the report's "Recommended Next Steps" section.
|
|
332
|
-
2. **Additional verification:** to launch a new okstra run with the same task-key, assemble the command through the `history` sub-command — it offers the full option set (base-ref, workers, render-only) and renders a host-correct invocation.
|
|
333
|
-
3. **Check related tasks:** if the report references related task-keys, fetch their reports too.
|
|
334
|
-
|
|
335
|
-
### report — Output template
|
|
336
|
-
|
|
337
|
-
```markdown
|
|
338
|
-
## Report for <task-key>
|
|
339
|
-
|
|
340
|
-
| Field | Value |
|
|
341
|
-
| ------------ | -------------------------------------------------- |
|
|
342
|
-
| Status | `<status>` |
|
|
343
|
-
| Task type | `<task-type>` |
|
|
344
|
-
| Run seq | `<NNN>` |
|
|
345
|
-
| Run date | `<runTimestamp ISO-8601>` |
|
|
346
|
-
| Report (rel) | `<relative-path-from-project-root>` |
|
|
347
|
-
| Report (abs) | `<absolute-path>` |
|
|
348
|
-
```
|
|
349
|
-
|
|
350
|
-
---
|
|
351
|
-
|
|
352
|
-
## time
|
|
353
|
-
|
|
354
|
-
Trigger phrases: "work time", "elapsed time", "time summary", "duration", "elapsed", "how long did it take", "time analysis".
|
|
355
|
-
|
|
356
|
-
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.**
|
|
357
|
-
|
|
358
|
-
### time.1 — Resolve the task-key
|
|
359
|
-
|
|
360
|
-
Same standard as `cost.1`: full task-key → use directly; bare token (task-id or task-group) → `okstra resolve-task-key <token> --project-root <projectRoot> --json` and branch on `matches[]` (0 = not found, 1 = use, N = 3-option picker). If no okstra history exists, say `No okstra history found. Run /okstra-run first.`
|
|
361
|
-
|
|
362
|
-
### time.2 — Fetch aggregated data
|
|
363
|
-
|
|
364
|
-
```bash
|
|
365
|
-
okstra time-report <task-key> --project-root <projectRoot> --json
|
|
366
|
-
```
|
|
367
|
-
|
|
368
|
-
Returns (all durations are **raw milliseconds**):
|
|
369
|
-
- `byTaskType[]` — `{taskType, runs, leadMs, workersMs, cpuSumMs}`, plus `grandTotal`
|
|
370
|
-
- `perWorker` — `{<taskType>: [{workerId, agents[], runs, totalMs, avgMs}]}`; only workers with a nonzero run appear, and `agents[]` lists agent labels that differ from `workerId`
|
|
371
|
-
- `perRunWallClock[]` — `{runTimestamp, taskType, wallClockMs}` (max `endedAt` − min `startedAt` per run)
|
|
372
|
-
- `phaseTimelines[]` — `{runTimestamp, taskType, phases:[{phase, firstAt, wallMsToNext}]}`
|
|
373
|
-
- `unavailable[]` — `{runTimestamp, taskType, reason}` for runs with no Phase-7 durations (never summed into totals)
|
|
374
|
-
|
|
375
|
-
### time.3 — Render
|
|
376
|
-
|
|
377
|
-
Convert every `*Ms` to `HH:MM:SS` (zero-pad; never show raw ms). Task types in `byTaskType` are already in chronological (first-appearance) order.
|
|
378
|
-
|
|
379
|
-
- **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`.
|
|
380
|
-
- **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)`.
|
|
381
|
-
- **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.
|
|
382
|
-
- If `unavailable[]` is non-empty, append a trailing note listing each run with its reason. Never fold them into totals.
|
|
383
|
-
- Show the resolved `<task-key>` in the heading.
|
|
384
|
-
|
|
385
|
-
```markdown
|
|
386
|
-
## Time summary — <task-key>
|
|
387
|
-
|
|
388
|
-
### By task type
|
|
389
|
-
|
|
390
|
-
| Task type | Runs | CPU sum | Lead | Workers |
|
|
391
|
-
|------------------------|------|-----------|----------|----------|
|
|
392
|
-
| requirements-discovery | 2 | 00:33:12 | 00:12:08 | 00:21:04 |
|
|
393
|
-
| **Grand total** | 6 | **03:03:06** | 01:05:49 | 01:57:17 |
|
|
394
|
-
|
|
395
|
-
### Per worker — requirements-discovery
|
|
396
|
-
|
|
397
|
-
| Worker | Runs | Total | Avg/run |
|
|
398
|
-
|----------------------|------|----------|----------|
|
|
399
|
-
| lead | 2 | 00:12:08 | 00:06:04 |
|
|
400
|
-
| claude (sonnet-eval) | 2 | 00:09:12 | 00:04:36 |
|
|
401
|
-
|
|
402
|
-
> Unavailable: 1 run (implementation / 2026-04-30_03-03-48) — Phase 7 not reached
|
|
403
|
-
```
|
|
404
|
-
|
|
405
|
-
---
|
|
406
|
-
|
|
407
|
-
## cost
|
|
408
|
-
|
|
409
|
-
Trigger phrases: "okstra context-cost", "context cost", "context-cost", "context cost (Korean)", "read cost", "artifact cost", "task bundle cost", "agent read cost".
|
|
410
|
-
|
|
411
|
-
Read-only estimate of how much file/context surface a prepared task bundle asks the lead, analysis workers, and report-writer to absorb. This sub-command does **not** mutate task artifacts.
|
|
412
|
-
|
|
413
|
-
### cost.1 — Resolve target
|
|
414
|
-
|
|
415
|
-
Accepted target forms:
|
|
416
|
-
|
|
417
|
-
1. Full task-key: `<project-id>:<task-group>:<task-id>`.
|
|
418
|
-
2. Bare token — a task-id (e.g. `DEV-9184`) **or** a task-group (e.g. `PROD`).
|
|
419
|
-
3. Task root path, e.g. `<projectRoot>/.okstra/tasks/<group>/<task-id>`.
|
|
420
|
-
|
|
421
|
-
If the user gives a task root path, run `okstra context-cost <absolute-or-user-provided-path>` directly.
|
|
422
|
-
|
|
423
|
-
If the user gives a full task-key, run:
|
|
424
|
-
|
|
425
|
-
```bash
|
|
426
|
-
okstra context-cost <task-key> --project-root <projectRoot>
|
|
427
|
-
```
|
|
428
|
-
|
|
429
|
-
If the user gives a bare token, resolve it with the shared resolver (SSOT — `scripts/okstra_ctl/resolve_task_key.py` / `okstra_project.resolve_task_reference`). The resolver matches the token as a task-id **and** as a task-group, unioning both (a group expands to its member tasks); each entry carries `_matchedVia` (`"taskId"` | `"taskGroup"`):
|
|
61
|
+
Facets that accept a bare token (a task-id like `DEV-9184` **or** a task-group like `PROD`) resolve it with the shared resolver (SSOT — `scripts/okstra_ctl/resolve_task_key.py` / `okstra_project.resolve_task_reference`). The resolver matches the token as a task-id **and** as a task-group, unioning both (a group expands to its member tasks); each entry carries `_matchedVia` (`"taskId"` | `"taskGroup"`):
|
|
430
62
|
|
|
431
63
|
```bash
|
|
432
64
|
okstra resolve-task-key <token> --project-root <projectRoot> --json
|
|
433
65
|
```
|
|
434
66
|
|
|
435
|
-
Branch on the stdout JSON `matches[]
|
|
67
|
+
Branch on the stdout JSON `matches[]`:
|
|
436
68
|
- **0** → report the task cannot be found. Do not guess.
|
|
437
69
|
- **1** → use that entry's `taskKey`.
|
|
438
70
|
- **N** → list the candidate `taskKey`s (with `updatedAt`, and `_matchedVia` so the user sees which came from a task-id vs a task-group) and ask via a 3-option picker (1–2 recommendations + `Enter directly`), then use the chosen `taskKey`.
|
|
439
71
|
|
|
440
|
-
|
|
72
|
+
### No-task fallback
|
|
73
|
+
|
|
74
|
+
When a facet needs a task but the user did not name one:
|
|
441
75
|
|
|
442
76
|
1. Read `.okstra/discovery/task-catalog.json`.
|
|
443
77
|
2. If exactly one task exists, use it.
|
|
444
|
-
3. If multiple tasks exist, show the latest 10 by `updatedAt` and ask which
|
|
445
|
-
|
|
446
|
-
### cost.2 — Run estimator
|
|
447
|
-
|
|
448
|
-
Use the CLI output as the source of truth:
|
|
449
|
-
|
|
450
|
-
```bash
|
|
451
|
-
okstra context-cost <resolved-target> --project-root <projectRoot>
|
|
452
|
-
```
|
|
453
|
-
|
|
454
|
-
Do not re-count files manually unless the CLI fails and the user explicitly asks for manual fallback.
|
|
455
|
-
|
|
456
|
-
### cost.3 — Render
|
|
457
|
-
|
|
458
|
-
Render the CLI JSON into the cost.4 template. Each row's Files / Size / ~Tokens come from the matching output block — `totals` (Task bundle, Current run, Legacy timestamp), `instructionSet`, `leadPhase1`, `analysisWorker`, `reportWriter`, `skillAssets`; their exact field names are in the CLI output (do not re-list them here). Format bytes as raw + rounded KB/MB.
|
|
459
|
-
|
|
460
|
-
Field-specific notes (these affect interpretation, not just display):
|
|
461
|
-
- Analysis worker uses per-worker fields (`bytesPerWorker`, `estimatedTokensPerWorker`). Use `analysisWorker.estimatedReductionPercent` directly for the worker-input reduction — do **not** recompute it from `bytesPerWorker` when `mode == "analysis-packet-primary"` (that value is already the packet-primary cost).
|
|
462
|
-
- `estimatedTokens*` are a static ranking heuristic (~4 ASCII chars/token, non-ASCII ≈ 1 token/char), never billing numbers — actual cost is the token-usage collector's domain.
|
|
463
|
-
- `skillAssets` = the per-run hot-path instruction assets loaded OUTSIDE the task bundle (skill bodies + agent specs), sorted by size — the prompt-diet target.
|
|
464
|
-
|
|
465
|
-
### cost.4 — Output template
|
|
466
|
-
|
|
467
|
-
```markdown
|
|
468
|
-
## okstra Context Cost — <task-key>
|
|
469
|
-
|
|
470
|
-
| Surface | Files | Size | ~Tokens |
|
|
471
|
-
|---|---:|---:|---:|
|
|
472
|
-
| Task bundle | <N> | <bytes> (<human>) | - |
|
|
473
|
-
| Current run | <N> | <bytes> (<human>) | - |
|
|
474
|
-
| Instruction set | <N> | <bytes> (<human>) | <estimatedTokens> |
|
|
475
|
-
| Lead Phase 1 (`<mode>`) | <N> | <bytes> (<human>) | <estimatedTokens> |
|
|
476
|
-
| Analysis worker / worker (`<mode>`) | <N> | <bytes> (<human>) | <estimatedTokensPerWorker> |
|
|
477
|
-
| Report writer synthesis | <N> | <bytes> (<human>) | <estimatedTokens> |
|
|
478
|
-
| Skill assets (hot path) | <N> | <bytes> (<human>) | <estimatedTokens> |
|
|
479
|
-
|
|
480
|
-
- Current run: `<currentRunPath-or-->`
|
|
481
|
-
- Legacy timestamp artifacts: `<N>`
|
|
482
|
-
- Legacy full worker contract: `<legacyFullContractBytesPerWorker>` bytes (`<human>`) per analysis worker
|
|
483
|
-
- Packet estimate: `<estimatedPacketModeBytesPerWorker>` bytes (`<human>`) per analysis worker
|
|
484
|
-
- Estimated worker-input reduction: `<percent>%`
|
|
485
|
-
|
|
486
|
-
### Reading
|
|
487
|
-
|
|
488
|
-
<One or two Korean sentences explaining the main bottleneck and the next likely optimization target.>
|
|
489
|
-
```
|
|
490
|
-
|
|
491
|
-
Interpretation rules:
|
|
492
|
-
|
|
493
|
-
- `leadPhase1.mode == "active-run-context"` means the compact lead intake file is present and should be treated as the primary lead read surface.
|
|
494
|
-
- `leadPhase1.mode == "legacy-five-file"` means this task was prepared before active-run-context, or the manifest does not reference it.
|
|
495
|
-
- `analysisWorker.mode == "analysis-packet-primary"` means new workers should read `analysis-packet.md` first and open full source inputs only for evidence checks or missing detail.
|
|
496
|
-
- If `analysisWorker.mode == "full-input-contract"` and `estimatedReductionPercent` is low, the next target is worker prompt/input contract slimming.
|
|
497
|
-
- If `reportWriter.bytes` dominates, the next target is a compact `synthesis-input` artifact.
|
|
498
|
-
- If `skillAssets.estimatedTokens` dominates the per-run fixed cost, the next target is slimming the largest `skillAssets.files[]` entries (prompt diet — perf plan v2 P2), e.g. thin-core + lazy-sidecar split.
|
|
499
|
-
- If `legacyTimestampFileCount` is high, recommend current-view/cold-artifact separation or retention cleanup, not destructive deletion by default.
|
|
500
|
-
|
|
501
|
-
---
|
|
502
|
-
|
|
503
|
-
## logs
|
|
504
|
-
|
|
505
|
-
Trigger phrases: "okstra logs", "log status", "log files", "log files", "log size", "log status", "log cleanup", "log cleanup".
|
|
506
|
-
|
|
507
|
-
Read-only inventory of codex/antigravity wrapper log files written next to each prompt history file (`<prompt>.log`). Reports sizes, ages, totals, and suggests cleanup commands. **Does not delete** — the user runs whichever `find … -delete` line they like.
|
|
508
|
-
|
|
509
|
-
**Background:** codex/antigravity wrappers (`okstra-codex-exec.sh`, `okstra-antigravity-exec.sh`) write a sidecar log next to each prompt history file:
|
|
510
|
-
|
|
511
|
-
```
|
|
512
|
-
.okstra/tasks/<task-group>/<task-id>/runs/<phase>/prompts/
|
|
513
|
-
<worker>-worker-prompt-<phase>-<seq>.md <-- prompt (git-tracked)
|
|
514
|
-
<worker>-worker-prompt-<phase>-<seq>.log <-- live stdout+stderr mirror
|
|
515
|
-
```
|
|
516
|
-
|
|
517
|
-
The log is truncated at each dispatch (`: > "$log_path"`) — only the latest run for a given seq is preserved. Different seqs keep separate files. Long-running implementation dispatches can produce multi-MB logs; analysis-phase dispatches are typically smaller.
|
|
518
|
-
|
|
519
|
-
### logs.1 — Inventory
|
|
520
|
-
|
|
521
|
-
```bash
|
|
522
|
-
okstra log-report --project-root <projectRoot> --json
|
|
523
|
-
```
|
|
524
|
-
|
|
525
|
-
Scans `<projectRoot>/.okstra/tasks/**/runs/*/prompts/*.log` and parses task/phase/worker/seq from each path. Returns (sizes are **raw bytes**, mtimes **epoch seconds**):
|
|
526
|
-
- `topLargest[]` — `{path, sizeBytes, mtimeEpoch, taskKey, taskGroup, taskId, phase, worker, seq}`, size desc (widen with `--top <N>`)
|
|
527
|
-
- `perTask[]` — `{taskKey, fileCount, totalBytes, oldestEpoch, newestEpoch}`, total-size desc
|
|
528
|
-
- `totals` — `{fileCount, totalBytes, taskCount}`
|
|
529
|
-
|
|
530
|
-
If `totals.fileCount` is 0, report `No wrapper log files found under <projectRoot>` and stop.
|
|
531
|
-
|
|
532
|
-
### logs.2 — Summary tables
|
|
533
|
-
|
|
534
|
-
Render from the CLI output (format bytes → KB/MB; epoch → `Nd`/`Nh` relative to now):
|
|
535
|
-
|
|
536
|
-
**Table A — Top largest logs** (from `topLargest`): `| # | Task | Phase | Worker | Seq | Size | Age | Path |`.
|
|
537
|
-
|
|
538
|
-
**Table B — Per-task totals** (from `perTask`): `| Task Key | Files | Total Size | Oldest | Newest |`.
|
|
539
|
-
|
|
540
|
-
**Footer:** `Total: <fileCount> files, <totalBytes→MB> across <taskCount> tasks under <PROJECT_ROOT>`.
|
|
541
|
-
|
|
542
|
-
### logs.3 — Suggested cleanup commands
|
|
543
|
-
|
|
544
|
-
Emit a fenced bash block the user can copy-paste. Do NOT execute. Each block pairs a dry-run preview (`-print`) with the destructive (`-delete`) command:
|
|
545
|
-
|
|
546
|
-
```markdown
|
|
547
|
-
## Cleanup options (manual)
|
|
548
|
-
|
|
549
|
-
# Delete only logs older than 7 days
|
|
550
|
-
find <PROJECT_ROOT>/.okstra/tasks \
|
|
551
|
-
-type f -path '*/runs/*/prompts/*.log' -mtime +7 -print # dry-run
|
|
552
|
-
find <PROJECT_ROOT>/.okstra/tasks \
|
|
553
|
-
-type f -path '*/runs/*/prompts/*.log' -mtime +7 -delete
|
|
554
|
-
|
|
555
|
-
# Delete only logs older than 30 days
|
|
556
|
-
find <PROJECT_ROOT>/.okstra/tasks \
|
|
557
|
-
-type f -path '*/runs/*/prompts/*.log' -mtime +30 -print # dry-run
|
|
558
|
-
find <PROJECT_ROOT>/.okstra/tasks \
|
|
559
|
-
-type f -path '*/runs/*/prompts/*.log' -mtime +30 -delete
|
|
560
|
-
|
|
561
|
-
# Delete all logs for a specific task-group (e.g. dev-9388)
|
|
562
|
-
find <PROJECT_ROOT>/.okstra/tasks/dev-9388 \
|
|
563
|
-
-type f -name '*.log' -print # dry-run
|
|
564
|
-
find <PROJECT_ROOT>/.okstra/tasks/dev-9388 \
|
|
565
|
-
-type f -name '*.log' -delete
|
|
566
|
-
|
|
567
|
-
# Delete all logs for a specific task-id (e.g. dev-9428)
|
|
568
|
-
find <PROJECT_ROOT>/.okstra/tasks/*/dev-9428 \
|
|
569
|
-
-type f -name '*.log' -print # dry-run
|
|
570
|
-
find <PROJECT_ROOT>/.okstra/tasks/*/dev-9428 \
|
|
571
|
-
-type f -name '*.log' -delete
|
|
572
|
-
|
|
573
|
-
# Delete everything (caution)
|
|
574
|
-
find <PROJECT_ROOT>/.okstra/tasks \
|
|
575
|
-
-type f -path '*/runs/*/prompts/*.log' -print # dry-run
|
|
576
|
-
find <PROJECT_ROOT>/.okstra/tasks \
|
|
577
|
-
-type f -path '*/runs/*/prompts/*.log' -delete
|
|
578
|
-
```
|
|
579
|
-
|
|
580
|
-
Substitute the literal `<PROJECT_ROOT>` with the resolved absolute path so the commands are directly copy-pasteable.
|
|
581
|
-
|
|
582
|
-
### logs.4 — Notes for the user
|
|
583
|
-
|
|
584
|
-
- Logs are truncated on each re-dispatch of the same `seq`, so deleting an in-flight run's log will cause the wrapper to recreate an empty file on the next dispatch — no data loss beyond the current trace.
|
|
585
|
-
- **If a dispatch is currently running, check the `status` sub-command first** and avoid deleting logs for tasks in `in-progress` state — you will lose the live trace for the active run.
|
|
586
|
-
- Prompt history files (`.md`) are separate and are NOT touched by these commands — only `.log` sidecars.
|
|
587
|
-
- This sub-command **does not modify any external files itself**, including `.gitignore`. If the project commits `.okstra/`, the user may want to add `.okstra/tasks/**/runs/**/prompts/*.log` to `.gitignore` manually to keep large logs out of git.
|
|
588
|
-
|
|
589
|
-
---
|
|
590
|
-
|
|
591
|
-
## errors
|
|
592
|
-
|
|
593
|
-
Trigger phrases: "okstra errors", "error report", "error report (Korean)", "error summary", "gather the errors", "clean up failure logs".
|
|
594
|
-
|
|
595
|
-
Aggregate a task's okstra-run error logs (`runs/*/logs/errors-*.jsonl`, lead-observed + worker-reported) into a timestamped markdown report and summarize it. This sub-command renders a **read-derived artifact** (a `.md` file) but never mutates task state (`task-manifest.json`, catalog, timeline).
|
|
596
|
-
|
|
597
|
-
### errors.1 — Resolve target
|
|
598
|
-
|
|
599
|
-
Accepted target forms (same as `cost`):
|
|
600
|
-
|
|
601
|
-
1. Full task-key: `<project-id>:<task-group>:<task-id>`.
|
|
602
|
-
2. Bare token (task-id or task-group) — resolve via `okstra resolve-task-key <token> --project-root <projectRoot> --json` and branch on `matches[]` using the standard 0/1/N rule from `cost.1` (0 = not found, 1 = use, N = picker).
|
|
603
|
-
3. Task root path.
|
|
604
|
-
|
|
605
|
-
If the user asks for an error report without naming a task, apply the same no-task fallback as `cost.1` — list only the placeholder forms and do not ask back: read `.okstra/discovery/task-catalog.json`, use the single task as-is if there is one, and if there are several, list the latest 10 by `updatedAt` as real task-keys and ask (no guessing).
|
|
606
|
-
|
|
607
|
-
### errors.2 — Run the renderer
|
|
608
|
-
|
|
609
|
-
Use the CLI output as the source of truth:
|
|
610
|
-
|
|
611
|
-
```bash
|
|
612
|
-
okstra error-report <resolved-target> --project-root <projectRoot>
|
|
613
|
-
```
|
|
614
|
-
|
|
615
|
-
For a task-root path, run `okstra error-report <path>` directly. Do not parse the jsonl files by hand unless the CLI fails and the user explicitly asks for a manual fallback.
|
|
616
|
-
|
|
617
|
-
### errors.3 — Summarize output
|
|
618
|
-
|
|
619
|
-
Parse the stdout JSON and report:
|
|
620
|
-
|
|
621
|
-
| Field | Source |
|
|
622
|
-
|---|---|
|
|
623
|
-
| Report file | `reportPath` (project-root-relative `.md`) |
|
|
624
|
-
| Total errors | `totals.errorCount` |
|
|
625
|
-
| Logs (runs) | `totals.runCount` |
|
|
626
|
-
| By errorType | `totals.byErrorType` (tool-failure / cli-failure / contract-violation) |
|
|
627
|
-
| By source | `totals.bySource` (lead-observed / worker-reported) |
|
|
628
|
-
| By phase | `byPhase[]` |
|
|
629
|
-
| By agent | `byAgent[]` |
|
|
630
|
-
| Parse-skipped lines | `parseSkipped` |
|
|
631
|
-
|
|
632
|
-
- If `reportPath` is empty AND `totals.errorCount == 0`: report `This task has no recorded error logs.` and do not claim a file was written.
|
|
633
|
-
- Otherwise show the `.md` path and offer to read it.
|
|
634
|
-
- If `parseSkipped > 0`, surface it (do not silently hide malformed lines).
|
|
635
|
-
|
|
636
|
-
### errors — Output template
|
|
637
|
-
|
|
638
|
-
```markdown
|
|
639
|
-
## okstra Error Report — <task-key>
|
|
640
|
-
|
|
641
|
-
- Report: `<reportPath-or-->`
|
|
642
|
-
- Total errors: <N> across <runCount> log(s)
|
|
643
|
-
- By type: <tool-failure: a, cli-failure: b, ...>
|
|
644
|
-
- By source: <lead-observed: x, worker-reported: y>
|
|
645
|
-
|
|
646
|
-
| Phase | Count |
|
|
647
|
-
|---|---:|
|
|
648
|
-
| implementation | 3 |
|
|
649
|
-
|
|
650
|
-
| Agent | Count |
|
|
651
|
-
|---|---:|
|
|
652
|
-
| codex-worker | 2 |
|
|
653
|
-
|
|
654
|
-
<If parseSkipped > 0: "⚠ Parse-skipped lines: <N>">
|
|
655
|
-
```
|
|
656
|
-
|
|
657
|
-
---
|
|
658
|
-
|
|
659
|
-
## error-zip
|
|
660
|
-
|
|
661
|
-
Trigger phrases: "okstra error-zip", "error zip", "error feedback", "error bundle", "cross-project errors".
|
|
662
|
-
|
|
663
|
-
Collect and anonymize the okstra run errors (`runs/*/logs/errors-*.jsonl`) of every target project on the machine into the global run-index, then bundle them as a `.zip` (aggregate report + anonymized JSONL). Read-only over every target's `.okstra/`.
|
|
664
|
-
|
|
665
|
-
### error-zip.1 — Decide the output path (picker)
|
|
666
|
-
|
|
667
|
-
Read the previous output path from `lastOutputPath` in `~/.okstra/error-zip.json`. If that value exists, present it in a 3-option picker:
|
|
668
|
-
|
|
669
|
-
1. (previous path exists) reuse `<lastOutputPath>` — recommended, first option.
|
|
670
|
-
(no previous path) propose the default path `~/okstra-error-feedback-<YYYY-MM-DD>.zip` — recommended.
|
|
671
|
-
2. Enter directly (always the last option).
|
|
672
|
-
|
|
673
|
-
Read `~/.okstra/error-zip.json` directly with Read (if absent, treat it as no previous path).
|
|
674
|
-
|
|
675
|
-
### error-zip.2 — Run the renderer
|
|
676
|
-
|
|
677
|
-
```bash
|
|
678
|
-
okstra error-zip --out <resolved-path>
|
|
679
|
-
```
|
|
680
|
-
|
|
681
|
-
### error-zip.3 — Report the summary
|
|
682
|
-
|
|
683
|
-
Parse the stdout JSON and report:
|
|
684
|
-
|
|
685
|
-
| Field | Source |
|
|
686
|
-
|---|---|
|
|
687
|
-
| Output zip | `outPath` |
|
|
688
|
-
| Total errors | `errorCount` |
|
|
689
|
-
| Logs (runs) | `runCount` |
|
|
690
|
-
| Unreachable runs | `unreachableRuns` |
|
|
691
|
-
| Cluster count | `clusterCount` |
|
|
692
|
-
| Project count | `projectCount` |
|
|
693
|
-
|
|
694
|
-
- If `unreachableRuns > 0`, surface it (no silent omission).
|
|
695
|
-
- End with the next step: "To fix okstra itself with this zip, build a brief with the error-feedback variant of `/okstra-brief-gen`, then run `okstra-run --task-type error-analysis` in the okstra repo."
|
|
696
|
-
|
|
697
|
-
---
|
|
698
|
-
|
|
699
|
-
## recap
|
|
700
|
-
|
|
701
|
-
Trigger phrases: "okstra recap", "recap", "work summary", "summarize this task", "before/after summary", "explain this work", "task question".
|
|
702
|
-
|
|
703
|
-
On top of the `.okstra` artifacts accumulated for a single task-id, (a) produce a before/after summary and (b) answer free-form questions about that work. By default it reads only the `.okstra/` subtree (artifact mode). It expands to code mode only when the user explicitly asks to look at the code changes too. This sub-command performs only the `recap/recap-log.jsonl` append and the `notes/` note authoring (recap.5); it never mutates `task-manifest.json` / catalog / timeline.
|
|
704
|
-
|
|
705
|
-
### recap.1 — Resolve target
|
|
706
|
-
|
|
707
|
-
The same three forms as `cost` / `errors`: ① full task-key, ② bare token (task-id or task-group → `okstra resolve-task-key <token> --project-root <projectRoot> --json`; the standard 0/1/N branch from `cost.1`), ③ task-root path.
|
|
708
|
-
|
|
709
|
-
If the user asks for a recap without naming a task (e.g. "summarize this work"), apply the `cost.1` no-task fallback as-is — do not list only a placeholder form like `<task-group>` and ask back; read `.okstra/discovery/task-catalog.json`, use the single task as-is if there is one, and if there are several, list the latest 10 by `updatedAt` as real task-keys and ask (no guessing).
|
|
710
|
-
|
|
711
|
-
### recap.2 — Assemble the before/after summary
|
|
712
|
-
|
|
713
|
-
Use the CLI output as the source of truth:
|
|
714
|
-
|
|
715
|
-
```bash
|
|
716
|
-
okstra recap assemble <resolved-target> --project-root <projectRoot>
|
|
717
|
-
```
|
|
718
|
-
|
|
719
|
-
Parse the stdout JSON (`{taskKey, runCount, transitions[], latestPhaseStates}`) and narrate the per-run before/after transitions. For each `transitions[]` entry, show `fromPhase → toPhase` (previous run currentPhase → this run currentPhase), `status`, `lastCompletedPhase`, `nextRecommendedPhase`, and `reportPath` in chronological order. If `runCount == 0`, answer only "This task has no recorded runs." and do not claim to have read any file.
|
|
720
|
-
|
|
721
|
-
For a run that has a `reportPath`, read that final-report to enrich the summary only when the user wants a deeper one (do not read them all automatically).
|
|
722
|
-
|
|
723
|
-
### recap.3 — Free-form Q&A loop
|
|
724
|
-
|
|
725
|
-
After the summary output, take the user's free-form questions.
|
|
726
|
-
|
|
727
|
-
- **artifact mode (default)**: answer only from `.okstra/` artifacts (timeline, task-manifest, that run's final-report). Every factual claim is accompanied by a `path:line` citation to the `.okstra` file.
|
|
728
|
-
- **code mode (opt-in)**: only when the user **explicitly asks** — "look at the code changes / the diff too" — additionally read `git diff` · `git log` from that task's worktree/branch and answer at the code level. Entering recap never by itself switches to code mode.
|
|
729
|
-
|
|
730
|
-
### recap.4 — Persist each turn
|
|
731
|
-
|
|
732
|
-
Log one summary and each Q&A answer (append-only):
|
|
733
|
-
|
|
734
|
-
```bash
|
|
735
|
-
okstra recap record <resolved-target> --project-root <projectRoot> \
|
|
736
|
-
--kind <summary|qa> --mode <artifact|code> \
|
|
737
|
-
--question "<question or omit>" --answer "<one or two line summary>" \
|
|
738
|
-
--citation "<path:line>" --citation "<path:line>"
|
|
739
|
-
```
|
|
740
|
-
|
|
741
|
-
Put a one-or-two-line summary in `--answer`, not the full answer transcript. If there are multiple citations, repeat `--citation`. Do not silently swallow a recording failure (abnormal exit) — tell the user.
|
|
742
|
-
|
|
743
|
-
### recap — Output template
|
|
744
|
-
|
|
745
|
-
```markdown
|
|
746
|
-
## okstra Recap — <task-key>
|
|
747
|
-
|
|
748
|
-
Before/after summary (runs: <N>):
|
|
749
|
-
|
|
750
|
-
| # | when | task-type | from → to | status | next |
|
|
751
|
-
|---|---|---|---|---|---|
|
|
752
|
-
| 1 | <ts> | requirements-discovery | (start) → requirements-discovery | done | error-analysis |
|
|
753
|
-
|
|
754
|
-
<Free-form questions follow. To include code changes, ask "also show me the diff".>
|
|
755
|
-
```
|
|
756
|
-
|
|
757
|
-
### recap.5 — Agent-authored notes (`notes/`)
|
|
758
|
-
|
|
759
|
-
Leave something in `notes/` only when, during recap, you produced an artifact **for the okstra task** — verification evidence, a design/decision draft, an analysis note — that may serve as grounding for future runs, and whose content is **neither a rendered report nor a user decision**.
|
|
760
|
-
|
|
761
|
-
**Route by ownership.** First determine which of the following the thing you are about to write belongs to:
|
|
762
|
-
|
|
763
|
-
| Content | Lane (path) | Author |
|
|
764
|
-
|---|---|---|
|
|
765
|
-
| final report body | `runs/<type>/reports/*.md` (rendered from `*.data.json`) | okstra renderer — never hand-edit |
|
|
766
|
-
| user's answer to a clarification | `runs/<type>/user-responses/*.md` (`created-by: user`) | user only |
|
|
767
|
-
| finalized ADR | `.okstra/decisions/NNNN-*.md` | promoted / managed |
|
|
768
|
-
| **Agent evidence / design draft / analysis** | **`.okstra/tasks/<group>/<id>/notes/`** | you (the AI) |
|
|
769
|
-
|
|
770
|
-
If it is **your own grounding/draft** — not a rendered artifact, not a user decision — it goes to `notes/`. Do not hand-stamp the note; write it via the CLI — code guarantees the path/frontmatter/date and prints the argument to pass into the next run:
|
|
771
|
-
|
|
772
|
-
```bash
|
|
773
|
-
okstra recap note <resolved-target> --project-root <projectRoot> \
|
|
774
|
-
--kind <verification-evidence|decision-draft|analysis-note> \
|
|
775
|
-
--slug <short-topic-slug> \
|
|
776
|
-
--purpose "<one line — what it is and which run/decision it feeds>" \
|
|
777
|
-
--scope-note "<one line — what it is NOT, e.g. not a user decision on C-00x>" \
|
|
778
|
-
--body-file <note-body markdown path>
|
|
779
|
-
```
|
|
780
|
-
|
|
781
|
-
Write the body to the scratchpad as markdown first, then pass it with `--body-file` (if short, an inline `--body "<md>"` also works). The CLI creates `.okstra/tasks/<group>/<id>/notes/<slug>-<YYYY-MM-DD>.md` and returns `notePath` and `clarificationResponseArg` as stdout JSON.
|
|
782
|
-
|
|
783
|
-
**self-check rules (there is no validator, so you keep them yourself):**
|
|
784
|
-
|
|
785
|
-
1. **Do not hand-edit a rendered report** (`*.md` / `*.data.json` / `*.html` under `runs/*/reports/`). Because it is regenerated from `data.json`, an edit is overwritten and diverges from the SSOT. Write findings to `notes/` instead.
|
|
786
|
-
2. **Do not author a `user-responses/` file or apply `created-by: user`.** That is the user's decision, and writing it for them forges a decision the user never made. If your evidence supports a particular answer, write that in `notes/` and leave the decision to the user. The one exception is the echo-back confirmation flow of the `okstra-user-response` skill — there the user makes the decision in-session and the CLI is merely a transcription channel, so recording a `created-by: user` sidecar with `write` is legitimate. This exception holds only after the user has explicitly confirmed "correct", and only for verbatim input.
|
|
787
|
-
3. **Do not write to okstra-managed directories** (`runs/`, `instruction-set/`, `history/`, `recap/`, `.okstra/decisions/`). `notes/` is the only agent-owned lane. `recap/recap-log.jsonl` is the exception — write it, but not by hand; only via the `okstra recap record` CLI.
|
|
788
|
-
4. **`notes/` is inert to okstra** — no run reads it automatically. After writing, relay the `clarificationResponseArg` the CLI printed (e.g. `--clarification-response <notePath>`) to the user verbatim, telling them it only takes effect when the next run is executed with that argument.
|
|
789
|
-
|
|
790
|
-
**Guardrail:** `.okstra/` is gitignored — treat `notes/` as local scratch and never `git add` it. Creating a new note is easy to undo (delete the file), so always prefer it over editing a generated or user-owned file.
|
|
791
|
-
|
|
792
|
-
---
|
|
78
|
+
3. If multiple tasks exist, show the latest 10 by `updatedAt` as real task-keys and ask which one. Do not guess, and do not answer with placeholder forms only.
|
|
793
79
|
|
|
794
80
|
## Output Rules (shared)
|
|
795
81
|
|