# okstra-inspect AI Manual

## Source

- Skill source: [`skills/okstra-inspect/SKILL.md`](../../../skills/okstra-inspect/SKILL.md)
- Facet bodies: `skills/okstra-inspect/facets/<sub-command>.md` — the skill is a thin core (preflight + dispatch + shared rules); each sub-command's full procedure is a lazily loaded facet file, guarded by `tests/contract/test_okstra_inspect_facets.py`
- CLI registry: [`src/cli-registry.mjs`](../../../src/cli-registry.mjs)
- context-cost CLI: `scripts/okstra_ctl/context_cost.py`
- time-report CLI: `scripts/okstra_ctl/time_report.py`
- log-report CLI: `scripts/okstra_ctl/log_report.py`
- error-report CLI: `scripts/okstra_ctl/error_report.py`
- container is a separate skill: [`okstra-container-build.md`](okstra-container-build.md)

## Purpose

`okstra-inspect` is the single entry point for okstra read-side work. Most of it is read-only, with two exceptions.

- `status.4`: writes the user-requested `workStatus` into `task-manifest.json`.
- `errors`, `error-zip`, `recap record`: produce report/zip/log artifacts from the information read.

No sub-command writes outside this machine.

## sub-command list

| Sub-command | Role | Writes? |
|---|---|---|
| `status` | check task/phase/workflow status, change workStatus | manifest edit in `status.4` |
| `history` | list past runs, assemble rerun/resume command | read by default |
| `report` | resolve final-report path and optionally read | read |
| `time` | aggregate elapsed time per task type/worker | read |
| `logs` | inventory wrapper `.log` sidecars and suggest cleanup commands | read |
| `cost` | estimate task bundle context/read cost | read |
| `errors` | aggregate task error logs into a timestamped markdown report | generates report |
| `error-zip` | build an anonymized zip of cross-project error logs | generates zip |
| `run-audit` | check every run's artifacts against progress invariants — catches a run that ended wrong without ever logging a failure | read |
| `recap` | summarize a task's before/after runs, or a task-group's per-brief status and latest conclusions, and record Q&A | appends `recap-log.jsonl` (task `recap/`, group `.recap/`) |

## Preflight

Run once before any sub-command.

```bash
okstra preflight --runtime claude-code
```

The project check only sees the cwd of the Bash call. For a project that is not the cwd (a sibling repo, a monorepo subdir, or a project named in the request), `Okstra preflight: failed` can be a false negative rather than missing setup. Retry with `okstra preflight --runtime claude-code --cwd <that-dir>` (`--cwd` is the sanctioned way to target a project without a leading `cd`). Only when that also reports `Okstra preflight: failed` do you show `Reason` and `Recovery`, then stop. On `Okstra preflight: ready`, carry `Project root` as a literal value and pass it to the sub-command CLIs that accept it (`recap`, `context-cost`, etc.) via `--cwd`/`--project-root <projectRoot>`.

## intent routing

Classify the user request into one or more facets. If ambiguous, show the entire sub-command table and let the user pick by number/name. Do not hide a facet because of AskUserQuestion's option limit.

If several facets appear in one message, execute them sequentially. Step 0 runs only once.

## task-key resolution — shared rule

Many facets accept the following target forms.

1. full task-key: `<project-id>:<task-group>:<task-id>`
2. bare task-id
3. task root path

A bare task-id uses the shared resolver.

```bash
okstra model-io task-selection-input --project-root <projectRoot> --task-ref <task-id>
```

Handling the fixed text projection's `Match count` and repeated task lines:

- 0: say it cannot be found; do not guess.
- 1: use that `taskKey`.
- N: show the candidate `taskKey`s and `updatedAt`, and take a disambiguation.

## status

### Project overview

Run `okstra model-io status-input --project-root <projectRoot>`. Its fixed text task blocks are the projected source.

Sort: `updatedAt` desc, then `taskKey`.

Keep the table narrow.

