Files
poimen/tasks/T10.9-cli-transcript-and-metrics-ux.md

3.5 KiB

T10.9 — CLI: runs list/episode/transcript

Field Value
Phase P10 — Orchestration
Size S — under 1 day
Status Not started
Flags
Spec inlined below
Blocks

Goal

Three thin CLI wrappers over the HTTP API — poimen runs list --goal <id>, poimen runs episode <run_id>, poimen runs transcript <run_id> <step> <attempt> — the whole troubleshooting UX, no dashboard.

Facts (inlined — no spec read needed)

  • Thin HTTP clients, not a second implementation of the query logic already in T10.1/T1.7/T1.6 — the CLI calls the same routes T10.4 exposes.
  • Rides the eventual shared poimen binary (T9.3); workable as a standalone binary if T9.3 hasn't landed yet — soft dependency, not a hard block.
  • episode output must include failed attempts by default — T1.7's own rule. A CLI that hides them defeats the purpose of the command.
  • transcript dereferences the BlobRef server-side, via the HTTP route (T10.4) — the CLI never talks to BlobStore directly.

Steps

  1. poimen runs list [--goal <id>] [--status <state>]GET /v1/runs, table output (run_id, status, goal_id, age).
  2. poimen runs episode <run_id>GET /v1/runs/{id}/episode, human-readable rendering of EpisodeView including failed attempts, clearly marked.
  3. poimen runs transcript <run_id> <step> <attempt>GET .../transcript, prints prompt/output text, dereferenced server-side.
  4. Exit codes: non-zero on API error, distinct code for "run not found" vs "transport error" — operator scripting depends on this distinction.
  5. Test against a live embedded API instance (T10.4's test harness) with a run that has a retry and a rewind.

Acceptance

  • episode on a run with two failed attempts and one success shows all three, visually distinguishable.
  • transcript returns the same text content as reading the BlobRef directly through BlobStore in a test assertion.

Verify

Harness: T10.4's axum test instance, one run with a retry (two attempts, one failed) and a rewind.

Integration testtests/it_cli_runs_ux.rs:

  1. runs list --goal G; assert output contains exactly the runs tagged G, none untagged.
  2. runs episode <id>; assert both the failed and successful attempt appear — count them explicitly, not just non-empty output.
  3. runs transcript <id> <step> 1 (the failed attempt) and ... 2 (the retry); assert distinct content for each, matching their respective BlobRefs byte-for-byte.
  4. Run-not-found case; assert a distinct exit code from a transport-down case.

Command: cargo test -p cli runs_ux

False pass:

  • Step 2 checking only that output is non-empty — a CLI silently filtering to the winning attempt (T1.7's own named trap) passes a non-empty check while hiding exactly the debugging signal requested.

Traps

  • Filtering episode output to "just the successful attempt for clarity" — T1.7's trap restated at the CLI layer; the failed attempts are the reason this command exists.
  • Fetching transcripts client-side by resolving BlobRef directly instead of through the HTTP route. Bypasses the tenant auth checks the API enforces.

Background (not required to do this task): T10.4-http-api-surface.md · T1.7-episode-query-surface.md · T1.6-prompt-and-output-blob-capture.md · T8.2-metrics.md