TTYCast (ttycast v0.1.0)
Copy MarkdownSeekable, compressed terminal recordings for BEAM applications.
TTYCast records terminal output, input metadata, resize events, and custom
semantic events into a self-contained .ttycast file. Recordings are split
into independently compressed chunks with Ghostty terminal keyframes so readers
can seek by timestamp without replaying the whole file.
Writing
TTYCast.write("demo.ttycast", [width: 120, height: 40], fn writer ->
TTYCast.Writer.write(writer, "hello\r\n")
end)Reading
cast = TTYCast.open!("demo.ttycast")
TTYCast.info(cast)
TTYCast.snapshot!(cast, time_ms: 1_000)
TTYCast.stream(cast) |> Enum.to_list()Recording commands
TTYCast.record(["sh", "-lc", "echo hello"], path: "demo.ttycast")See FORMAT.md for the binary container layout.
Summary
Functions
Returns decoded events as a list. Prefer stream/2 for large recordings.
Exports a recording to a supported format.
Exports terminal input/output streams as asciinema v2 JSON lines.
Finds times where plain terminal snapshots contain a string or regex match.
Imports a recording from a supported format.
Imports asciinema v2 JSON lines into a ttycast file.
Returns a compact summary map for a recording.
Returns a collectable sink that writes iodata into the recording.
Opens a recording without decoding chunks eagerly.
Opens a recording or raises.
Reads and decodes one compressed chunk by index entry.
Reads one compressed chunk or raises.
Records a command under a real pseudo-terminal.
Records a command interactively, forwarding the current terminal to the child PTY.
Rebuilds the trailer/footer index from intact chunks.
Returns a Ghostty-rendered terminal snapshot at a timestamp.
Returns a terminal snapshot or raises.
Starts a recording writer.
Streams decoded events lazily from chunks matching the optional time range.
Opens a writer, calls fun, and closes the writer afterwards.
Types
@type event() :: TTYCast.Writer.event()
Functions
@spec events( Path.t() | TTYCast.Cast.t(), keyword() ) :: [event()]
Returns decoded events as a list. Prefer stream/2 for large recordings.
@spec export(Path.t() | TTYCast.Cast.t(), :asciinema, Path.t()) :: :ok | {:error, term()}
Exports a recording to a supported format.
@spec export_asciinema(Path.t() | TTYCast.Cast.t(), Path.t()) :: :ok | {:error, term()}
Exports terminal input/output streams as asciinema v2 JSON lines.
@spec find(Path.t() | TTYCast.Cast.t(), binary() | Regex.t(), keyword()) :: [ %{time_ms: non_neg_integer(), match: binary()} ]
Finds times where plain terminal snapshots contain a string or regex match.
@spec import(Path.t(), :asciinema, Path.t(), keyword()) :: {:ok, TTYCast.Cast.t()} | {:error, term()}
Imports a recording from a supported format.
@spec import_asciinema(Path.t(), Path.t(), keyword()) :: {:ok, TTYCast.Cast.t()} | {:error, term()}
Imports asciinema v2 JSON lines into a ttycast file.
@spec info(Path.t() | TTYCast.Cast.t()) :: map()
Returns a compact summary map for a recording.
@spec into(pid()) :: TTYCast.Sink.t()
Returns a collectable sink that writes iodata into the recording.
@spec open(Path.t() | TTYCast.Cast.t()) :: {:ok, TTYCast.Cast.t()} | {:error, term()}
Opens a recording without decoding chunks eagerly.
@spec open!(Path.t() | TTYCast.Cast.t()) :: TTYCast.Cast.t()
Opens a recording or raises.
@spec read_chunk(Path.t() | TTYCast.Cast.t(), map()) :: {:ok, map()} | {:error, term()}
Reads and decodes one compressed chunk by index entry.
@spec read_chunk!(Path.t() | TTYCast.Cast.t(), map()) :: map()
Reads one compressed chunk or raises.
@spec record( [String.t()] | {String.t(), [String.t()]}, keyword() ) :: {:ok, TTYCast.Recorder.result()} | {:error, term()}
Records a command under a real pseudo-terminal.
@spec record(String.t(), [String.t()], keyword()) :: {:ok, TTYCast.Recorder.result()} | {:error, term()}
Records a command interactively, forwarding the current terminal to the child PTY.
Rebuilds the trailer/footer index from intact chunks.
@spec snapshot( Path.t() | TTYCast.Cast.t(), keyword() ) :: {:ok, binary() | map()} | {:error, term()}
Returns a Ghostty-rendered terminal snapshot at a timestamp.
@spec snapshot!( Path.t() | TTYCast.Cast.t(), keyword() ) :: binary() | map()
Returns a terminal snapshot or raises.
@spec start_writer(keyword()) :: GenServer.on_start()
Starts a recording writer.
@spec stream( Path.t() | TTYCast.Cast.t(), keyword() ) :: Enumerable.t()
Streams decoded events lazily from chunks matching the optional time range.
Opens a writer, calls fun, and closes the writer afterwards.