---
name: okstra-inspect
description: >-
  Inspect okstra tasks and record user-managed status, including direct completion of brief-backed tasks that have never run. The tell is usually a named task id (PROD-1623, dev-9184) without the word "okstra." Reach for it when the user wants one task's: status, current/next phase, blockers, or approval gate; its final report — where it is or whether it passed; its elapsed time or context/read cost; its run history, re-run, or resume; to mark it done / in-progress / blocked / todo; or a failed run's error logs gathered into a report. The recap facet also takes a task-group: which briefs are done / in progress / not started, what is next, each task's latest conclusion. Also builds an anonymized cross-project error zip and audits run health. NOT for starting a run (okstra-run), a group's run/time/error totals (okstra-rollup), schedules (okstra-schedule-gen), a brief (okstra-brief-gen), setup (okstra-setup), or cross-project management (okstra-manager).
---

# OKSTRA Inspect

Also handles tasks that have never run: a status mutation can register an existing brief,
and direct completion records are available to status, recap, group context, and later runs.
For an explicit status change, dispatch to status.4 before catalog-only task selection.
An unregistered brief will not appear in that selection yet.

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.

| Sub-command | Facet file | What it does |
|---|---|---|
| `status` | `facets/status.md` | Task / phase status, blockers, approval state. Also writes `workStatus` on user request. |
| `history` | `facets/history.md` | List past okstra runs; assemble re-run or resume command. |
| `report` | `facets/report.md` | Resolve final-report path for a task-key. Optionally read it. |
| `time` | `facets/time.md` | Per-task-type and per-worker duration breakdown for a task. |
| `logs` | `facets/logs.md` | Inventory codex/antigravity wrapper `.log` sidecars; emit cleanup commands. |
| `cost` | `facets/cost.md` | Estimate file/read context cost for a task bundle. |
| `errors` | `facets/errors.md` | Aggregate okstra-run error logs for a task into a timestamped markdown report; print a summary. |
| `error-zip` | `facets/error-zip.md` | Collect cross-project okstra error logs into an anonymized zip (report + raw) and summarize clusters. |
| `run-audit` | `facets/run-audit.md` | Check every run's artifacts against progress invariants; report what went wrong without an error ever being logged. |
| `recap` | `facets/recap.md` | Summarize a task's run-to-run phase transitions — or a task-group's start order, per-brief status, and each task's latest conclusion — then answer free-form questions over the `.okstra` artifacts. Appends each summary/Q&A to `recap-log.jsonl` (task `recap/`, group `.recap/`), and writes agent-authored notes to `notes/` for feeding into later runs. |

## Step 0: Preflight (shared)

Resolve `<host-runtime>` from the launcher's `OKSTRA_RUNTIME_HOST` when present; otherwise use the registered host ID declared by the current harness (`codex` in Codex, `claude-code` in Claude Code). This follows `okstra-run`'s host selection rule. Do not infer the host from worker models, installed executables, or `PATH`. If neither source identifies the host, report that it is unknown instead of substituting Claude Code. Keep the same resolved host when retrying against another project directory.

<!-- BEGIN FRAGMENT: bash-invocation-rule -->
Run one Bash tool call, starting with the literal token `okstra` (never wrapped in `if`/`eval`/`export`/`$(...)`/`VAR=...`/`||`/`&&`/`npx` — a non-literal leading token defeats the `Bash(okstra:*)` permission match):
<!-- END FRAGMENT: bash-invocation-rule -->

```bash
okstra preflight --runtime <host-runtime>
```

The project check only sees the cwd of the Bash call. When the user is asking about a project that is **not** the cwd (a sibling repo, a monorepo subdir, or a project named explicitly in the request), the bare form can report `Okstra preflight: failed` — a false negative, not a missing setup; do not hard-stop on it.

Branch on the fixed first line:
- `Okstra preflight: ready` → carry `Project root` as a literal string; it is the base for every sub-command step below.
- `Okstra preflight: failed` → before concluding "no setup", ask whether the user pointed at a specific project directory. If they did, re-run targeting it: `okstra preflight --runtime <host-runtime> --cwd <that-dir>` (`--cwd` is the sanctioned way to target a project — a leading `cd` would break the permission match). Only if this also fails do you show `Reason` and `Recovery`, then stop.

<!-- BEGIN FRAGMENT: preflight-outdated-cli -->
If the call fails with `unknown command: preflight`, the `okstra` binary on PATH predates this skill — tell the user to update it (`npm i -g okstra@latest`), then stop (`/okstra-setup` does not update the binary).
<!-- END FRAGMENT: preflight-outdated-cli -->

Carry the resolved `projectRoot` into the sub-commands: read file artifacts under `<projectRoot>/.okstra/...`, and for sub-command CLIs that accept it (e.g. `recap`, `context-cost`) pass `--cwd <projectRoot>` / `--project-root <projectRoot>` so they target the same project rather than the Bash cwd.

<!-- BEGIN FRAGMENT: python-bootstrap-note -->
Every subsequent `okstra <subcmd>` call self-bootstraps its Python path, so this skill never needs `okstra paths --shell` / `export PYTHONPATH=...`.
<!-- END FRAGMENT: python-bootstrap-note -->

## Step 1: Dispatch by intent

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.

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.

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.

## Shared rules (referenced by facets)

### Standard task-key resolution (0/1/N)

Facets that accept a bare token (a task-id like `DEV-9184` **or** a task-group like `PROD`) resolve it through the fixed text projection:

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

Branch on `Match count` in the projection and use only its repeated `Task`,
`Updated at`, and `Matched via` lines:
- **0** → report the task cannot be found. Do not guess.
- **1** → use that entry's `taskKey`.
- **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`.

### No-task fallback

When a facet needs a task but the user did not name one:

1. Run `okstra model-io task-selection-input --project-root <projectRoot>`.
2. Branch on `Match count`; if exactly one task exists, use it.
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.

## Output Rules (shared)

- Write responses in Korean unless the user requests otherwise. Spell out task ids, phase names, and
  status values the first time each appears — the reader has not seen the report you are summarizing.
- Use project-relative paths whenever possible.
- If there is no recent report, display `--`.
- If a specific task does not exist, explicitly state that the task resolver returned no match.
- If `awaitingApproval` is true, clearly indicate that the task is awaiting user approval.
- Display status fields as-is from disk (`completed`, `contract-violated`, `todo`, `error`, empty, ...). Do not normalize or remap.
- Dates in `YYYY-MM-DD HH:MM` format.
