Concepts
Ownership Boundaries
tastty separates terminal concerns by what the caller wants to own.
tastty-core owns terminal protocol state. It parses bytes into a virtual
screen, tracks modes and events, encodes input, and represents host replies. The
caller still owns the transport, the event loop, and all reads and writes.
tastty owns PTY session lifecycle. It starts a child process, reads from the
PTY on a background thread, writes input to the child, resizes the PTY and
screen together, and exposes snapshots of the parsed screen.
tastty-driver owns active control. It turns a live session into a higher-level
surface for spawning, sending input, waiting for conditions, capturing snapshots,
inspecting terminal metadata, and controlling the process.
Dependency direction
The dependency direction is intentionally one-way:
tastty-driver -> tastty -> tastty-coreThis keeps protocol code usable without session management, and keeps session management usable without the driver layer. It also gives callers a clear choice between parser-only, managed session, and active control APIs.
Parser, Terminal, Driver
The same terminal state appears at different levels:
Parserreceives bytes and mutates aScreen.Terminalowns a managed child process and exposesscreen,snapshot, andwith_screenviews of the parsed state.Sessionintastty-driverexposes snapshots, scrollback snapshots, inspection data, waits, and process-control operations.
Move up a layer when you want that layer to own more lifecycle. Move down a layer when you need a smaller dependency or a custom transport.
Site docs and rustdoc
The site docs explain the shape of the libraries and the common workflows. They do not duplicate rustdoc.
Use these pages for:
- deciding which crate to depend on;
- understanding how the layers relate;
- learning the first calls to make;
- seeing compact examples that connect the pieces.
Use rustdoc for:
- complete type and method lists;
- enum variants and non-exhaustive markers;
- exact error variants;
- feature-gated APIs;
- item-level examples and invariants.
Terminal sizes and positions
The public API uses named coordinate and size types. TerminalSize carries
rows and cols; Position carries row and col. This makes resize,
cursor, wait, and snapshot code read consistently across the three layers.
Use TerminalSize::new for dimensions from untrusted input. Runtime resizes
reject zero rows or columns. Struct-literal construction is still available when
the caller already knows the values are valid.
Input paths
There are three input paths, depending on how much abstraction you want:
- raw bytes, through
Terminal::sendorSession::send_bytes; - typed keys and mouse events, encoded against current terminal modes;
- driver input segments, parsed from text such as
echo ready<Enter>.
Typed input is preferable when the child program may change keyboard modes. Raw bytes are appropriate when you intentionally want protocol-level control. Driver input segments are useful when a workflow mixes literal text with named keys in a single ordered sequence.
Waits and snapshots
The driver wait API polls snapshots until a condition matches, the timeout
expires, or the child exits before a non-exit condition can match. Conditions
cover text, regex, row regex, cell text, cursor position, process exit, stable
screens, and any_of composition.
A driver Snapshot is richer than tastty::TerminalSnapshot: it includes
visible text, cells, style runs, cursor state, title metadata, and alternate
screen state. Use tastty::TerminalSnapshot when you only need a compact view
from a managed PTY session. Use tastty-driver snapshots when waits,
inspection, styles, scrollback, or process control are part of the workflow.
Feature flags
tastty-core keeps optional integrations behind features:
crosstermadds conversions from crossterm input types;widgetadds virtual-screen rendering integration through ratatui-related types.
tastty enables widget and crossterm by default and forwards those features
to tastty-core.
tastty-driver has no default features. Its async feature adds
Session::wait_async, a runtime-agnostic future wrapper around the same wait
logic used by Session::wait.