Skip to content

docs: automate CLI demo recordings with virtui + embed across the docs#11

Open
Tombar wants to merge 4 commits into
mainfrom
claude/adoring-fermat-0v4lrn
Open

docs: automate CLI demo recordings with virtui + embed across the docs#11
Tombar wants to merge 4 commits into
mainfrom
claude/adoring-fermat-0v4lrn

Conversation

@Tombar

@Tombar Tombar commented Jun 24, 2026

Copy link
Copy Markdown
Member

Summary

Adds the recording half of the documentation flow — a sibling to the doc-validation harness in #2. That harness proves the copy-paste snippets in docs/ run against the real binary; this drives the same commands under virtui ("Playwright for the terminal"), records each session to asciicast v2, renders to embeddable SVG, and wires them into the docs — so prose, tests, and demos can't drift.

This is the "wire it up for real" follow-through on the earlier prototype: virtui v0.2.0 was installed and the pipeline run end-to-end, so the committed SVGs are recordings of the shipped binary, not mockups.

What's here

The recorder — scripts/record-docs.sh

  • Builds failsafe into a throwaway bindir, sandboxes $HOME (failsafe reads all state from $HOME) so demos never touch your real ~/.config/failsafe — same isolation trick as the harness's helpers.bash.
  • Starts the virtui daemon, spawns a recorded bash per scenario, types the documented command and --waits for expected screen text (deterministic, no fixed sleeps).
  • Parses virtui's session_id: from run output (no jq dependency), kills the session to flush each cast.
  • Fixed sandbox path so the explain cwd is readable and committed SVGs diff only when behaviour changes.
  • Skips cleanly (exit 0) when virtui is absent — never fails a build. Optional --render turns .cast.svg (svg-term) or .gif (agg).

The recordings — docs/assets/casts/

Cast Command Embedded in
explain-block failsafe explain "kubectl … delete ns payments" README hero, getting-started step 3, how-to/explain-a-command
mode-toggle failsafe mode get / set rw / set ro getting-started step 4, reference/modes
audit failsafe audit how-to/repo-policy

CI — .github/workflows/record-docs.yml: workflow_dispatch-only (same posture as docs.yml). Early-stage virtui is deliberately not wired into the required ci gate — a flaky upstream can never block main.

Docs — docs/demos/README.md: documents the flow and the honest split below.

What's NOT automated (honest split)

virtui is headless/VT100, so it records the CLI surface only. The GUI-only surfaces — WezTerm toasts & format-tab-title, iTerm2's Python-runtime keybinding — are not recordable here and remain manual, exactly the STATIC / LIVE-MANUAL surfaces #2 calls out in test/docs/REPORT.md. This automates the CLI documentation flow, not the full flow.

Test plan

  • scripts/record-docs.sh --render — produces 3 casts + 3 SVGs against the real binary (virtui v0.2.0)
  • All --wait strings verified against real binary output (Decision: BLOCK, read & write, block rule(s))
  • Skips cleanly (exit 0) with virtui absent; bash -n clean
  • All three SVGs well-formed XML and contain expected on-screen text
  • mkdocs build --strict green; every embedded image path resolves in the built site
  • go test ./... unaffected, all green

Depends on nothing in #2, but is designed to pair with it. Recommend landing both — together they give: snippets that work (#2) + demos that show them working (this).

🤖 Generated with Claude Code


Generated by Claude Code

claude added 4 commits June 24, 2026 22:11
Adds the recording half of the docs automation flow, a sibling to the
doc-validation harness (test/docs/): that harness proves the doc snippets
run against the real binary; this drives the same commands under virtui
("Playwright for the terminal") and records each session to asciicast v2,
so prose, tests, and demos can't drift.

- scripts/record-docs.sh: builds failsafe into a throwaway bindir, sandboxes
  $HOME so demos never touch ~/.config/failsafe, starts the virtui daemon,
  and records three headless CLI scenarios (explain-block, mode-toggle,
  audit) by typing the documented command and --waiting for expected screen
  text (no fixed sleeps). Verified the wait strings match real output.
  Skips cleanly (exit 0) when virtui is absent — never fails a build.
  Optional --render turns .cast into embeddable .svg/.gif.
- docs/demos/README.md: documents the flow and the honest CLI-vs-GUI split
  (WezTerm/iTerm2 GUI surfaces stay manual, same as test/docs/REPORT.md).
- .github/workflows/record-docs.yml: workflow_dispatch-only, mirroring
  docs.yml — early-stage virtui is never wired into the required ci gate.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
Claude-Session: https://claude.ai/code/session_0147YNPKgm4m7DqA92DtqJqP
Runs the prototype end-to-end with virtui v0.2.0 installed and wires the
output into the documentation:

- docs/assets/casts/{explain-block,mode-toggle,audit}.{cast,svg}: real
  recordings of the shipped binary, rendered to embeddable SVG with
  svg-term. The recorder now parses virtui's `session_id:` from `run`
  output (no jq dependency), kills the session to flush each cast, and
  uses a fixed sandbox HOME so the printed cwd is readable and the
  committed SVGs diff only when behaviour changes.
- Embedded the SVGs in: README hero, getting-started steps 3 & 4,
  how-to/explain-a-command, reference/modes, how-to/repo-policy.
- .gitignore now keeps .cast (source) and .svg (embedded) committed,
  ignoring only heavy .gif renders.

Verified: `mkdocs build --strict` is green and every embedded image path
resolves in the built site; all three SVGs are well-formed and contain
the expected on-screen text (BLOCK / read & write / block rules).

Co-Authored-By: Claude Opus 4.8 <[email protected]>
Claude-Session: https://claude.ai/code/session_0147YNPKgm4m7DqA92DtqJqP
The recordings played as a blur. Add a configurable STEP_PAUSE (default 2s)
held before each command and on the final frame. virtui records in real
wall-clock time, so a host-side idle gap becomes a visible pause in the
cast; svg-term preserves the full timeline (mode-toggle now animates over
10.6s instead of <1s). Set STEP_PAUSE=0 for a fast smoke-test recording.

Regenerated all three casts + SVGs at the new pace.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
Claude-Session: https://claude.ai/code/session_0147YNPKgm4m7DqA92DtqJqP
Move the STEP_PAUSE linger to after each command's output instead of
before the next one — playback now rests on each result (the BLOCK
verdict, the flipped mode) before moving on, with no dead air on an empty
prompt first. Timing is baked into the cast, so this is a re-record, not
a re-render. Regenerated all three casts + SVGs.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
Claude-Session: https://claude.ai/code/session_0147YNPKgm4m7DqA92DtqJqP
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants