API Reference
Public surface for @vibecook/avocado-sdk
and the avo CLI.
Pre-alpha — APIs may change before 1.0.
Subpaths
Import only what you need. Peer dependencies are optional at the package level — install peers for the subpaths you use.
import { createPTYSessionManager } from '@vibecook/avocado-sdk'; import { LocalPTYSession } from '@vibecook/avocado-sdk/node-pty'; import { createUDSServer } from '@vibecook/avocado-sdk/transport-ipc'; import { PTYMeshBridge } from '@vibecook/avocado-sdk/transport-truffle'; import { AvocadoProvider, TerminalSurface } from '@vibecook/avocado-sdk/react';
Core @vibecook/avocado-sdk
Flagship entry — re-exports the core session-management surface and shared types. No required peer dependencies.
PTYSessionManager
Owns a set of IPTYSessions and registered IPTYTransports. Routes I/O by session source so local, IPC, and remote sessions share one API.
Factory for a new session manager instance.
Register sessions, attach transports, subscribe to lifecycle events (sessionDiscovered, sessionLost, output, exit, resized, focusChanged).
TerminalService
Tracks virtual terminals attached to sessions and enforces one-active-terminal-per-session. Multiple passive viewers can share a shell; only one accepts input.
Create a terminal service bound to a session manager.
Implementation of the TerminalService interface — create/list terminals, set active, resize, mode switching.
Terminal store sync
Sync virtual-terminal layout state across processes or devices via a store backend.
Implements ITerminalStoreSync — terminal entries, modes, and change events.
import { createPTYSessionManager, PTYSessionManager, createTerminalService, TerminalServiceImpl, createTerminalStoreSync, getOriginalId, WS_PTY_MESSAGE_TYPES, } from '@vibecook/avocado-sdk';
Types @vibecook/avocado-sdk/types
Shared types, interfaces, and protocol constants. Largely a type surface with a few runtime utilities (IDs, buffers, message guards).
Core interfaces
Running PTY contract: id, dimensions, write/resize/kill, and events — output, resized, exit, focusChanged. Implemented by local, IPC, and proxy sessions.
Symmetric viewer/owner contract. Viewer: sendInput, sendResize, sendKill, sendFocus, subscribe. Owner: sendOutput, sendResized, sendSessionEnded, sendFocusChanged.
Abstract base with shared lifecycle and event-emitter logic. Constants: DEFAULT_COLS, DEFAULT_ROWS.
Abstract host API for the React layer — Electron IPC, WebSocket, or any shim that surfaces sessions and terminals to the renderer.
Session & transport types
| Type | Notes |
|---|---|
SessionSource | 'local' | 'ipc' | 'ws' |
TransportType | Transport discriminator |
SessionMetadata | Base / IPC / WS metadata union |
PTYSessionState | Lifecycle state of a session |
RemoteSessionAnnounce | Shape published in mesh sync store |
ConnectionState / HandshakeState | IPC / wire connection phases |
Virtual terminal types
| Type | Notes |
|---|---|
TerminalInfo | UI terminal record |
TerminalMode | Active vs passive input mode |
TerminalType | Terminal kind / renderer class |
CreateSessionOptions / CreateTerminalOptions | Creation option bags |
Protocol
Wire-format discriminators shared across IPC and mesh transports (pty:input, pty:output, pty:resize, …). Guards: isWSPTYMessageType, isWSOutputPayload, isWSInputPayload, etc.
Utilities
| Export | Role |
|---|---|
generateSessionId / generateLocalSessionId / generateCliSessionId | ID helpers |
createNamespacedId / parseNamespacedId / getOriginalId | Namespaced session IDs |
getSocketDir / getSocketPath | Default IPC socket paths |
CircularOutputBuffer / createOutputBuffer | Output buffering when disconnected |
Node PTY …/node-pty
Local PTY source. Peer dependency: node-pty.
Implements IPTYSession. Emits output, exit, resized into the session manager. Spawn via static LocalPTYSession.spawn(spawnFn, spawnConfig, options).
| Type | Notes |
|---|---|
PTYSpawnFunction | Adapter over node-pty’s spawn |
PTYSpawnConfig | command, args, cwd, cols, rows, env, … |
LocalPTYSessionOptions | Metadata passed into the session |
IPty | Minimal node-pty process surface |
import { LocalPTYSession, type PTYSpawnFunction } from '@vibecook/avocado-sdk/node-pty'; import { spawn as ptySpawn } from 'node-pty'; const spawnFn: PTYSpawnFunction = (opts) => ptySpawn(opts.command, opts.args, opts); const session = LocalPTYSession.spawn( spawnFn, { command: '/bin/bash', args: [], cwd: process.cwd(), cols: 120, rows: 32, }, { command: 'bash', cwd: process.cwd() } ); sessionManager.registerSession(session);
Transport IPC …/transport-ipc
Unix Domain Socket (macOS/Linux) or Named Pipe (Windows). Bridges a CLI process to a long-running host so sessions appear with source: 'ipc'. No peer deps — uses built-in Node networking. Messages are msgpack-encoded with the same WS_PTY_MESSAGE_TYPES discriminators as the mesh.
Exports
Listen on a socket path; accept CLI connections and dispatch namespaced handlers.
Wire the UDS server into the session manager — announce sessions, multiplex I/O, handle connection lifecycle.
Per-connection IPTYTransport over the message bus.
import { createPTYSessionManager } from '@vibecook/avocado-sdk'; import { createUDSServer, createPTYIPCBridge, } from '@vibecook/avocado-sdk/transport-ipc'; const sessionManager = createPTYSessionManager(); const udsServer = createUDSServer(); udsServer.start({ socketPath: '/tmp/my-app.sock' }); const bridge = createPTYIPCBridge(sessionManager); bridge.initialize(udsServer); // Windows named pipe example: // socketPath: '\\\\.\\pipe\\my-app'
Transport Truffle …/transport-truffle
Cross-device terminal session sync over Tailscale via @vibecook/truffle. Peer: @vibecook/truffle@^0.6.0 (Peer-first API, RFC 022). Live routing uses Peer handles; durable ULIDs are for SyncedStore discovery only.
Architecture
Key exports
One per peer; holds a Peer handle; implements IPTYTransport. Namespace: PTY_NAMESPACE.
Transport lifecycle for online peers (not gated on wsConnected). Primary key peer.ref; secondary index by durable ULID for store reconciliation.
Session discovery via truffle’s SyncedStore — per-device slices of { sessions, updatedAt }, keyed by durable ULID. Default store id: DEFAULT_PTY_STORE_ID.
Owner-side forwarders that copy output / resized / exit from a local session to a viewer’s transport.
Orchestrator: ties bridge + sync store + relays together and dispatches owner-side PTY commands. Optional IPeerNotifier for UI side-channels.
import { createMeshNode } from '@vibecook/truffle'; import { createPTYSessionManager } from '@vibecook/avocado-sdk'; import { PTYMeshBridge, PTYSyncStore, RemoteSessionService, type IPeerNotifier, } from '@vibecook/avocado-sdk/transport-truffle'; const node = await createMeshNode({ appId: 'my-app', deviceName: 'my-device', onAuthRequired: (url) => { /* surface to UI */ }, }); const sessionManager = createPTYSessionManager(); const bridge = new PTYMeshBridge({ node, sessionManager }); const syncStore = new PTYSyncStore({ node }); const notifier: IPeerNotifier = { sessionFocusChanged: () => {}, remoteSessionsChanged: () => {}, }; const service = new RemoteSessionService({ node, sessionManager, bridge, syncStore, notifier, }); await bridge.initialize(); await service.enable();
Wire format
Every PTY message on the mesh shares:
{
type: 'pty:input' | 'pty:output' | 'pty:resize' | …,
sessionId: string,
// type-specific fields
}
JSON-serialized to a Buffer, sent via peer.send('pty', buf). On receive, truffle decodes at the NAPI boundary — msg.payload is already a plain object; msg.from is an interned Peer (WhoIs-verified Tailscale attribution).
CREATE_SESSION → CREATE_FAILED). Primary device election / focus conflict resolution (cooperative last-write-wins).React …/react
Components, hooks, and pluggable terminal engines. Peers: react, xterm, @xterm/addon-fit. Optional Ghostty VT path: restty.
Context
Root provider. Pass a TerminalBackend that exposes the host process’s session/terminal APIs (Electron IPC, custom WebSocket, etc.). Hook: useAvocadoBackend().
import { AvocadoProvider, TerminalSurface } from '@vibecook/avocado-sdk/react'; export function App() { return ( <AvocadoProvider backend={electronBackend}> <TerminalSurface sessionId={sid} terminalId={tid} engine="restty" isActive /> </AvocadoProvider> ); }
Components
Headless interactive terminal bound to a PTY session. Owns behavior only — engine lifecycle, PTY I/O, auto-fit, click-to-focus, active/passive resize gating. Zero visual opinion: style from your own CSS via data attributes ([data-active], [data-ready], [data-engine]). renderError overrides error UI, actionsRef exposes imperative focus/fit/write, children render as overlay chrome.
Legacy styled wrapper over TerminalSurface (baked-in dark chrome). Prefer TerminalSurface — styled demo UI (cards, grids) lives in apps/playground and apps/ghostty as copyable recipes.
Engine-neutral view contract. Engines: 'xterm' (default) and 'restty' (libghostty-vt). Factory: createTerminalView(engine, options). Wire via <TerminalSurface engine="restty" /> or useTerminalCore({ engine }).
Hooks
| Hook | Returns |
|---|---|
usePTYSessions() | Live session list; optional SessionSourceFilter |
useTerminals() | Virtual terminal state |
useTerminalGrid(options?) | Headless grid selection/settings; pluggable layout fn, maxTerminals (default defaultGridLayout, 9) |
useResizeHandle(options) | Drag-to-resize prop getters (getHandleProps('e'|'s'|'se')) with pointer capture + min-size clamping |
useTerminalSnapshot(options) | Polled screen lines + cursor of a backend headless terminal |
useTerminalAPI() | Imperative terminal operations |
useRemoteSessions() | Mesh remote session offers |
useTerminalCore() | Low-level core state/actions for custom renderers |
View / core types
TerminalEngineId, TerminalView, TerminalViewCreateOptions, TerminalViewFactory, TerminalCoreState, TerminalCoreActions, GridLayout, ResizeHandleDirection, TerminalSnapshot.
CLI @vibecook/avocado
General-purpose terminal session wrapper. Syncs to a host (e.g. the playground) over UDS / Named Pipe and can participate in mesh when the host has truffle enabled.
npm i -g @vibecook/avocado avo --help
Usage
avo # wrap $SHELL avo claude # wrap claude CLI avo -- htop # -- separates avo flags from command avo --no-sync bash # run without host connection avo -s /path/to/sock bash # custom socket path
On startup, avo prints a TUI banner with the wrapped command, session id, and sync status. Type exit or press Ctrl+D to leave.
How it works
| Piece | Role |
|---|---|
| PTYHost | Spawns the command in a pseudo-terminal via node-pty |
| Router | Multiplexes I/O between PTY, stdin/stdout, and sync |
| SyncClient | Connects to host: handshake, heartbeat, output buffer (up to 1MB when disconnected) |
| RealTerminal | Active/passive mode for focus management |
avo silently retries in the background and buffers output until a connection is established.avo --help for the authoritative flag list — the CLI is still evolving in pre-alpha.