Collaborative terminal control plane

One terminal session. Many participants. Every byte multiplexed.

uterm creates, transports, secures, shares, records, replays, and arbitrates terminal sessions across browsers, WebSockets, telnet, SSH, local PTYs, and remote workers. xterm.js is the screen; uterm is the rest of the iceberg.

DLE/STX framing DeckMux presence MCP-native Durable Objects

Demo reel

13 recorded demos — control channel, DeckMux, MCP, fan-out — concatenated.

1280x720 85.2s All demos →

Recorded uterm sessions — drag a slider, click play.

Each card below is a real recording produced by scripts/demos/record_*.py in the provide-uterm repo. mp4 + asciinema, whichever reads best for the feature.

All demos →

Workers expose. The hub multiplexes. Everyone attaches.

A single WebSocket carries every byte and every control frame. Three roles in the dance — and the protocol is the same whether you run it on your laptop, at the edge, or inside an agent.

  1. Workers expose a PTY

    A local or remote worker spawns a process behind a UNIX PTY. The HijackableMixin makes the session safe to hand off at checkpoints — no torn state mid-command.

  2. TermHub multiplexes the stream

    The hub routes raw terminal bytes and JSON control frames through one WebSocket using DLE/STX framing. Leases, RBAC, presence, and annotations all live inline.

  3. Browsers, agents, fleets attach

    xterm.js, AI agents over MCP, and fan-out controllers attach as additional participants. Each gets the same snapshot view and obeys the same lease.

Seven packages, one control plane.

Python and TypeScript live in the same workspace. The same DLE/STX framing runs on the server, in the browser, at the edge, and inside the MCP server an AI agent uses.

provide-uterm Core brain

ANSI engine, screen state, DeckMux logic, control-channel framing — shared by every other package.

Python 3.11+pyteaiosqlite
provide-uterm-server Reference hub

TermHub, FastAPI surface, RBAC + lease management, tunnels, gateway. CLI entry: `uterm`, `uterm-server`.

FastAPIuvicornwebsockets
provide-uterm-cloudflare Edge hub

Cloudflare Worker + Durable Object adapter. One DO per session, SQLite persistence for chat and annotations.

WorkersDurable ObjectsSQLite
provide-uterm-client SDK + AI

HTTP/WS client, telnet/SSH/WS transports, the `uterm-mcp` FastMCP server with 21 tools for agents.

httpxFastMCPMCP
provide-uterm-platform Agent tier

PTY connector, PAM auth, LD_PRELOAD capture, External Management Tier (`uterm-manager`).

PTYPAMLD_PRELOAD
provide-uterm-frontend Browser UI

Vanilla TypeScript on top of xterm.js. Renders the DeckMux UI, presence chips, and annotation overlays.

TypeScriptxterm.jsVanilla CSS
provide-uterm-app App shell

Packaging shell that bundles the frontend and server for distribution.

shellbundle

Run a hub. Attach a worker. Open the browser.

uterm ships a reference TermHub, a TypeScript browser frontend, a Python client SDK, and an MCP server for AI agents. Pick the surface that matches your harness — they all speak the same control channel.

Open the full quickstart →
git clone https://github.com/provide-io/provide-uterm.git
cd provide-uterm
uv sync --group dev
npm ci && npm run build:frontend

Run TermHub on 127.0.0.1:27780

uv run uterm-server \
  --bind 127.0.0.1:27780 \
  --auth dev \
  --config scripts/uterm-server.example.toml

.mcp.json (project) or ~/.claude.json (global)

{
  "mcpServers": {
    "uterm": {
      "command": "uv",
      "args": ["--directory", "/abs/path/to/provide-uterm", "run", "uterm-mcp"]
    }
  }
}

Deploy the Durable-Object backend

cd packages/provide-uterm-cloudflare
npx wrangler deploy
# Each session is a single Durable Object
# with attached SQLite for chat + annotations.

One stream. One brain. Many shells.

Inline control, not side-channels

Most terminal proxies juggle multiple WebSockets for I/O, control, and metadata. uterm multiplexes everything onto one stream — Python server and TypeScript browser agree on the same framing, byte for byte.

Collaboration is the substrate

DeckMux treats observers as first-class. Presence, role-based leases, queued keystrokes, and shared annotations live in the protocol, not bolted on top.

Same brain, three deployments

Run the reference TermHub on your own server, deploy it to Cloudflare Durable Objects at the edge, or embed the core library inside an AI agent. The session model doesn't change.

Three commands cover the local loop.

Serve the hub. Attach a client. Expose the MCP surface for AI agents. Every surface in uterm reduces to one of these three.

$ uv run uterm-server
$ uv run uterm connect ws://127.0.0.1:27780/term --role viewer
$ uv run uterm-mcp --transport stdio