atmos ai skill install atmos-castAtmos Cast
Use this skill for Atmos's built-in terminal session recording and rendering subsystem. A cast is
an asciicast v2 recording (.cast) of a terminal session that Atmos can play back or render into
shareable artifacts (GIF, MP4, HTML, ASCII, PNG, JPEG).
Related Skills
| Need | Load |
|---|---|
| Workflow step types in general, orchestration, output/UI steps | atmos-workflows |
| Custom CLI commands with native steps | atmos-custom-commands |
Global settings (atmos.yaml non-subsystem options) | atmos-settings |
Purpose
Cast recording turns a terminal session into a deterministic, replayable artifact instead of a one-off screen capture. It is used to:
- Record CLI demos and documentation screengrabs as committed
.castfiles that render identically every time (no flaky video capture, no OS-specific fonts/cursors baked in). - Capture a workflow or custom-command run as a proof-of-run artifact (CI evidence, runbook reproduction).
- Script fully synthetic "simulated" terminal sessions (typed commands with jitter, styled prompts) for docs and mindset demos, without actually running the commands shown.
Key Commands
| Command | Purpose |
|---|---|
atmos cast play <input.cast> | Play an asciicast recording back in the terminal |
atmos cast render <input.cast> --output=<path> | Render a recording to GIF, MP4, HTML, ASCII, PNG, or JPEG |
atmos cast render <input.cast> --output=<path> --format=<fmt> | Render with an explicit format when the output filename's extension doesn't indicate one |
Global --cast Flag / ATMOS_CAST
Any Atmos command can be recorded directly, without going through atmos cast:
atmos terraform plan vpc -s dev --cast=demo.cast # record raw asciicastatmos terraform plan vpc -s dev --cast=demo.gif # record, then auto-render to gif, discard the intermediate .castatmos terraform plan vpc -s dev --cast # auto value: record without keeping/rendering (ad hoc)ATMOS_CAST=demo.cast atmos terraform plan vpc -s dev
--cast/ATMOS_CAST accepts the same extensions as atmos cast render's output-format
inference. When the value ends in a renderable extension (not .cast), Atmos records to a
temporary cast in the OS temp dir, renders it to the requested output, and removes the
intermediate .cast. When the value is .cast, the raw recording is kept at that path. --cast
with no path (or true/1/yes/on via env) records without an explicit target.
Recording can also be enabled automatically for every command via atmos.yaml:
# atmos.yamlcast:recording:enabled: truebase_path: "./casts" # directory intermediate/auto casts are written underinput: false # also record stdin keystrokes, not just outputwidth: 120height: 30session:shell_init: clean # session-mode shell startup: clean (default), user, or an rc file path
Automatic (config-enabled) recording skips --help and shell-completion invocations so casual
--help calls aren't captured; an explicit --cast/ATMOS_CAST still records help output.
Output Format Inference
Both atmos cast render and the --cast/ATMOS_CAST flag infer the render format from the
output file's extension. Supported extensions/formats: .gif, .mp4, .html, .ascii, .png,
.jpg, and .jpeg (.jpg/.jpeg both map to the jpeg renderer). .cast means "keep the raw
recording, do not render."
atmos cast render demo.cast --output=demo.gif # format inferred from .gifatmos cast render demo.cast --output=demo.html # format inferred from .htmlatmos cast render demo.cast --output=demo.out --format=html # explicit --format for a non-matching extension
--format is required when the output path's extension doesn't map to a supported format (or has
none). If both the extension and --format imply a format, they must agree -- Atmos errors on a
conflict (e.g. --output=demo.gif --format=html).
Workflow and Custom-Command Step Types
The same recording/rendering engine is available as native step types inside workflows: and
custom-command steps: -- no wrapper script needed.
type: cast
A cast step wraps a set of child steps (or a scripted shell session) and records everything they
produce into an asciicast. It supports two mode: values:
mode: steps (default) -- runs nested child steps (any step type, including type: simulate)
through the normal step executor and records their combined output:
steps:- type: castname: demo-planmode: steps # optional, this is the defaultwidth: 120height: 30output: # CastOutput: any subset of these pathscast: demo.cast # keep the raw recordinggif: demo.gif # also render to gifhtml: demo.html # also render to htmlsteps:- type: simulatemode: typedtext: "atmos terraform plan vpc -s dev"- type: atmoscommand: terraform plan vpc -s dev
mode: session -- drives an interactive shell directly with a scripted list of session
actions instead of running typed steps. Each child step's type: is the session action:
| Action | Fields | Purpose |
|---|---|---|
write | text, rate | Type literal text into the session |
key | key, interval | Send a single keypress (e.g. enter, tab, ctrl+c) |
pause | duration | Wait a fixed duration before the next action |
playback | duration, steps | Fit nested actions into an exact playback duration without changing execution time |
wait | text or regex (exactly one), timeout | Block until the session output matches; the echo of a line typed and submitted with Enter is never matched |
steps:- type: castname: demo-sessionmode: sessionshell: bashsteps:- type: writetext: "atmos workflow deploy-vpc -s dev\n"- type: waitregex: "Apply complete!"timeout: 2m- type: keykey: enter
A wait only matches output produced after the most recent input action (write or key), so
the echo of the command just typed and output from earlier commands never satisfy it. A timed-out
wait fails the cast with timed out waiting for cast output: /re/ not seen within 10s. Before the
first action, session mode waits for the shell to go quiet (its first prompt).
By default the session shell starts clean, without the user's startup files, so recordings stay
reproducible. shell_init: clean (default) does this (bash --noprofile --norc, zsh -f, fish
--no-config, other shells ENV=); shell_init: user loads the normal startup files; any other
value is an rc-file path sourced instead. Session blocks inherit the parent's value. Precedence:
the step's shell_init > atmos cast record --shell-init > cast.session.shell_init in
atmos.yaml (ATMOS_CAST_SESSION_SHELL_INIT) > clean.
Group Enter and its completion wait in type: playback with duration: 4s to accelerate
a long operation while preserving all recorded frames. Typing and reading pauses outside
the group keep their timing. Playback groups also support ordinary steps in mode: steps;
they require a positive duration and cannot nest or overlap. Short groups stretch to fit.
Cast-level fields: width/height (recording dimensions), rate (default output pacing),
title, command, env, and output (a CastOutput: cast, gif, mp4, html, ascii,
png, jpg -- any subset). defaults.cast (rate/width/height) and defaults.simulate
(see below) set shared defaults for child steps so they don't need to repeat the same values.
type: simulate
A simulate step (used as a child of a mode: steps cast) replays scripted terminal activity
without actually running a command -- useful for docs/demo casts that show a command's output
verbatim rather than depending on live infrastructure. Two mode: values:
mode: typed(default) -- typestextcharacter-by-character at the terminal, then presses enter. Fields:text(required),rate(base per-character delay),jitter(0-1, randomizes per-character timing deterministically so re-recording the same script is reproducible),duration(delay before the simulated enter/output),interval(pause after the step, before the next),cursor(show the terminal cursor while typing), andprompt(SimulatePrompt:textandstyle, wherestyleis one of the theme styles --body,command,label,muted,info,notice).mode: prompt-- renders just the prompt (and optional cursor), without typing anything; used to show an idle prompt between recorded actions.
steps:- type: castmode: stepsdefaults:simulate:prompt:text: "$ "style: commandjitter: 0.3steps:- type: simulatemode: typedtext: "atmos version"cursor: true- type: atmoscommand: version- type: simulatemode: prompt
Declarative Starlark recordings
Use cast.recorder(...) inside an existing Starlark script step when YAML repeats
simulated command text, execution, and validation. Keep each rec.comment(...)
with its related rec.run(...) calls; separate story sections with source comments
and two blank lines. Shared project modules can supply constructor defaults.
rec = cast.recorder(output="demo.cast", title="Inspect the project")rec.comment("List available stacks")rec.run("atmos list stacks", expect="dev", reject=cast.regex(r"panic:"))rec.generate()
Use rec.terminal.send, wait, and key for a persistent interactive PTY. Close
it with rec.terminal.close() before ordinary recorder actions. Do not invent a
terminal global or callback-based session API. Ordinary run calls have separate
processes; rec.cd updates the directory for subsequent declarations.
setup, hidden, and cleanup accept functions receiving a declaration builder.
Declare steps through that builder; direct exec.run or steps.* calls execute
immediately and would also execute during saved validation. rec.validate() uses
the same declaration to check a saved cast without running declared actions.
Older casts need regeneration to acquire validation metadata. policy(text) can
check the whole recording; replacements normalizes literal output paths before
saved-output checks. Failed execution, cleanup, or validation preserves the old cast.
Validating recordings
Prefer type: script with interpreter: starlark (or source: <file>.star, which infers it) for cast validation, including
when updating Python-based validators. Parse the recording with fs.read_file and
json.decode, join output-event payloads, then assert the expected result and
absence of secrets/local paths. Use regex for ANSI normalization and fail for
failed assertions; no Python process is needed. Run validation after successful
recording and required cleanup, and retain playback review for timing/layout.
See the portable Starlark validation example.
Common Patterns
- Committed docs screengrabs: record demo commands to a
.castfile, commit it, and render it at doc-build time (or check in the rendered HTML/image too). The.castsource stays deterministic across environments; re-rendering never depends on terminal fonts or timing. - CI proof-of-run artifacts: wrap a workflow's real steps in
type: castwithoutput.giforoutput.htmlso a pipeline can publish what actually ran, not just its exit code. - Fully synthetic demos: use
type: simulatesteps exclusively (no realatmos/shellchildren) to script a "fake" but visually authentic terminal walkthrough for marketing/docs content, independent of any live stack or component. - Mixing real and simulated steps: interleave
type: simulate(to narrate/type the command) with the realtype: atmos/type: shellstep that actually executes it, so the recording looks hand-typed while the executed output is genuine. - Synthetic directory transitions: when the story enters a generated or nested directory,
show
type: simulatewithcd <directory>before the first command there. This is display-only; keepworking_directoryon every real child step so execution does not depend on simulated terminal state. - Prefer
atmos cast renderover ad hoc--cast=<gif>one-liners when a.castsource should be kept and re-rendered into multiple formats later; use--cast=<ext>for quick one-shot capture when only the rendered artifact matters.