README
¶
CLI comparison recordings
record.sh runs real before/after binaries against the fixed synthetic API in
main.go. Commands run as openai on a PTY with a fake key and an isolated
environment. No live OpenAI requests or uploads are made.
capture_and_render.sh shares temporary setup, fixture lifecycle, PTY capture,
rendering and media assembly across this recorder, image models and streaming
text. Each recorder keeps its own scenes, rendering settings and assertions.
Failures stop the recording; exit and interruption clean up its fixture and
temporary state. Each run requires an empty output directory outside the
repository so it cannot overwrite previous evidence.
The tested replay tools are asciinema 3.2.1, agg 1.9.0 and ffmpeg 4.4.8. Install
these tools independently and put asciinema, agg, ffmpeg and ffprobe on
PATH. This is a terminal replay, not a native Apple Terminal, PowerShell or
cmd.exe capture. The retained .tape recipe is for VHS; it does not produce the
asciinema/agg media generated by this runner.
Reproduce
Run from the repository root. Build the fixture into the ignored output folder:
mkdir -p dist/demos/bin
go build -o dist/demos/bin/demo-api ./scripts/demos/main.go
Independently build a before CLI from the comparison base and an after CLI from the proposed commit. Verify that each binary comes from its supplied commit; the recorder logs commit IDs and file hashes but cannot establish provenance. Then run:
bash scripts/demos/record.sh readable-output \
/path/to/before/openai /path/to/after/openai \
"$BEFORE_SHA" "$AFTER_SHA" /path/to/evidence/readable-output
Both SHA arguments must be full 40-character commit IDs. Readable output uses main as its comparison base. For helpful errors, use the readable-output parent as the before commit and run:
bash scripts/demos/record.sh helpful-errors \
/path/to/before/openai /path/to/after/openai \
"$BEFORE_SHA" "$AFTER_SHA" /path/to/evidence/helpful-errors
Use DEMO_API_BINARY to select another prebuilt fixture.
The runner checks actual exit status and expected fixture text for each scene. Readable scenes expect exit 0; helpful-error scenes expect exit 1. The local fixture and temporary state are cleaned up on exit. The fixture binds only to loopback and serves fixed model data, file records and error responses.
List/get results
The list-get-results scenario compares the same two file records on the pager parent and
the feature branch. Both commands use openai files list --max-items 2. The
records have distinct IDs, filenames and sizes, with seven fields each so the
complete before output fits in the 90-column by 24-row capture. The after scene
retains ID, filename, purpose, bytes and status, followed by
one Summary; use --format json for full data. notice after the list.
Two more scenes retrieve the first file before and after the change. The last
scene uses openai --format json files retrieve file_training, demonstrating
that the original object and created_at fields are still available. All five
scenes use the same fixture server and expect exit 0. The recorder checks both
file IDs in the list scenes, exactly one summary hint in each after scene, and the
creation timestamp in the before and explicit JSON scenes.
Build the fixture as above, then capture the final feature binary using its
actual full commit ID. For the September 2026 feature extraction, the pinned
before commit is the pager cleanup parent ef4fd8b6baf818781ff5c5705f7e048e0efbe322.
Build its binary independently, then supply both verified binary paths:
PATH="/Users/vguvvala/.cache/cli-terminal-replay/bin:$PATH" \
bash scripts/demos/record.sh list-get-results \
"$BEFORE_BINARY" "$AFTER_BINARY" \
ef4fd8b6baf818781ff5c5705f7e048e0efbe322 \
"$AFTER_SHA" \
/absolute/path/to/list-get/media
Keep the media outside Git. Inspect before.png, after.png,
before-retrieve.png, after-retrieve.png, explicit-json.png and frames from
comparison.gif before using them for review. The fixture and recipe are
synthetic; the screenshots and GIF must come from actual binary execution.
list-get-results.tape preserves the same commands for a separate VHS capture.
Evidence and limits
The scenes show before, after and explicit JSON output. Each uses bash, 90 columns by 24 rows, Menlo at 22 px, Dracula colors and a 3.5-second final pause. If Menlo is unavailable, supply it locally before recording so styling matches. Terminal color detection can add a delay; recorded output and timing are not rewritten.
Each original scene is rendered separately with agg, then ffmpeg joins the full GIF frames while retaining the recorded timing and final pauses (within GIF timing precision). This avoids partial glyphs that agg 1.9.0 can retain across screen clears in a merged recording. The combined cast is preserved alongside the individual captures for provenance.
The output folder contains comparison.gif, before.png, after.png,
explicit-json.png, individual scene GIFs and their comparison-scenes.txt
list, individual and combined .cast files, text transcripts, and the retained
VHS tape. metadata.txt and media.json record commits,
hashes, actual exit codes, OS, shell, tool versions, dimensions and duration.
Inspect the GIF and screenshots for readable text, clipping, timing, correct
behavior and sensitive data before sharing. Keep recorded media outside the
repository; executables may use ignored dist/. Regenerate evidence after changes
that affect the demonstrated behavior. Retain only the runner, fixture and
recipes in Git.
For a separate VHS capture, provide DEMO_BEFORE_DIR and DEMO_AFTER_DIR
containing the matching binaries named openai, plus OPENAI_BASE_URL pointing
to this local fixture and a synthetic OPENAI_API_KEY. Run the tape from an
ignored output directory with vhs and validate it first with vhs validate.
Do not label asciinema/agg output as a VHS or native-terminal capture.
Official documentation: asciinema recording, configuration, agg rendering, VHS, and ffmpeg.
Help pages
record-help.sh compares the same help command on two real binaries. Build the
existing request-counting fixture, then pass the comparison commits and command
path:
go build -o dist/demos/bin/image-model-demo-api ./scripts/demos/image-models/main.go
bash scripts/demos/record-help.sh \
/path/to/before/openai /path/to/after/openai \
BEFORE_COMMIT AFTER_COMMIT /path/outside/repository/help-demo images edit
This records openai images edit --help. Omit the command path for root help;
put --all before the path to record openai help --all images edit. Use each
PR's immediate parent as the before build. Both commit arguments must be full
40-character IDs; independently verify that the binaries match them.
The runner reuses capture_and_render.sh, removes the API key inside both
scenes, and points the CLI at a rejecting loopback fixture. Any API request
fails the recording. It forwards command names only, never request options.
DEMO_API_BINARY can select a separately built fixture. Put asciinema, agg,
ffmpeg and ffprobe on PATH. No live requests or paid generation are needed.
Both scenes use 90 columns, 48 rows and Menlo at 18 px. Set DEMO_ROWS higher
for longer pages, and inspect both screenshots for clipped content before
sharing. comparison.gif, before.png and after.png are replay media, not
native terminal validation. The output also preserves transcripts, captures,
the exact scene, tool versions, hashes, commit IDs and the empty request log.
Keep this output outside Git; rerun after changing the demonstrated help.
Command navigation
record-command-navigation.sh compares command discovery in a 105-column, 45-row PTY.
The root mode records the first 38 lines of full help and labels both scenes as excerpts.
The projects mode records complete help for openai admin organization projects.
Build the existing fixture:
go build -o dist/demos/bin/image-model-demo-api ./scripts/demos/image-models
Record the root comparison against a pinned main binary:
bash scripts/demos/record-command-navigation.sh root \
/path/to/main/openai /path/to/candidate/openai \
MAIN_COMMIT CANDIDATE_COMMIT /path/outside/repository/root-demo
Record the project comparison against a verified main binary with truncated group help:
bash scripts/demos/record-command-navigation.sh projects \
/path/to/main/openai /path/to/candidate/openai \
MAIN_COMMIT CANDIDATE_COMMIT /path/outside/repository/projects-demo
Supply full commit IDs and an empty output directory for each mode.
Use a clean candidate build for PR evidence and verify both binaries against their supplied commit IDs.
Check each binary's build information; record archive provenance when its build information lacks a commit ID.
For local development, set DEMO_SOURCE_MANIFEST when the candidate contains uncommitted changes.
The recorder copies this manifest, captures available Go build information, and hashes both binaries.
The recorder checks exit status, expected help text, and an empty loopback request log.
It removes the API key before running each command.
Inspect both PNG files and comparison.gif before sharing.
These files show actual PTY execution through asciinema/agg replay, not graphical terminal validation.
Grouped actions and root shortcuts
record-command-shortcuts.sh compares audio actions, root discovery, and root shortcut help.
Build the existing image-model-demo-api fixture, then run:
bash scripts/demos/record-command-shortcuts.sh audio \
/path/to/before/openai /path/to/candidate/openai \
BEFORE_COMMIT CANDIDATE_COMMIT /path/outside/repository/audio-demo
Use root for a labeled 32-line root help excerpt containing shortcuts and grouped commands.
Use transcribe for openai transcribe --help; this expects status 3 before and status 0 after.
Each mode requires a separate empty output directory and verified full commit IDs.
Use DEMO_API_BINARY for a separately built fixture and DEMO_SOURCE_MANIFEST for uncommitted development sources.
The recorder uses isolated Bash PTYs, no API key, and a rejecting loopback fixture. It checks real exit statuses and requires zero API requests. The 105-column replay uses 28 rows, or 40 rows for root help, with Menlo at 18 pixels. Inspect PNGs and individual GIF frames before sharing; exclude any combined GIF with rendering artifacts. Build information, hashes, transcripts, and raw captures remain beside the media. This records actual local CLI execution, not native graphical terminal appearance or API behavior.
Installed command paths
record-command-paths.sh compares the no-argument welcome page using the same
absolute invocation and PATH entry. Only the installed symlink's target changes
between the verified before and after binaries:
bash scripts/demos/record-command-paths.sh \
/path/to/before/openai /path/to/after/openai \
BEFORE_COMMIT AFTER_COMMIT /path/outside/repository/command-paths-demo
Supply full 40-character commit IDs and an empty output directory. The shared
capture helper records real exit statuses and rejects failed commands. The
runner checks that welcome examples change from a full path to openai.
It starts no API fixture and uses no credentials. Inspect the 130x24 terminal
replay, screenshots and metadata before publishing; keep media outside Git.
Image loading feedback
record-image-loading.sh compares the same generation request with an identical
synthetic PNG returned after two seconds. Both commands use --inline off so the
recording isolates waiting feedback and final saved-path output.
go build -o dist/demos/bin/demo-api ./scripts/demos
bash scripts/demos/record-image-loading.sh \
/path/to/before/openai /path/to/after/openai \
BEFORE_COMMIT AFTER_COMMIT /path/outside/repository/loading-demo
Use the immediate parent as the before build and verify both commit IDs. The
recorder reuses capture_and_render.sh, a fake key and isolated temporary homes.
Its loopback fixture accepts only the existing fixed synthetic request. The
optional DEMO_IMAGE_DELAY fixture setting accepts 0–5 seconds and stops waiting
when the client cancels; this recording sets it to two seconds.
comparison.gif preserves the real wait and completed output. before.png and
after.png show actual pending frames selected one second before each recorded
saved-path event; selection times are retained. before-complete.png and
after-complete.png show cleanup and the final prompt. The recorder verifies
identical requests and saved bytes, feedback only after the change, line cleanup
and no feedback after the saved path. It never hides the cursor. Exit statuses
are checked and retained in metadata.txt, without a status label in the replay.
Inspect all four PNGs and the GIF before sharing. The 90 × 20 replay uses bash, Menlo 18px, asciinema and agg; it does not validate native image appearance or Windows terminal behavior. Media, casts, transcripts, fixture logs and exact saved bytes remain outside Git. No live generation or uploads occur.
Image defaults and saving
Build the comparison binaries from main and the proposed feature commit in separate checkouts, then build the synthetic fixture:
go build -o dist/demos/bin/demo-api ./scripts/demos/main.go
PATH="$HOME/.cache/cli-terminal-replay/bin:$PATH" \
bash scripts/demos/record-image-saving.sh \
/path/to/before/openai /path/to/after/openai \
BEFORE_COMMIT AFTER_COMMIT /path/outside/repository/image-saving-demo
The runner reuses capture_and_render.sh for setup, fixture lifecycle, capture
and rendering. Image scenes and assertions remain in record-image-saving.sh.
Use an empty output directory outside the repository; fixture shutdown must
succeed before output validation and media assembly.
It uses asciinema 3.2.1 and agg 1.9.0, real binaries in a PTY, isolated
synthetic home directories, and a loopback API. It records the same prompt
before and after, then explicit JSON. It verifies request defaults, unchanged
saved PNG bytes, complete paths and the absence of files in API-output mode.
Inspect the screenshots and GIF before sharing them. This is a terminal-text
replay, not native image-renderer validation. image-saving.tape is the reusable
VHS alternative; it was not used for the macOS replay.
Image-saving recovery
record-image-saving-recovery.sh reuses the same image fixture and capture
helper. It compares --stream=true --max-items -1 before and after the fix,
then a two-image response with an invalid second image and closed stdout
(| true). The recovery scenes preserve one saved file and exit 1; only the
after scene explains that saved paths could not be printed.
Build demo-api as above, then run:
bash scripts/demos/record-image-saving-recovery.sh \
/path/to/before/openai /path/to/after/openai \
BEFORE_COMMIT AFTER_COMMIT /path/outside/repository/image-saving-recovery
The runner checks real exit codes, exact request bodies, saved PNG bytes and
recovery text. Inspect comparison.gif, before.png, after.png,
before-recovery.png and after-recovery.png. The local fixture only accepts
fixed synthetic inputs. image-saving-recovery.tape is the VHS alternative.
Image edits and variations
record-image-edit-saving.sh compares edits and variations, then explicit JSON.
It reuses main.go and capture_and_render.sh. Build the fixture as above and
pass independently built comparison binaries:
bash scripts/demos/record-image-edit-saving.sh \
/path/to/before/openai /path/to/after/openai \
BEFORE_COMMIT AFTER_COMMIT /path/outside/repository/image-edit-saving
The fixture validates fixed multipart settings and exact source/mask bytes.
Edit responses are identical; variation responds with a synthetic URL before,
and base64 after the saving path requests b64_json. No URL is downloaded.
The recorder checks saved filenames, full printed paths, original image bytes
and explicit JSON bypass. It retains source files, saved PNGs, request hashes,
transcripts and the alternative image-edit-saving.tape VHS recipe.
Inspect all five screenshots and comparison.gif before sharing.
Directories
¶
| Path | Synopsis |
|---|---|
|
global-flags-demo-api reflects a synthetic request's project header in model data.
|
global-flags-demo-api reflects a synthetic request's project header in model data. |
|
image-model-demo-api serves synthetic metadata only.
|
image-model-demo-api serves synthetic metadata only. |
|
audio-demo-api serves a fixed, delayed synthetic transcription event stream.
|
audio-demo-api serves a fixed, delayed synthetic transcription event stream. |
|
streaming-demo-api serves a fixed, delayed synthetic Responses event stream.
|
streaming-demo-api serves a fixed, delayed synthetic Responses event stream. |