Skip to content

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, then rename(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 whatever LINES reports; pinning at 24 keeps those screenshots normal-sized. Tall scrolling output (a long git log) is handled separately, by the snug-mode auto-grow described under --snug / --no-snug.
--scale N
Pixel scale factor. Default: 2 (retina). Use 1 for half-resolution output, 3 for 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-snug to keep the literal width × height grid 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 long git log produces a tall screenshot containing every line, while vim, less, and htop still render at their normal 24-row size. With --no-snug, scrolling drops the top row as a real terminal would.
--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-fonts to 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. Try 1.21.4 for 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 --timeout and 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-command on a stable shot).
--check
Render in memory and compare against the existing PNG on disk; never write. Prints one of [emoji] <path> missing|OK|changed per shot and exits non-zero if any target is missing or out of date. Designed for CI "docs are stale" gates — drop-in replacement for shotty && 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-all mode, where the default flips to off (emitting 20 inline PNGs back-to-back is rarely what you want). Pass --inline auto or --inline on to opt back in for bulk runs. See Inline images.

Metadata

--embed-command / --no-embed-command
Embed the command in the PNG's UserComment metadata (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-shot style and the config's default_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, then shotty -- shotty --demo to PNG it.
--version
Print the build's version (derived at build time from git describe --tags --always --dirty) and exit. Tagged releases look like v0.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-256color
  • COLORTERM=truecolor
  • CLICOLOR=1, CLICOLOR_FORCE=1
  • FORCE_COLOR=3
  • COLUMNS, LINES — set to the requested grid size
  • KITTY_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.