Skip to content

Michaelliv/pi-shot

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

3 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

pi-shot

Capture the live pi TUI as a pixel-perfect PNG. Compose synthetic conversations from CLI flags, drive real slash commands, load existing sessions, swap themes — whatever you need to make the screenshot you want.

hero

Why

pi is a terminal-first AI coding agent and its TUI does a lot of work (syntax-highlighted reads, real diffs on edits, colored bash backgrounds, custom extension messages, theme support). Most screenshot tools either:

  • snapshot a static frozen frame and lose all the live behavior, or
  • run the real terminal and inherit your font/theme/window chrome.

pi-shot drives a real headless pi instance inside node-pty + @xterm/headless, walks the buffer cell-by-cell, and renders the result through HTML + Playwright. The output uses pi's actual ANSI colors, the actual theme JSON, and a clean macOS-style window frame. The image is auto-trimmed to fit the content so there's no dead space below the conversation.

Install

npm install -g @miclivs/pi-shot

You also need pi itself installed and on your PATH:

npm install -g @mariozechner/pi-coding-agent

Quick start

# render a synthetic two-turn chat with a bash tool call
pi-shot \
  --no-banner --pi-arg --offline \
  -m "user:list files" \
  -m "bash:ls -la:total 12\ndrwxr-xr-x  3 user staff  96 ." \
  -m "assistant:Three files." \
  -o chat.png
# capture an existing pi session as-is
pi-shot --session ~/.pi/agent/sessions/proj/abc.jsonl -o session.png
# pre-fill the editor box with a half-typed prompt
pi-shot --prompt "add tests for the auth flow" -o prompt.png
# drive an extension's slash command live
pi-shot --no-banner --keys "/psst-set" --keys "\r" -o ext.png

Examples

The examples/ folder has 15 self-contained scripts covering every feature. Each one writes a numbered PNG next to itself. Run any of them individually, or bash run-all.sh to generate them all.

File Shows
01-empty.sh Empty pi at rest
02-simple-chat.sh A two-turn user/assistant chat
03-bash-tool.sh A bash tool call with multi-line output
04-edit-tool.sh An edit tool rendered as a real unified diff
05-all-tools.sh Every tool kind in one shot: read, write, edit, bash, grep, find, ls
06-thinking.sh An assistant turn with a thinking block
07-custom-message.sh A custom-typed message of the kind extensions emit
08-prefilled-prompt.sh The editor box pre-filled with text
09-slash-command.sh The slash-command autocomplete popup
10-multi-step-keys.sh Multiple --keys bursts driving a multi-step flow
11-real-session.sh An existing pi session JSONL rendered as-is
12-light-theme.sh The same conversation in pi's built-in light theme
13-custom-theme.sh A custom theme JSON file applied to pi
14-with-extension.sh An extension's slash command rendered live
15-pi-psst-end-to-end.sh Full pi-psst story with a real LLM call

Composing conversations

For quick captures, the -m "kind:body" shorthand covers everything:

user:<text>
assistant:<text>
thinking:<text>
bash:<command>:<output>
read:<path>:<content>
write:<path>:<content>
edit:<path>:<oldText>:<newText>
grep:<pattern>:<path>:<matches>
find:<pattern>:<path>:<results>
ls:<path>:<entries>
custom:<type>:<content>
model:<provider>:<model-id>
thinking_level:<off|minimal|low|medium|high|xhigh>

Use \n inside any field to insert a real newline.

For more complex flows (multi-content assistant turns, custom tool details), write a JSON file matching the ComposeMessage union and pass --compose file.json instead:

[
  { "kind": "user", "text": "hello" },
  { "kind": "assistant", "text": "hi", "thinking": "they greeted me" },
  { "kind": "bash", "command": "ls", "output": "file.txt" },
  { "kind": "edit", "path": "src/a.ts", "oldText": "foo", "newText": "bar" }
]

The compose builder uses pi's own typed SessionManager under the hood, so the resulting JSONL is guaranteed to match pi's real session schema.

Driving live pi

