Capture
The orchestrator routed you here. This atom owns the full recording lifecycle: launch a target, execute an interaction script, collect raw outputs.
You should already have a driver atom loaded (terminal-use, true-input, browser-use, or desktop-use) and optionally a target atom (droid-cli). This atom layers the recording discipline on top.
Inputs
The command that invoked you should have provided:
- Target: what to launch and on which branch(es)
- Interaction script: the sequence of actions to perform
- What to capture: recordings (.cast/.mp4), screenshots, text snapshots, byte sequences
- Keystroke logging: whether to emit a keystroke TSV for later overlay
Recording lifecycle
For desktop-use, follow its recording contract; do not translate the terminal commands below into desktop commands. Routine desktop snapshots stay in the driver's observe/act/verify loop.
1. Pre-flight
Before recording anything:
- Terminal size is consistent across all sessions (
--cols 120 --rows 36) - Browser viewport size matches the composition layout (see "Browser viewport sizing" below) — mismatched aspects letterbox in the final video
- Branch/worktree paths and env vars are correct
- Recording format matches the driver:
.castfor tuistory,.mp4for true-input, screenshots for agent-browser, window PNGs /recording.mp4for cua-driver - If comparing branches, both sessions use identical terminal / viewport dimensions and launch parameters
- For
droid-devcaptures,--repo-rootis mandatory —tctlwill refuse to launch without it - Color env vars are set (see below)
Browser viewport sizing
Panel aspect ratio in the final composition is layout-dependent. At the default 1920×1080 output with factory preset margins, the window-chrome panels that clips render into come out roughly:
| Layout | Panel aspect | Recommended browser viewport |
|---|---|---|
single | ~1760×920 (≈16:9 landscape) | 1280×720 or 1440×810 |
side-by-side | ~872×920 per panel (≈8:9, near-square / slight portrait) | 960×1000, 900×1000, or 1024×1080 |
Feeding a 16:9 landscape recording into a near-square side-by-side panel triggers objectFit: "contain" letterboxing — you get a thin strip of content with giant black bars above and below. Two ways to avoid it:
- Match aspects at capture time (preferred) — pick the viewport from the table above based on the committed layout.
- Opt into cropping at compose time — pass
"objectFit": "cover"in showcase props. Crops the edges of the clip instead of letterboxing. Use when the relevant UI is centered and the clip's edges are expendable.
If you're unsure of the layout when capturing, default to 960×1000 — it is workable in both layouts (slight horizontal letterbox in single, no letterbox in side-by-side).
bashTCTL=${DROID_PLUGIN_ROOT}/bin/tctl # RUN_ID and RUN_DIR should already be set by the parent (see droid-control ground rule 5)
2. Launch and record
CRITICAL: tuistory's virtual PTY does not advertise color support by default. Node.js apps (Ink/chalk) detect this and suppress ALL color escape codes, producing a monochrome recording. You must pass FORCE_COLOR=3 and COLORTERM=truecolor to force full 24-bit color output. Without these, agg has nothing to theme and the video will look grey/desaturated regardless of the agg theme chosen.
Single branch:
bash$TCTL launch "droid-dev" -s ${RUN_ID}-demo --backend tuistory \ --repo-root /path/to/worktree \ --cols 120 --rows 36 --record ${RUN_DIR}/demo.cast \ --env FORCE_COLOR=3 --env COLORTERM=truecolor
Comparison (before/after):
bash$TCTL launch "droid-dev" -s ${RUN_ID}-before --backend tuistory \ --repo-root /path/to/baseline-worktree \ --cols 120 --rows 36 --record ${RUN_DIR}/before.cast \ --env FORCE_COLOR=3 --env COLORTERM=truecolor $TCTL launch "droid-dev" -s ${RUN_ID}-after --backend tuistory \ --repo-root /path/to/candidate-worktree \ --cols 120 --rows 36 --record ${RUN_DIR}/after.cast \ --env FORCE_COLOR=3 --env COLORTERM=truecolor
Browser: size the viewport to match the composition layout (see table above).
bash# side-by-side layout → near-square panel agent-browser open <url> --viewport 960x1000 agent-browser record start ${RUN_DIR}/demo.webm # single layout → 16:9 panel agent-browser open <url> --viewport 1280x720 agent-browser record start ${RUN_DIR}/demo.webm
3. Execute the interaction script
Film for a viewer with no context. You are a director, not an operator.
- Record before setup -- the baseline state is act 1.
- Hold after state changes -- 2-3 seconds so text is readable. Use
snapshot --trimas natural verification beats. - Verify between steps --
waitorsnapshotto confirm state before proceeding. Don't blindly fire the next key. - Verification IS evidence. Capture the actual state after actions, including when no change is visible. One unchanged frame alone does not prove a frozen session or a dropped key; check the task's postcondition and timing.
For comparison recordings, both branches run identical interactions -- only the behavior differs. End both at the same script step: compose plays the longest clip in full and holds a shorter clip's final frame until it ends.
4. Keystroke logging
If the workflow requires keystroke overlay, emit a TSV file during recording. Since every interaction is scripted, the timing data is already known.
Write each keystroke's timestamp (seconds from recording start) and a human-readable label:
0.5 droid --fork 1.2 Enter 2.8 Ctrl+C 4.0 Esc
Use readable key names (Ctrl+C, not \x03). Save alongside the recording (e.g., ${RUN_DIR}/keys.tsv). Timestamps stay in raw recording seconds; compose converts them to output seconds when it sets speed, and any trim applied to the clip afterwards shifts them — trim before logging or note the offset in the handoff.
5. Close and verify raw outputs
bash$TCTL -s "${RUN_ID}-demo" close # terminal session owned by this run
Before handing off, confirm every expected output file exists and is non-empty:
- Recording files (.cast, .mp4, .webm)
- Screenshot files (.png)
- Keystroke TSV (if committed)
- Text snapshot logs (if needed for the report)
Evidence capture patterns
| Proof type | How to capture |
|---|---|
| Functional behavior | Text snapshots: $TCTL -s <name> snapshot --trim |
| Visual rendering | Screenshots: $TCTL -s <name> screenshot -o ${RUN_DIR}/proof-N.png |
| Keyboard encoding | PTY bytes: ${DROID_PLUGIN_ROOT}/scripts/capture-terminal-bytes.py --backend <terminal> --combo <keys> |
| Web/Electron | Screenshots: agent-browser screenshot --annotate ${RUN_DIR}/proof-N.png |
| Native desktop GUI | Follow desktop-use for exact-window or authorized desktop state and recorder ownership |
| Before/after | Run the same sequence on both branches at the same capture points |
Outputs
Hand these to the compose stage:
## Capture outputs - clips: [${RUN_DIR}/before.cast, ${RUN_DIR}/after.cast] # .cast / .mp4 / .webm only - screenshots: [${RUN_DIR}/proof-1.png, ${RUN_DIR}/proof-2.png] # stills go to compose's screenshot path, never as clips - keys: ${RUN_DIR}/keys.tsv (if keystroke logging was requested; raw recording seconds) - driver: tuistory | true-input | agent-browser | cua-driver - terminal_size: 120x36 # for tuistory / true-input - viewport: 960x1000 # for agent-browser; report so compose knows the clip aspect
Recovery
If a session gets stuck mid-recording:
bash$TCTL -s <name> press esc # bail out of stuck dialog $TCTL -s <name> snapshot --trim # check visible state $TCTL -s <name> close # hard reset
For an isolated browser owned by this run: agent-browser close.
For desktop-use, reacquire state after interruption and coordinate with the recorder owner. Do not stop a shared daemon, close a personal app, or replay an uncertain input to recover a recording. Preserve partial artifacts as diagnostic evidence; label them incomplete rather than claiming they satisfy the deliverable.

