CLI reference¶
shotty --render-all # bulk: every [[shot]] in the active config
shotty --render <name> # bulk: one [[shot]] from the config, by output name
shotty [options] "<full shell command>" # ad-hoc, shell mode (prompt header rendered)
shotty [options] -- <command> [args...] # ad-hoc, exec mode (no shell, no header)
shotty [options] <command> [args...] # equivalent to -- form
Exactly one of --render-all, --render <name>, or an ad-hoc
command is required.
Modes¶
| Form | What it does |
|---|---|
shotty --render-all |
Renders every [[shot]] in the active config (see Configuration). PNGs whose pixels haven't changed are silently skipped. |
shotty --render <name> |
Renders a single shot from the active config. <name> matches against output exactly, then against the basename, then against the basename without extension. |
shotty "ls -la \| head" |
Single positional → run via sh -c. A green ❯ + the command line is rendered above the output. |
shotty -- ls -la |
Everything after -- is the literal argv for execvp. No shell, no prompt header. |
shotty ls -la |
Same as the -- form. |
Output¶
-o PATH,--output PATH- Output PNG path. Default: a timestamped name in the cwd, e.g.
Shotty 2026-05-02 19.22.56.png— matching macOS's screenshot naming convention. Written atomically — temp file in the same directory, thenrename(2). Refuses to overwrite a target that exists and isn't already a PNG. --width N- Terminal columns. Default:
80. --height N- Terminal rows the child process sees as
LINES. Default:24. A small default is intentional — full-screen TUIs (vim,htop,less) size their UI to whateverLINESreports; pinning at 24 keeps those screenshots normal-sized. Tall scrolling output (a longgit log) is handled separately, by the snug-mode auto-grow described under--snug/--no-snug. --scale N- Pixel scale factor. Default:
2(retina). Use1for half-resolution output,3for super-retina. --margin N- Outer margin in points around the window (so the drop shadow has
room). Default:
36. --no-shadow- Disable the drop shadow. The PNG canvas shrinks accordingly.
--snug/--no-snug-
On by default. Two effects:
- Trim trailing blanks. After the command runs, the window
wraps snugly around what was actually drawn (plus a small
breathing margin: 1 row / 1.5 cells of bottom whitespace). Pass
--no-snugto keep the literalwidth × heightgrid even when output is shorter. - Preserve scrollback. The child still sees a
--height-row terminal (24 by default), but when its output exceeds that, the grid grows on each scroll instead of dropping the top row — up to--max-height. So a longgit logproduces a tall screenshot containing every line, whilevim,less, andhtopstill render at their normal 24-row size. With--no-snug, scrolling drops the top row as a real terminal would.
- Trim trailing blanks. After the command runs, the window
wraps snugly around what was actually drawn (plus a small
breathing margin: 1 row / 1.5 cells of bottom whitespace). Pass
--max-height N- Cap on how many rows the snug-mode scrollback can grow to.
Default
120. Past this point, scrolling falls back to drop-top behavior — runaway output still has a bound.
Typography¶
--font NAME- Monospace font PostScript name. Default:
Menlo-Regular. Use--list-fontsto see what's available. --font-size N- Font point size. Default:
13. --line-height N- Line-height multiplier on the font's natural line height.
Default:
1.0. Try1.2–1.4for more breathing room. --title TEXT- Window title text. Defaults to the command line. Centered when it fits; falls back to left-aligning past the traffic lights and clipping at the right edge when too long.
--no-title- Hide the title text entirely (traffic-light buttons remain).
Capture¶
--timeout N- SIGKILL the child after N seconds and render whatever was captured
up to that point. Useful for pagers (
less,man,bat's default pager) and TUI startup screens that wouldn't otherwise exit. When the timeout actually fires, Shotty draws a cursor block in the rendered shot so it reads as a live snapshot instead of "the command finished and exited." See--timeoutand the cursor.
Writing¶
--force- Always write the PNG, even when its pixels are identical to what's
already on disk. Useful when only metadata-affecting flags have
changed (e.g. toggling
--embed-commandon a stable shot). --check- Render in memory and compare against the existing PNG on disk;
never write. Prints one of
[emoji] <path> missing|OK|changedper shot and exits non-zero if any target is missing or out of date. Designed for CI "docs are stale" gates — drop-in replacement forshotty && git diff --exit-code docs/images/.
Inline display¶
--inline auto|on|off- Display the resulting PNG inline in your terminal after writing it.
Default is
auto(detect iTerm2 / Kitty / Ghostty / WezTerm via env vars and emit only when stdout is a TTY) — except in--render-allmode, where the default flips tooff(emitting 20 inline PNGs back-to-back is rarely what you want). Pass--inline autoor--inline onto opt back in for bulk runs. See Inline images.
Metadata¶
--embed-command/--no-embed-command- Embed the command in the PNG's
UserCommentmetadata (in the same TOML shape as a[[shot]]body) so a future reader can paste- reproduce the screenshot. Off by default — commands often contain paths, environment-leaking bits, or other things you may not want in a published image. The render parameters (font, size, grid dimensions, etc.) are always embedded; only the command line is opt-in.
Config¶
--style NAME- Apply a named
[styles.<name>]from the active config. Overrides any per-shotstyleand the config'sdefault_style. See Configuration § Named styles. --config PATH- Explicit config file path. Bypasses the cwd → home cascade and loads the given file verbatim, shots and all. See Configuration for the lookup rules and Config schema for the keys.
Introspection¶
--list-fonts- Print every monospaced font's PostScript name (one per line,
sorted) and exit. These are the values you can pass to
--font. --demo- Print a sampler of what Shotty's renderer can handle — text
attributes, the 16-color palette, the 256-color cube, a truecolor
sweep, and a Unicode line covering emoji families, skin tones, ZWJ
joiners, regional flags, CJK wide chars, and combining marks. If
your terminal speaks an inline-image protocol (Kitty / iTerm2 /
Ghostty / WezTerm), the Shotty logo prints at the top too. Useful
for sanity-checking that what your terminal renders is what Shotty
would capture — try
shotty --demo, thenshotty -- shotty --demoto PNG it. --version- Print the build's version (derived at build time from
git describe --tags --always --dirty) and exit. Tagged releases look likev0.2.0 (abc1234); dev builds carry the<tag>-<n>-g<hash>[-dirty]suffix. -h,--help- Show usage and exit.
Environment passed to the child¶
The child runs under a real PTY with these set on top of your environment:
TERM=xterm-256colorCOLORTERM=truecolorCLICOLOR=1,CLICOLOR_FORCE=1FORCE_COLOR=3COLUMNS,LINES— set to the requested grid sizeKITTY_WINDOW_ID=1— advertises inline-image support so child processes emit Kitty graphics for shotty to capture
This is enough for ls, git, bat, eza, cargo, npm, grep,
etc. to detect a terminal and emit colors automatically.
Exit codes¶
| Code | Meaning |
|---|---|
0 |
Wrote PNG, or skipped because pixels were unchanged. |
1 |
Render or write failed; one or more shots in bulk mode failed; or --check found missing/changed targets. |
2 |
Config parse error. |
64 |
Argument validation error (bad flag, refused to overwrite a non-PNG, missing command, etc.). |
127 |
The child command could not be execvp'd. The error appears inside the screenshot. |