Runtime And Web

std.pty

Hosted pseudoterminal child processes for interactive CLIs and terminal programs.

When To Use std.pty

In Zerolang, use std.pty for hosted child processes that need terminal semantics instead of plain pipes. PTY children are useful for interactive CLIs, REPLs, shells, editors, pagers, and tools that change behavior when stdout is a terminal.

Runnable today:

APIReturnNotes
std.pty.spawn(command)ProcChildStarts an argv-style command attached to a pseudoterminal.
std.pty.spawnIn(command, cwd)ProcChildStarts a PTY child in a hosted working directory.
std.pty.spawnInEnv(command, cwd, env)ProcChildStarts a PTY child with a working directory and newline-separated KEY=value environment bindings.
std.pty.spawnArgs(program, args, cwd, env)ProcChildStarts a program path plus newline-separated argv entries attached to a pseudoterminal.
std.pty.valid(child)BoolReports whether the handle currently names an open child slot.
std.pty.childValid(child)BoolAlias for std.pty.valid.
std.pty.running(child)BoolPolls the PTY child without blocking.
std.pty.wait(child)ProcStatusWaits for process exit and returns its status.
std.pty.kill(child)BoolSends the child a termination signal on supported hosts.
std.pty.interrupt(child)BoolSends the child an interrupt signal on supported hosts.
std.pty.close(child)BoolCloses the handle and remaining terminal resources.
std.pty.pid(child)i32Returns the hosted process id for the child, or 0 when unavailable.
std.pty.read(child, buffer)Maybe<usize>Nonblocking read from the PTY master into caller storage.
std.pty.write(child, bytes)Maybe<usize>Nonblocking write to the PTY master.
std.pty.resize(child, columns, rows)BoolSets the child terminal size on supported hosts.

Metadata labels:

  • effects: proc
  • allocation behavior: child handles may keep runtime-owned PTY output buffers while wait drains terminal output
  • target support: hosted targets with the proc capability
  • error behavior: spawn helpers return an invalid ProcChild handle on failure; read and write return null when no bytes can be transferred
  • ownership notes: ProcChild values name runtime-owned process slots; call wait when process status matters and close when the handle is no longer needed

Example

pub fn main(world: World) -> Void raises {    let child: ProcChild = std.pty.spawnArgs("printf", "hello pty\n", ".", "")    let resized: Bool = std.pty.resize(child, 80_usize, 24_usize)     var storage: [64]u8 = [0_u8; 64]    var saw_output: Bool = false    var attempts: usize = 0    while attempts < 20_usize && !saw_output {        let read: Maybe<usize> = std.pty.read(child, storage)        if read.has {            let bytes: Span<u8> = std.io.written(storage, read.value)            saw_output = std.str.contains(bytes, "hello pty")        }        if !saw_output {            let slept: Bool = std.time.sleep(std.time.ms(10))        }        attempts = attempts + 1_usize    }     let status: ProcStatus = std.pty.wait(child)    if resized && saw_output && std.proc.succeeded(status) {        check world.out.write("pty ok\n")    }    let closed: Bool = std.pty.close(child)}

Design Notes

std.pty returns the same ProcChild handle shape used by std.proc, but the underlying child is connected to a pseudoterminal master. PTY output is a single terminal byte stream: stderr is merged by the terminal, and std.pty.read reads from that stream. Targets without process support, including Windows hosts until their process runtime is implemented, reject PTY helpers before code generation. For short-lived programs, drain the PTY with std.pty.read before wait; some hosts report the terminal as closed once the child exits.

Use std.proc.spawnChild* for programs where separate stdout and stderr pipes matter. Use std.pty.spawn* for programs where terminal behavior matters.