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,84 @@
1
+ # okstra-inspect facet — cost
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
+ ## cost
6
+
7
+ Trigger phrases: "okstra context-cost", "context cost", "context-cost", "read cost", "artifact cost", "task bundle cost", "agent read cost".
8
+
9
+ 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.
10
+
11
+ ### cost.1 — Resolve target
12
+
13
+ Accepted target forms:
14
+
15
+ 1. Full task-key: `<project-id>:<task-group>:<task-id>`.
16
+ 2. Bare token — a task-id (e.g. `DEV-9184`) **or** a task-group (e.g. `PROD`).
17
+ 3. Task root path, e.g. `<projectRoot>/.okstra/tasks/<group>/<task-id>`.
18
+
19
+ If the user gives a task root path, run `okstra context-cost <absolute-or-user-provided-path>` directly.
20
+
21
+ If the user gives a full task-key, run:
22
+
23
+ ```bash
24
+ okstra context-cost <task-key> --project-root <projectRoot>
25
+ ```
26
+
27
+ If the user gives a bare token, resolve it via the standard task-key resolution rule in `SKILL.md` (core).
28
+
29
+ If the user asks generally ("show me the context cost") and does not name a task, apply the core no-task fallback to pick the task to measure.
30
+
31
+ ### cost.2 — Run estimator
32
+
33
+ Use the CLI output as the source of truth:
34
+
35
+ ```bash
36
+ okstra context-cost <resolved-target> --project-root <projectRoot>
37
+ ```
38
+
39
+ Do not re-count files manually unless the CLI fails and the user explicitly asks for manual fallback.
40
+
41
+ ### cost.3 — Render
42
+
43
+ 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.
44
+
45
+ Field-specific notes (these affect interpretation, not just display):
46
+ - 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).
47
+ - `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.
48
+ - `skillAssets` = the per-run hot-path instruction assets loaded OUTSIDE the task bundle (skill bodies + agent specs), sorted by size — the prompt-diet target.
49
+
50
+ ### cost.4 — Output template
51
+
52
+ ```markdown
53
+ ## okstra Context Cost — <task-key>
54
+
55
+ | Surface | Files | Size | ~Tokens |
56
+ |---|---:|---:|---:|
57
+ | Task bundle | <N> | <bytes> (<human>) | - |
58
+ | Current run | <N> | <bytes> (<human>) | - |
59
+ | Instruction set | <N> | <bytes> (<human>) | <estimatedTokens> |
60
+ | Lead Phase 1 (`<mode>`) | <N> | <bytes> (<human>) | <estimatedTokens> |
61
+ | Analysis worker / worker (`<mode>`) | <N> | <bytes> (<human>) | <estimatedTokensPerWorker> |
62
+ | Report writer synthesis | <N> | <bytes> (<human>) | <estimatedTokens> |
63
+ | Skill assets (hot path) | <N> | <bytes> (<human>) | <estimatedTokens> |
64
+
65
+ - Current run: `<currentRunPath-or-->`
66
+ - Legacy timestamp artifacts: `<N>`
67
+ - Legacy full worker contract: `<legacyFullContractBytesPerWorker>` bytes (`<human>`) per analysis worker
68
+ - Packet estimate: `<estimatedPacketModeBytesPerWorker>` bytes (`<human>`) per analysis worker
69
+ - Estimated worker-input reduction: `<percent>%`
70
+
71
+ ### Reading
72
+
73
+ <One or two Korean sentences explaining the main bottleneck and the next likely optimization target.>
74
+ ```
75
+
76
+ Interpretation rules:
77
+
78
+ - `leadPhase1.mode == "active-run-context"` means the compact lead intake file is present and should be treated as the primary lead read surface.
79
+ - `leadPhase1.mode == "legacy-five-file"` means this task was prepared before active-run-context, or the manifest does not reference it.
80
+ - `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.
81
+ - If `analysisWorker.mode == "full-input-contract"` and `estimatedReductionPercent` is low, the next target is worker prompt/input contract slimming.
82
+ - If `reportWriter.bytes` dominates, the next target is a compact `synthesis-input` artifact.
83
+ - 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.
84
+ - If `legacyTimestampFileCount` is high, recommend current-view/cold-artifact separation or retention cleanup, not destructive deletion by default.
@@ -0,0 +1,41 @@
1
+ # okstra-inspect facet — error-zip
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
+ ## error-zip
6
+
7
+ Trigger phrases: "okstra error-zip", "error zip", "error feedback", "error bundle", "cross-project errors".
8
+
9
+ 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/`.
10
+
11
+ ### error-zip.1 — Decide the output path (picker)
12
+
13
+ Read the previous output path from `lastOutputPath` in `~/.okstra/error-zip.json`. If that value exists, present it in a 3-option picker:
14
+
15
+ 1. (previous path exists) reuse `<lastOutputPath>` — recommended, first option.
16
+ (no previous path) propose the default path `~/okstra-error-feedback-<YYYY-MM-DD>.zip` — recommended.
17
+ 2. Enter directly (always the last option).
18
+
19
+ Read `~/.okstra/error-zip.json` directly with Read (if absent, treat it as no previous path).
20
+
21
+ ### error-zip.2 — Run the renderer
22
+
23
+ ```bash
24
+ okstra error-zip --out <resolved-path>
25
+ ```
26
+
27
+ ### error-zip.3 — Report the summary
28
+
29
+ Parse the stdout JSON and report:
30
+
31
+ | Field | Source |
32
+ |---|---|
33
+ | Output zip | `outPath` |
34
+ | Total errors | `errorCount` |
35
+ | Logs (runs) | `runCount` |
36
+ | Unreachable runs | `unreachableRuns` |
37
+ | Cluster count | `clusterCount` |
38
+ | Project count | `projectCount` |
39
+
40
+ - If `unreachableRuns > 0`, surface it (no silent omission).
41
+ - 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."
@@ -0,0 +1,69 @@
1
+ # okstra-inspect facet — errors
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
+ ## errors
6
+
7
+ Trigger phrases: "okstra errors", "error report", "error summary", "gather the errors", "clean up failure logs".
8
+
9
+ 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).
10
+
11
+ ### errors.1 — Resolve target
12
+
13
+ Accepted target forms (same as `cost`):
14
+
15
+ 1. Full task-key: `<project-id>:<task-group>:<task-id>`.
16
+ 2. Bare token (task-id or task-group) — resolve via the standard task-key resolution rule in `SKILL.md` (core).
17
+ 3. Task root path.
18
+
19
+ If the user asks for an error report without naming a task, apply the core no-task fallback — never list only placeholder forms and ask back.
20
+
21
+ ### errors.2 — Run the renderer
22
+
23
+ Use the CLI output as the source of truth:
24
+
25
+ ```bash
26
+ okstra error-report <resolved-target> --project-root <projectRoot>
27
+ ```
28
+
29
+ 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.
30
+
31
+ ### errors.3 — Summarize output
32
+
33
+ Parse the stdout JSON and report:
34
+
35
+ | Field | Source |
36
+ |---|---|
37
+ | Report file | `reportPath` (project-root-relative `.md`) |
38
+ | Total errors | `totals.errorCount` |
39
+ | Logs (runs) | `totals.runCount` |
40
+ | By errorType | `totals.byErrorType` (tool-failure / cli-failure / contract-violation) |
41
+ | By source | `totals.bySource` (lead-observed / worker-reported) |
42
+ | By phase | `byPhase[]` |
43
+ | By agent | `byAgent[]` |
44
+ | Parse-skipped lines | `parseSkipped` |
45
+
46
+ - If `reportPath` is empty AND `totals.errorCount == 0`: report `This task has no recorded error logs.` and do not claim a file was written.
47
+ - Otherwise show the `.md` path and offer to read it.
48
+ - If `parseSkipped > 0`, surface it (do not silently hide malformed lines).
49
+
50
+ ### errors — Output template
51
+
52
+ ```markdown
53
+ ## okstra Error Report — <task-key>
54
+
55
+ - Report: `<reportPath-or-->`
56
+ - Total errors: <N> across <runCount> log(s)
57
+ - By type: <tool-failure: a, cli-failure: b, ...>
58
+ - By source: <lead-observed: x, worker-reported: y>
59
+
60
+ | Phase | Count |
61
+ |---|---:|
62
+ | implementation | 3 |
63
+
64
+ | Agent | Count |
65
+ |---|---:|
66
+ | codex-worker | 2 |
67
+
68
+ <If parseSkipped > 0: "⚠ Parse-skipped lines: <N>">
69
+ ```
@@ -0,0 +1,90 @@
1
+ # okstra-inspect facet — history
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
+ ## history
6
+
7
+ Trigger phrases: "okstra history", "past runs", "run history", "re-run", "list tasks", "run again", "resume", "continue".
8
+
9
+ **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.
10
+
11
+ ### history.1 — Read the task catalog
12
+
13
+ 1. Read `.okstra/discovery/task-catalog.json`.
14
+ 2. Apply filters from user input (all optional, AND-combined):
15
+ - `--task-type <type>` → keep entries whose `taskType` matches.
16
+ - `--latest-run-status <status>` → keep entries whose `latestRunStatus` matches (`completed`, `contract-violated`, `error`).
17
+ - `--task-group <group>` → keep entries whose `taskGroup` matches.
18
+ 3. Sort by `updatedAt` desc.
19
+ 4. Page: default `--limit 20`. If truncated, add `... <N> more (pass --limit <N> to see all)`.
20
+ 5. Extract: `taskKey`, `taskType`, `currentStatus`, `latestRunStatus`, `latestRunManifestPath`, `updatedAt`, `latestReportPath`, `latestResumeCommandPath`, `historyTimelinePath`.
21
+
22
+ ```markdown
23
+ ## okstra Task History — <project-id>
24
+
25
+ | # | Task Key | Type | currentStatus | latestRunStatus | Last Run | Report |
26
+ |---|----------|------|---------------|------------------|----------|--------|
27
+ | 1 | proj:group:id | error-analysis | completed | completed | 2026-04-05 22:59 | .project-docs/.../final-report-*.md |
28
+ | 2 | proj:group:id2 | final-verification | todo | error | 2026-04-04 15:30 | -- |
29
+ ```
30
+
31
+ **Catalog absent — fallback.** Do NOT bail out. Manifests on disk are the source of truth.
32
+
33
+ 1. Glob `<projectRoot>/.okstra/tasks/*/*/task-manifest.json`.
34
+ 2. For each manifest, read the same fields as above.
35
+ 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.`
36
+ 4. Only if the glob yields zero manifests: `There is no okstra execution history yet.`
37
+
38
+ ### history.2 — Run history by task
39
+
40
+ When a user selects a specific task:
41
+
42
+ 1. Retrieve `historyTimelinePath`, read `runs` array.
43
+ 2. Extract: `runTimestamp`, `runDateTimeSegment`, `taskType`, `status`, `runManifestPath`, `reportPath`, `resumeCommandPath`, `relatedTasks`.
44
+
45
+ ```markdown
46
+ ## Runs for <task-key>
47
+
48
+ | # | Timestamp | Type | Status | Report |
49
+ |---|-----------|------|--------|--------|
50
+ | 1 | 2026-04-05 22:59 | error-analysis | completed | .../final-report-*.md |
51
+ | 2 | 2026-04-04 15:30 | error-analysis | error | -- |
52
+ ```
53
+
54
+ ### history.3 — Re-run (NEW run from old parameters)
55
+
56
+ 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.
57
+
58
+ 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.
59
+ 2. Read the manifest and extract required arguments:
60
+ - `projectId` → `--project-id`
61
+ - `taskGroup` → `--task-group`
62
+ - `taskId` → `--task-id`
63
+ - `taskType` → `--task-type`
64
+ - `taskBriefPath` → `--task-brief`
65
+ 3. Optional arguments (include only when present in source):
66
+ - `recommendedWorkers` → `--workers` (comma-separated)
67
+ - `relatedTasks` → `--related-tasks`
68
+ - model overrides → `--claude-model`, `--codex-model`, `--antigravity-model`
69
+ - for `taskType: implementation`: `teamContract.executor.provider` → `--executor <claude|codex|antigravity>` when different from `claude`.
70
+ 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.
71
+ 5. Display the assembled command:
72
+ ```bash
73
+ ~/.okstra/bin/okstra.sh \
74
+ --project-id <project-id> \
75
+ --task-group <task-group> \
76
+ --task-id <task-id> \
77
+ --task-type <task-type> \
78
+ --task-brief <brief-path> \
79
+ --workers <worker-list>
80
+ ```
81
+ 6. Once the user confirms, execute it.
82
+
83
+ ### history.4 — Resume (continue an interrupted run)
84
+
85
+ Continues an existing Claude session for an unfinished run. Does NOT create a new run-seq — for a fresh dispatch use `history.3`.
86
+
87
+ 1. Read `latestResumeCommandPath` from `history.1` (or `resumeCommandPath` from a `history.2` timeline entry).
88
+ 2. Verify the file exists on disk.
89
+ 3. If it exists: `bash <resume-command-path>`.
90
+ 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.`
@@ -0,0 +1,89 @@
1
+ # okstra-inspect facet — logs
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
+ ## logs
6
+
7
+ Trigger phrases: "okstra logs", "log status", "log files", "log size", "log cleanup".
8
+
9
+ 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.
10
+
11
+ **Background:** codex/antigravity wrappers (`okstra-codex-exec.sh`, `okstra-antigravity-exec.sh`) write a sidecar log next to each prompt history file:
12
+
13
+ ```
14
+ .okstra/tasks/<task-group>/<task-id>/runs/<phase>/prompts/
15
+ <worker>-worker-prompt-<phase>-<seq>.md <-- prompt (git-tracked)
16
+ <worker>-worker-prompt-<phase>-<seq>.log <-- live stdout+stderr mirror
17
+ ```
18
+
19
+ 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.
20
+
21
+ ### logs.1 — Inventory
22
+
23
+ ```bash
24
+ okstra log-report --project-root <projectRoot> --json
25
+ ```
26
+
27
+ Scans `<projectRoot>/.okstra/tasks/**/runs/*/prompts/*.log` and parses task/phase/worker/seq from each path. Returns (sizes are **raw bytes**, mtimes **epoch seconds**):
28
+ - `topLargest[]` — `{path, sizeBytes, mtimeEpoch, taskKey, taskGroup, taskId, phase, worker, seq}`, size desc (widen with `--top <N>`)
29
+ - `perTask[]` — `{taskKey, fileCount, totalBytes, oldestEpoch, newestEpoch}`, total-size desc
30
+ - `totals` — `{fileCount, totalBytes, taskCount}`
31
+
32
+ If `totals.fileCount` is 0, report `No wrapper log files found under <projectRoot>` and stop.
33
+
34
+ ### logs.2 — Summary tables
35
+
36
+ Render from the CLI output (format bytes → KB/MB; epoch → `Nd`/`Nh` relative to now):
37
+
38
+ **Table A — Top largest logs** (from `topLargest`): `| # | Task | Phase | Worker | Seq | Size | Age | Path |`.
39
+
40
+ **Table B — Per-task totals** (from `perTask`): `| Task Key | Files | Total Size | Oldest | Newest |`.
41
+
42
+ **Footer:** `Total: <fileCount> files, <totalBytes→MB> across <taskCount> tasks under <PROJECT_ROOT>`.
43
+
44
+ ### logs.3 — Suggested cleanup commands
45
+
46
+ 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:
47
+
48
+ ```markdown
49
+ ## Cleanup options (manual)
50
+
51
+ # Delete only logs older than 7 days
52
+ find <PROJECT_ROOT>/.okstra/tasks \
53
+ -type f -path '*/runs/*/prompts/*.log' -mtime +7 -print # dry-run
54
+ find <PROJECT_ROOT>/.okstra/tasks \
55
+ -type f -path '*/runs/*/prompts/*.log' -mtime +7 -delete
56
+
57
+ # Delete only logs older than 30 days
58
+ find <PROJECT_ROOT>/.okstra/tasks \
59
+ -type f -path '*/runs/*/prompts/*.log' -mtime +30 -print # dry-run
60
+ find <PROJECT_ROOT>/.okstra/tasks \
61
+ -type f -path '*/runs/*/prompts/*.log' -mtime +30 -delete
62
+
63
+ # Delete all logs for a specific task-group (e.g. dev-9388)
64
+ find <PROJECT_ROOT>/.okstra/tasks/dev-9388 \
65
+ -type f -name '*.log' -print # dry-run
66
+ find <PROJECT_ROOT>/.okstra/tasks/dev-9388 \
67
+ -type f -name '*.log' -delete
68
+
69
+ # Delete all logs for a specific task-id (e.g. dev-9428)
70
+ find <PROJECT_ROOT>/.okstra/tasks/*/dev-9428 \
71
+ -type f -name '*.log' -print # dry-run
72
+ find <PROJECT_ROOT>/.okstra/tasks/*/dev-9428 \
73
+ -type f -name '*.log' -delete
74
+
75
+ # Delete everything (caution)
76
+ find <PROJECT_ROOT>/.okstra/tasks \
77
+ -type f -path '*/runs/*/prompts/*.log' -print # dry-run
78
+ find <PROJECT_ROOT>/.okstra/tasks \
79
+ -type f -path '*/runs/*/prompts/*.log' -delete
80
+ ```
81
+
82
+ Substitute the literal `<PROJECT_ROOT>` with the resolved absolute path so the commands are directly copy-pasteable.
83
+
84
+ ### logs.4 — Notes for the user
85
+
86
+ - 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.
87
+ - **If a dispatch is currently running, check task status first (load `facets/status.md`)** and avoid deleting logs for tasks in `in-progress` state — you will lose the live trace for the active run.
88
+ - Prompt history files (`.md`) are separate and are NOT touched by these commands — only `.log` sidecars.
89
+ - 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.
@@ -0,0 +1,96 @@
1
+ # okstra-inspect facet — recap
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
+ ## recap
6
+
7
+ Trigger phrases: "okstra recap", "recap", "work summary", "summarize this task", "before/after summary", "explain this work", "task question".
8
+
9
+ 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.
10
+
11
+ ### recap.1 — Resolve target
12
+
13
+ The same three forms as `cost` / `errors`: ① full task-key, ② bare token — the standard task-key resolution rule in `SKILL.md` (core), ③ task-root path.
14
+
15
+ If the user asks for a recap without naming a task (e.g. "summarize this work"), apply the core no-task fallback as-is — do not list only a placeholder form like `<task-group>` and ask back.
16
+
17
+ ### recap.2 — Assemble the before/after summary
18
+
19
+ Use the CLI output as the source of truth:
20
+
21
+ ```bash
22
+ okstra recap assemble <resolved-target> --project-root <projectRoot>
23
+ ```
24
+
25
+ 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.
26
+
27
+ 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).
28
+
29
+ ### recap.3 — Free-form Q&A loop
30
+
31
+ After the summary output, take the user's free-form questions.
32
+
33
+ - **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.
34
+ - **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.
35
+
36
+ ### recap.4 — Persist each turn
37
+
38
+ Log one summary and each Q&A answer (append-only):
39
+
40
+ ```bash
41
+ okstra recap record <resolved-target> --project-root <projectRoot> \
42
+ --kind <summary|qa> --mode <artifact|code> \
43
+ --question "<question or omit>" --answer "<one or two line summary>" \
44
+ --citation "<path:line>" --citation "<path:line>"
45
+ ```
46
+
47
+ 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.
48
+
49
+ ### recap — Output template
50
+
51
+ ```markdown
52
+ ## okstra Recap — <task-key>
53
+
54
+ Before/after summary (runs: <N>):
55
+
56
+ | # | when | task-type | from → to | status | next |
57
+ |---|---|---|---|---|---|
58
+ | 1 | <ts> | requirements-discovery | (start) → requirements-discovery | done | error-analysis |
59
+
60
+ <Free-form questions follow. To include code changes, ask "also show me the diff".>
61
+ ```
62
+
63
+ ### recap.5 — Agent-authored notes (`notes/`)
64
+
65
+ 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**.
66
+
67
+ **Route by ownership.** First determine which of the following the thing you are about to write belongs to:
68
+
69
+ | Content | Lane (path) | Author |
70
+ |---|---|---|
71
+ | final report body | `runs/<type>/reports/*.md` (rendered from `*.data.json`) | okstra renderer — never hand-edit |
72
+ | user's answer to a clarification | `runs/<type>/user-responses/*.md` (`created-by: user`) | user only |
73
+ | finalized ADR | `.okstra/decisions/NNNN-*.md` | promoted / managed |
74
+ | **Agent evidence / design draft / analysis** | **`.okstra/tasks/<group>/<id>/notes/`** | you (the AI) |
75
+
76
+ 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:
77
+
78
+ ```bash
79
+ okstra recap note <resolved-target> --project-root <projectRoot> \
80
+ --kind <verification-evidence|decision-draft|analysis-note> \
81
+ --slug <short-topic-slug> \
82
+ --purpose "<one line — what it is and which run/decision it feeds>" \
83
+ --scope-note "<one line — what it is NOT, e.g. not a user decision on C-00x>" \
84
+ --body-file <note-body markdown path>
85
+ ```
86
+
87
+ 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.
88
+
89
+ **self-check rules (there is no validator, so you keep them yourself):**
90
+
91
+ 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.
92
+ 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.
93
+ 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.
94
+ 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.
95
+
96
+ **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.
@@ -0,0 +1,61 @@
1
+ # okstra-inspect facet — report
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
+ ## report
6
+
7
+ Trigger phrases: "find report", "show report for", "read the okstra report", "continue from report".
8
+
9
+ ### report.1 — Resolve report path
10
+
11
+ task-key format: `<project-id>:<task-group>:<task-id>`.
12
+
13
+ **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.
14
+
15
+ Lookup methods (in priority order):
16
+
17
+ A. **`task-catalog.json` (fast):** read `.okstra/discovery/task-catalog.json`, match `taskKey` lowercase. `latestReportPath` is task-type-agnostic "most recent report".
18
+
19
+ 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).
20
+
21
+ 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`.
22
+
23
+ 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.
24
+
25
+ ### report.2 — Confirm existence
26
+
27
+ 1. Verify `latestReportPath` is non-empty AND the file exists on disk. Either signal indicates report presence (tolerant).
28
+ 2. If present, display the path and ask the user whether to read it.
29
+ 3. If absent, check `task-manifest.json` signals:
30
+ - `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>).`
31
+ - Any signal indicates completion but the file is missing → `Report file does not exist: <path>`
32
+
33
+ `workStatus` enum: `todo | in-progress | blocked | done`. `currentStatus`: `completed` / `contract-violated` etc. `"completed"` string does NOT exist in `workStatus` — do not confuse the two.
34
+
35
+ ### report.3 — Read + next-step guidance
36
+
37
+ 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:
38
+
39
+ - **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.
40
+ - **Full-read intent** ("the whole thing", "read it all", "full body"): ingest the resolved report file.
41
+
42
+ After reading, surface follow-up options:
43
+
44
+ 1. **Proceed to implementation:** based on the report's "Recommended Next Steps" section.
45
+ 2. **Additional verification:** to launch a new okstra run with the same task-key, assemble the command through the `history` facet (load `facets/history.md`) — it offers the full option set (base-ref, workers, render-only) and renders a host-correct invocation.
46
+ 3. **Check related tasks:** if the report references related task-keys, fetch their reports too.
47
+
48
+ ### report — Output template
49
+
50
+ ```markdown
51
+ ## Report for <task-key>
52
+
53
+ | Field | Value |
54
+ | ------------ | -------------------------------------------------- |
55
+ | Status | `<status>` |
56
+ | Task type | `<task-type>` |
57
+ | Run seq | `<NNN>` |
58
+ | Run date | `<runTimestamp ISO-8601>` |
59
+ | Report (rel) | `<relative-path-from-project-root>` |
60
+ | Report (abs) | `<absolute-path>` |
61
+ ```