- Task Key
- Category
- Phase
- workStatus
- Next

`nextRecommendedPhase` is an object `{phase, status, rationale}`. The Next cell is its `phase`, or `--` when that is empty. If `awaitingApproval`, or `nextRecommendedPhase.status` is anything but `ready`, add a marker to the Next cell and explain it. When `awaitingApproval` is true, the next human action is to approve the plan (`okstra-run` → `implementation`, or `--approve`); do not re-run `implementation-planning`. When the pointer is `blocked` after planning, send the user to `okstra-user-response` on the named `C-NNN` ids first.

### Specific task

For a single task's detail, run `okstra model-io status-input --project-root <projectRoot> --task-ref <task-key>` and use its named lines.

Information to show:

- work category
- current phase/state
- last completed phase
- next-phase pointer: `phase` (or `--`), its `status`, its `rationale`
- awaiting approval
- task status, latest run status
- latest report, resume command
- workStatus, note
- phase states
- safe resume checkpoint

### workStatus update

Write only when the user explicitly requests a status change.

Allowed values:

- `todo`
- `in-progress`
- `blocked`
- `done`

Procedure: update via a single `okstra set-work-status <token> <status> [--note <text>] --project-root <projectRoot> --text` call — do not edit the manifest by hand. On `Stage: ambiguous`, re-ask with the listed `Match` values; on `Stage: not-found`, answer that it cannot be found.

When `workStatus` is absent in a read display, infer it from the lifecycle state, but do not back-fill on read alone.

## history

First branch: distinguish re-run from resume.

- Re-run: create a new run from previous run parameters. A new run-seq is created.
- Resume: continue an interrupted existing run. No new run-seq is created.

Run `okstra model-io history-input --project-root <projectRoot>` for project history, or add `--task-ref <task-key>` for one task.

Re-run obtains `projectId`, `taskGroup`, `taskId`, `taskType`, `taskBriefPath`, workers, related tasks, model overrides, and executor provider through `okstra model-io rerun-input --run-manifest <runManifestPath>`. Omit `implementation`'s `--base-ref` to reuse a registration; if launch reports that a base is required, ask the user.

Resume checks `latestResumeCommandPath` or the timeline entry's `resumeCommandPath`, and if the file exists, guides/runs `bash <resume-command-path>`. If the path is empty or the file is missing, declare "no resume" and guide to history.3 (re-run).

## report

Run `okstra model-io report-input --project-root <projectRoot> --task-ref <task-key>` for the latest report. For a specific run, use the `Report` line from `okstra model-io history-input --project-root <projectRoot> --task-ref <task-key>`. Render a full reading copy on demand with `okstra render-final-report <that data.json>`.

Match read depth to the request (a final report is 300+ lines / 50K+ tokens). For summary/conclusion/pass questions ("summary", "just the key points", "conclusion", "did it pass?"), do not read the whole thing — read only the verdict in the `runs/<task-type-segment>/status/final-<task-type-segment>-<NNN>.status` (stage-isolated: `runs/<task-type-segment>/stage-<N>/status/`) sidecar plus the report's leading summary block. Ingest the whole file only for "the whole thing / read it all / full body". If a completion signal exists but the file does not, report it as a missing report; if it is not yet complete, show the current status and workStatus.

## time

The CLI does the time computation. The AI does not recompute duration by hand.

```bash
okstra time-report <task-key> --project-root <projectRoot> --text
```

Convert every `*Ms` to `HH:MM:SS` for display. `CPU sum` is the overlapping cost of lead and workers time combined, not wall-clock. Show wall-clock from `perRunWallClock` only when the user explicitly asks. For `by stage`/`per stage`/`which stage took longest`, the task-type view (the By task type table) is the default answer — do not treat it as 'not measurable'. Render the intra-run `phaseTimelines` only on an explicit request like 'Phase 1–7' / 'which phase', and when it is empty, mention it only as a footnote rather than a headline.

`unavailable[]` is not summed into totals; show it as a separate note.

## cost

