UniPty v1 · PTY platform

The runtime-neutral PTY contract for Node, Bun, and Deno.

One Core API for pseudo-terminals. Bring your own native substrate — node-pty, Bun.Terminal, or @sigma/pty-ffi — through developer-selectable, replaceable Backends. Support claims come only from the release evidence catalog, never from metadata.

Read the docs View verified tuples

Quick start

Acquire a ready Backend, hand it to Core, spawn a shell with a structured argv — no string commands, no implicit shell.

import { UniPty } from "unipty";
import { createNodePtyBackend } from "@unipty/backend-node-pty";

// 1. Acquire a ready Backend (one-time, asynchronous).
const backend = await createNodePtyBackend();

// 2. Core accepts only a structurally ready Backend.
const unipty = new UniPty({ backend });

// 3. Spawn: argv is non-empty, argv[0] is the executable.
const pty = unipty.spawn(["/bin/sh", "-i"], {
  terminal: { cols: 80, rows: 24 },
});

// 4. Consume Terminal Text (or Terminal Bytes with "bytes").
for await (const chunk of pty.stream({ encoding: "utf8" })) {
  process.stdout.write(chunk);
}

// 5. Write with boolean readiness; drain when Core says pause.
if (!pty.write("echo hello\r")) {
  await pty.drain();
}

// 6. Observe process exit independently of the stream.
const { exitCode, signal } = await pty.exited;

The same Core contract runs on every official Backend route. Swapping routes means swapping the Backend you acquire — nothing else changes.

Why UniPty

One contract, three runtimes

Core owns streams, bootstrap buffering, UTF-8 conversion, backpressure, common errors, and lifecycle. Your code stays runtime-neutral across Node, Bun, and Deno.

Backends are replaceable

The native substrate — node-pty, Bun.Terminal, @sigma/pty-ffi — lives behind a Backend Endpoint seam. Persistent or remote hosts arrive as Backends, not a second plugin lifecycle.

Evidence, not promises

Metadata declares targets; it never claims support. Only a full-suite conformance pass against an installed package on an exact runtime/platform tuple becomes verified in the release catalog.

Official Backend routes

Package Substrate Runtime Provenance
@unipty/backend-node-pty node-pty (via @lydell/node-pty prebuilds) Node Third-party native addon — not a native Node API
@unipty/backend-bun Bun.Terminal Bun Built-in Bun API (1.3.13+ Linux/macOS, 1.3.14+ Windows)
@unipty/backend-deno-sigma__pty-ffi @sigma/pty-ffi Deno Rust portable-pty over Deno FFI, vendored

Which tuples are actually verified for the current release? See the compatibility catalog.