pty — persistent terminal sessions
What it is
pty runs a command in a managed terminal session you can detach from and
reconnect to later, from anywhere (including over SSH). It's the terminal /
session layer: run, list, peek, send, restart, kill, up.
When to reach for it
- A long-lived / background process: dev server, test suite, build, watcher, an agent.
- An interactive CLI that needs a real TTY: keychain/auth prompts, a TUI, a REPL.
- Any "start it, go do something else, come back to read / send / restart" task.
Prefer pty over & / nohup / pipes for these — you get lifecycle control,
readable replayed output, and the ability to wait for specific text. For a
one-shot command whose output you read right now, just run it directly.
The idiom (happy path)
pty run -d --name <name> --tag owner=<you> -- <command> # start detached, tagged
pty peek --wait "<ready text>" --plain <name> -t 30 # block until ready
pty peek --full --plain <name> # read full output
pty send <name> --seq "<text>" --seq key:return # send input + Enter
pty kill <name> # clean up when done
Tag the sessions you create; only touch sessions you created.
Key modifiers accept +, -, or _ separators and ignore case. For example,
key:ctrl+u, key:ctrl-u, key:ctrl_u, and readline-style key:C-u are
equivalent.
Footguns (the ones that actually bite)
- A broken global
pty on $PATH silently breaks the whole message bus.
st / smalltalk delivery shells out to pty send found on $PATH. If a
global-install symlink points at a stale or broken pty, every agent's
message delivery fails network-wide — silently. Run pty from the intended
install; if you do global-install, confirm pty --version works before
trusting delivery.
- Isolation is
PTY_ROOT, not PTY_SESSION_DIR. To keep scratch/test
sessions out of the production registry, set PTY_ROOT=<dir>.
PTY_SESSION_DIR is a deprecated alias and is ignored when PTY_ROOT is
already set (as it is inside a supervised session tree) — so setting only
PTY_SESSION_DIR there leaks your sessions into the ambient registry. pty
now warns when both are set.
- Sending text + Enter: mind the timing (top cause of "I sent it but nothing
happened").
pty send <ref> "text" sends NO newline — to submit, use
pty send <ref> --seq "text" --seq key:return. The why it can silently fail:
a terminal program processes a burst of bytes differently from spaced-out
input. With zero spacing, the trailing key:return routinely arrives before
the program's readline / PTY event loop has parsed and rendered the typed
text (and before bracketed-paste framing closes), so the Enter submits an
empty or partial line. pty send now inserts a 0.3s gap between --seq
items by default so each chunk is consumed before the next — you usually
don't need to think about it. Overrides: --with-delay <sec> to tune (some
slow TUIs want 0.5s+), and --with-delay 0 for a raw back-to-back stream
(fast/bulk sends where you know the receiver can take it).
- Don't nest. Inside a session, a bare
pty run runs the command directly
(nesting guard); use pty run -d to explicitly background a new session from
inside one.
The exact surface
Run pty --help for the full subcommand list, and pty <subcommand> --help for
that command's flags and examples. pty --version prints <semver>+<short-sha>.
1---2name: pty3description: Run and manage long-lived or background processes — dev servers, test suites, builds, interactive CLIs, agents — in persistent, detachable terminal sessions. Reach for pty INSTEAD of `&` / nohup / raw background shell whenever you need to start work, go do something else, then come back to read its output, send it input, or restart it; and for any interactive tool that needs a real TTY (auth/keychain prompts, TUIs, REPLs).4---56# pty — persistent terminal sessions78## What it is9`pty` runs a command in a managed terminal session you can detach from and10reconnect to later, from anywhere (including over SSH). It's the terminal /11session layer: `run`, `list`, `peek`, `send`, `restart`, `kill`, `up`.1213## When to reach for it14- A long-lived / background process: dev server, test suite, build, watcher, an agent.15- An interactive CLI that needs a real TTY: keychain/auth prompts, a TUI, a REPL.16- Any "start it, go do something else, come back to read / send / restart" task.1718Prefer `pty` over `&` / `nohup` / pipes for these — you get lifecycle control,19readable replayed output, and the ability to wait for specific text. For a20one-shot command whose output you read right now, just run it directly.2122## The idiom (happy path)23```sh24pty run -d --name <name> --tag owner=<you> -- <command> # start detached, tagged25pty peek --wait "<ready text>" --plain <name> -t 30 # block until ready26pty peek --full --plain <name> # read full output27pty send <name> --seq "<text>" --seq key:return # send input + Enter28pty kill <name> # clean up when done29```30Tag the sessions you create; only touch sessions you created.3132Key modifiers accept `+`, `-`, or `_` separators and ignore case. For example,33`key:ctrl+u`, `key:ctrl-u`, `key:ctrl_u`, and readline-style `key:C-u` are34equivalent.3536## Footguns (the ones that actually bite)37- **A broken global `pty` on `$PATH` silently breaks the whole message bus.**38 `st` / smalltalk delivery shells out to `pty send` found on `$PATH`. If a39 global-install symlink points at a stale or broken `pty`, *every* agent's40 message delivery fails network-wide — silently. Run `pty` from the intended41 install; if you do global-install, confirm `pty --version` works before42 trusting delivery.43- **Isolation is `PTY_ROOT`, not `PTY_SESSION_DIR`.** To keep scratch/test44 sessions out of the production registry, set `PTY_ROOT=<dir>`.45 `PTY_SESSION_DIR` is a deprecated alias and is *ignored* when `PTY_ROOT` is46 already set (as it is inside a supervised session tree) — so setting only47 `PTY_SESSION_DIR` there leaks your sessions into the ambient registry. pty48 now warns when both are set.49- **Sending text + Enter: mind the timing (top cause of "I sent it but nothing50 happened").** `pty send <ref> "text"` sends NO newline — to submit, use51 `pty send <ref> --seq "text" --seq key:return`. The *why* it can silently fail:52 a terminal program processes a burst of bytes differently from spaced-out53 input. With zero spacing, the trailing `key:return` routinely arrives before54 the program's readline / PTY event loop has parsed and rendered the typed55 text (and before bracketed-paste framing closes), so the Enter submits an56 empty or partial line. `pty send` now inserts a **0.3s gap between `--seq`57 items by default** so each chunk is consumed before the next — you usually58 don't need to think about it. Overrides: `--with-delay <sec>` to tune (some59 slow TUIs want 0.5s+), and **`--with-delay 0` for a raw back-to-back stream**60 (fast/bulk sends where you know the receiver can take it).61- **Don't nest.** Inside a session, a bare `pty run` runs the command directly62 (nesting guard); use `pty run -d` to explicitly background a new session from63 inside one.6465## The exact surface66Run `pty --help` for the full subcommand list, and `pty <subcommand> --help` for67that command's flags and examples. `pty --version` prints `<semver>+<short-sha>`.