Anything you can type into pi, you can send via --keys. Each --keys flag is one keystroke burst, and pi-shot waits for pi to settle between bursts so multi-step flows work cleanly:

pi-shot \
  --no-banner \
  --keys "/psst-set DEMO_KEY sk-live-abc demo,prod\r" \
  --keys "echo the value of DEMO_KEY using bash\r" \
  --idle-ms 8000 \
  -o demo.png

Escape sequences supported: \r, \n, \t, \e, and \xHH.

Theming

# built-in light theme
pi-shot --theme light -o light.png

# any pi theme JSON file
pi-shot --theme my-theme.json -o custom.png

The theme JSON schema is documented in pi's own theme directory. pi-shot copies your real ~/.pi/agent dir into a private temp dir and layers the theme override on top, so all your packages, credentials, and model preferences still apply.

Output

pi-shot writes the output file path to stdout so you can pipe it:

convert "$(pi-shot -m 'user:hi' -o /tmp/x.png -q)" -resize 50% small.png

All status messages go to stderr. Use -q/--quiet to silence them entirely. NO_COLOR is honored.

Reference

USAGE
  pi-shot [INPUT] -o OUTPUT.png [OPTIONS]

INPUT (one of)
  --session <file>            open an existing pi session JSONL
  --compose <file>            load compose messages from a JSON array file
  -m, --message <kind:body>   compose a synthetic message (repeatable)

OUTPUT
  -o, --output <file>         output PNG path (required)

PROMPT BOX & DRIVING
  --prompt <text>             pre-fill the editor input box
  --keys <text>               send raw keystrokes (repeatable)
  --extension <path>          load a pi extension before capture (repeatable)

TERMINAL SIZE
  --cols <n>                  terminal columns (default: 120)
  --rows <n>                  terminal rows (default: 35)

CAPTURE TIMING
  --idle-ms <n>               ms of pty silence to consider pi idle (default: 2500)
  --step-timeout-ms <n>       hard timeout per message step (default: 30000)
  --delay <n>                 extra delay after final idle, before capture
  --capture <mode>            "viewport" (default) or "all" (full scrollback)

WINDOW CHROME
  --no-window                 disable the macOS-style window frame
  --padding <px>              padding inside the window (default: 20)
  --background <color>        window background color
  --border-radius <px>        window border radius (default: 8)

STARTUP CHROME
  --no-banner                 skip pi's startup overview (welcome banner,
                              [Context], [Extensions], [Skills], etc)

THEMING
  --theme <name|file>         pi theme: "dark", "light", or path to JSON
  --window-bg <color>         override the screen background only
  --font-family <css>         override the monospace font stack
  --font-size <px>            override font size (default: 14)
  --line-height <n>           override line-height multiplier (default: 1.15)

PI PASSTHROUGH
  --cwd <path>                working directory pi runs in
  --pi-arg <arg>              pass an extra argument to pi (repeatable)

GENERAL
  -q, --quiet                 suppress pi-shot's own status output
  -h, --help                  show full help
  --version                   print version

Run pi-shot --help for the complete reference with all message kinds and inline examples.

How it works

  1. PtyRunner spawns pi inside node-pty with COLORTERM=truecolor and feeds its output into an @xterm/headless Terminal instance.
  2. SessionBuilder uses pi's exported SessionManager to write a real session JSONL file from the compose messages, guaranteeing the shape pi expects.
  3. The runner waits for pi to go idle (no output for --idle-ms ms), then any --prompt is typed into the editor and any --keys bursts are sent.
  4. HtmlRenderer walks the xterm cell buffer, builds an HTML document with the exact ANSI colors pi emitted, integer-pixel row heights to avoid sub-pixel gaps in colored backgrounds, and auto-trims trailing empty rows.
  5. Playwright screenshots the HTML and writes the PNG.

The whole pipeline takes 5-10 seconds for a typical capture.

License

MIT

About

Capture the live pi TUI as a pixel-perfect PNG. Compose synthetic conversations, drive slash commands, load real sessions.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors