factory-ai/tuistory
Background knowledge for droid-control workflows -- not invoked directly. Tuistory driver mechanics for terminal TUI automation via virtual PTY.
npx skills add https://github.com/Factory-AI/factory-plugins --skill tuistory
The orchestrator routed you here. Use these mechanics to execute your plan.
Launch a target command in a virtual PTY with Playwright-style CLI for typing, pressing keys, waiting, snapshotting, and recording.
wait / wait-idle against the virtual screen bufferIf you need to prove what Ghostty or Kitty actually emits for a given keystroke, use true-input instead.
npm install -g tuistory # or: bun add -g tuistory
Optional: tmux (scrollback flows), asciinema (recordings), agg (.cast to .gif).
TCTL=${DROID_PLUGIN_ROOT}/bin/tctl
$TCTL launch "droid-dev" -s demo --backend tuistory \
--repo-root /path/to/worktree \
--cols 120 --rows 36 \
--env FORCE_COLOR=3 --env COLORTERM=truecolor
$TCTL -s demo wait ">" --timeout 15000
$TCTL -s demo type "hello"
$TCTL -s demo press enter
$TCTL -s demo snapshot --trim
$TCTL -s demo close
Note: --repo-root is mandatory for droid-dev launches — tctl enforces it.
Always pass --env FORCE_COLOR=3 --env COLORTERM=truecolor when launching. The virtual PTY doesn't advertise color support, so Node.js apps (Ink/chalk) suppress all color escape codes without these.
| Command | Purpose |
|---|---|
| launch <cmd> -s <name> --backend tuistory | Start a tuistory session |
| type <text> | Send literal text |
| press <key> [keys...] | Send key chord (e.g., press shift enter) |
| wait <pattern> | Block until text or /regex/ appears |
| wait-idle | Block until output stabilizes |
| snapshot [--trim] | Print cleaned text (--trim strips trailing blanks) |
| close | Tear down session |
Launch options: --cols <n>, --rows <n>, --cwd <path> (child working directory; defaults to --repo-root when set), --env KEY=VALUE, --record <path>.
Pass --record at launch. tctl wraps asciinema rec around the PTY, so recording must be set at launch time (raw tuistory cannot record):
$TCTL launch "droid-dev" -s demo --backend tuistory \
--repo-root /path/to/worktree \
--cols 120 --rows 36 --record /tmp/demo.cast \
--env FORCE_COLOR=3 --env COLORTERM=truecolor
# ... interact ...
$TCTL -s demo close # finalizes the .cast
Before/after comparison -- launch two sessions against different worktrees:
$TCTL launch "droid-dev" -s before --backend tuistory \
--repo-root /path/to/baseline-worktree \
--cols 120 --rows 36 --record /tmp/before.cast \
--env FORCE_COLOR=3 --env COLORTERM=truecolor
$TCTL launch "droid-dev" -s after --backend tuistory \
--repo-root /path/to/candidate-worktree \
--cols 120 --rows 36 --record /tmp/after.cast \
--env FORCE_COLOR=3 --env COLORTERM=truecolor
Playback: asciinema play /tmp/demo.cast
Only needed when the demo requires terminal-emulator scrollback and the app uses the standard buffer (not alternate screen). True-input sessions rarely need tmux because the real terminal owns native scrollback.
Use --tmux at launch. tctl wraps the command in tmux, starts tmux with TERM=xterm-256color, and preconfigures default-terminal=tmux-256color, terminal-features=...,xterm-256color:RGB, terminal-overrides=...,xterm-256color:Tc (fallback for tmux < 3.2), COLORTERM=truecolor (via set-environment), escape-time=50, and mode-keys=vi.
Copy-mode: ctrl-b [ to enter, g g top, shift-g bottom, ctrl-u/ctrl-d half-page, / search, q to exit (not esc).
Launch with tmux:
$TCTL launch "droid-dev" -s demo --backend tuistory --tmux \
--repo-root /path/to/worktree \
--cols 120 --rows 36 --record /tmp/demo.cast \
--env FORCE_COLOR=3 --env COLORTERM=truecolor
When recording includes tmux redraws, asciinema must wrap tmux, not the reverse.
asciinema rec: Do not call asciinema rec directly. tctl --record wraps asciinema rec around the PTY so that tuistory-relay still owns the session and interactive TUIs (Ink/React) receive stdin correctly. Calling asciinema rec manually bypasses this wiring — stdin forwarding breaks, typed keys echo on the outer PTY instead of reaching the child, and tuistory commands (wait, snapshot, close) cannot find the session.tuistory launch with tctl flags: tuistory has no --record, --backend, --repo-root, or --env flags. Passing them crashes tuistory-relay. Use tctl for all launches.$TCTL -s demo press esc # bail out of a stuck dialog
$TCTL -s demo snapshot --trim # check visible state
$TCTL -s demo close # hard reset
If tctl itself is broken or unavailable, you can fall back to raw tuistory for non-recording sessions only. Raw tuistory accepts only --cols, --rows, and -s — no other flags. Do not pass --record, --backend, --repo-root, --env, or --tmux.
tuistory launch "my-tui-app" -s demo --cols 120 --rows 36
tuistory -s demo wait ">" --timeout 15000
tuistory -s demo snapshot --trim
tuistory -s demo close
Take factory-ai/tuistory from the repository into ~/.claude/skills for personal
use, or into .claude/skills inside a project.
The agent identifies a skill by the name field in its header. Two skills with the
same name cannot sit side by side — one of them will be ignored.
The instructions reference npm.
Without those the skill loads but fails at the first command.