For context/read cost, the CLI output is the source of truth.

```bash
okstra context-cost <task-key> --project-root <projectRoot>
```

Interpretation points:

- the token estimate is a heuristic, not a billing figure.
- if `leadPhase1.mode == "active-run-context"`, the compact lead intake is primary.
- if `analysisWorker.mode == "analysis-packet-primary"`, the worker reads the analysis-packet first and opens the full source only when needed.
- if `skillAssets` is large, it is a prompt-diet target.
- if there are many legacy timestamp artifacts, propose current-view/cold-artifact separation rather than a destructive delete.

## logs

wrapper sidecar log inventory:

```bash
okstra log-report --project-root <projectRoot> --text
```

Scans `.okstra/tasks/**/runs/*/prompts/*.log`. Does not delete. The cleanup command merely presents a dry-run and `-delete` pair as fenced bash.

Deleting an active run's log loses the live trace, so recommend checking `status` first.

## errors

Aggregate task error logs into a markdown report.

```bash
okstra error-report <task-key> --project-root <projectRoot> --text
```

Read the fixed `Report path`, total, phase, agent, and parse-skipped labels and summarize. If the report path is `-` and total errors is 0, say there are no recorded error logs. Do not hide a nonzero parse-skipped count.

## error-zip

Bundle the machine's cross-project okstra errors into an anonymized zip.

Run `okstra model-io error-zip-input`. Recommend its `Previous output path` first when present; otherwise propose `~/okstra-error-feedback-<YYYY-MM-DD>.zip`.

Run:

```bash
okstra error-zip --out <path> --text
```

Summary fields:

- `outPath`
- `errorCount`
- `runCount`
- `unreachableRuns`
- `clusterCount`
- `projectCount`

At the end, guide the user to build a brief with the error-feedback variant of `/okstra-brief-gen`, then run `error-analysis` in the okstra repo.

## recap

The default is artifact mode. It builds the before/after summary and answers questions using only `.okstra/` artifacts.

Read the fixed recap projection:

```bash
okstra model-io recap-input --project-root <projectRoot> --task-ref <task-key>
```

Use the emitted `Run count` and repeated `Transition` fields in order. Do not parse recap JSON or open recap state files directly.

Group scope — when the user names a task-group, or the bare token resolves only via `taskGroup`:

```bash
okstra model-io recap-input --project-root <projectRoot> --task-group <task-group>
```

The projection joins the group's briefs (start order, `waits for` edges), the catalog / task-manifests (real status, progress, run count, next phase, report), and the group document's Task Memory (headline, decisions, watch-outs, follow-ups). Read `Brief count` / `Task count` / `Next in group`, then the repeated `Queue entry` and `Task` blocks. Run-count / time / error totals belong to `okstra-rollup`.

record:

```bash
okstra recap record <task-key> --project-root <projectRoot> --kind <summary|qa> --mode <artifact|code> --question "<question>" --answer "<summary>" --citation "<path:line>"
```

In group scope, `--task-group <task-group>` replaces `<task-key>` and the line lands at `.okstra/tasks/<task-group>/.recap/recap-log.jsonl`. `recap note` has no group form.

Enter code mode only when the user explicitly requests it, such as "including the diff" or "the code changes too". Entering recap alone does not read the code diff.

## Output rules

- Answer in Korean, spelling out task ids, phase names, and status values on first mention.
- Prefer project-relative paths.
- Show disk field values as-is without normalizing.
- Clearly indicate an awaiting-approval state.
- If there is no recent report, show `--`.
- Display dates in `YYYY-MM-DD HH:MM`.

## Forbidden patterns

- Failing immediately because the catalog is absent. There is a manifest fallback.
- Confusing `workStatus` with `currentStatus`.
- Hand-computing time duration without the CLI.
- Running a cleanup command directly.
- Arbitrarily reinterpreting raw files instead of CLI output in `errors`/`cost`/`time`.
- Automatically reading code changes in recap artifact mode.
