MCPcopy Index your code
hub / github.com/cs01/termpair

github.com/cs01/termpair @v1.2.0

Chat with this repo
repository ↗ · DeepWiki ↗ · release v1.2.0 ↗ · + Follow
307 symbols 830 edges 48 files 13 documented · 4% updated 3mo agov1.2.0 · 2026-03-25★ 1,7351 open issues
What it actually does AI analysis from the code graph — generated when you open this
loading…
README

TermPair

View and control remote terminals from your browser with end-to-end encryption

termpair share command

termpair browser view

Why TermPair?

  • Zero-knowledge sharing -- your terminal is end-to-end encrypted (AES-128-GCM). The server is a blind relay that never sees your data.
  • One command to share -- run termpair share, send the link. Anyone with the link watches your terminal live in their browser.
  • Let others type -- viewers can type in your terminal from the browser, or set --read-only to keep them watching.
  • Public or private -- private sessions are encrypted and link-only. Public sessions (--public) are listed on the landing page for anyone to discover and watch.
  • Survive server restarts -- if the server goes down, both sides automatically reconnect and resume where they left off.
  • Single binary, no deps -- one static binary bundles the server, client, and web frontend. No Node, no Python, no Docker required.
  • Works anywhere -- Linux, macOS, Windows. Share any terminal app: your shell, vim, htop, Claude Code, anything with a TTY.

Installation

Quick Install

curl -fsSL https://raw.githubusercontent.com/cs01/termpair/main/install.sh | sh

Installs to ~/.local/bin. Customize with environment variables:

INSTALL_DIR=/usr/local/bin sh    # custom install directory
VERSION=v1.2.0 sh               # specific version

GitHub Releases

Download a prebuilt binary from the releases page. Available for Linux (x86_64, aarch64), macOS (x86_64, Apple Silicon), and Windows (x86_64).

Build from Source

git clone https://github.com/cs01/termpair.git
cd termpair/termpair-rs
cargo build --release
cp target/release/termpair ~/.local/bin/

Usage

Start the server:

termpair serve

Share your terminal:

termpair share

This prints a URL containing a unique terminal ID and encryption key. Share it with whoever you want to give access. Anyone with the link can access your terminal while the session is running.

By default, termpair share runs your $SHELL. The server multicasts terminal output to all connected browsers.

How it Works

┌─────────────────┐                                    ┌─────────────────┐
│                 │    encrypted terminal output        │                 │
│  Terminal       │───────────────────────────────────▶│  Browser(s)     │
│  (termpair      │         ┌───────────────┐          │  (xterm.js +    │
│   share)        │◀────────│  Server       │─────────▶│   Web Crypto)   │
│                 │         │  (blind relay) │          │                 │
│  - forks pty    │    encrypted browser input          │  - decrypts     │
│  - encrypts I/O │         │  never sees   │          │    output       │
│  - manages keys │         │  plaintext    │          │  - encrypts     │
│                 │         └───────────────┘          │    input        │
└─────────────────┘                                    └─────────────────┘

The server is a blind relay -- it routes encrypted WebSocket messages without access to keys or plaintext. The terminal client forks a pty, encrypts all output with AES-128-GCM, and decrypts browser input. Browsers decrypt and render with xterm.js + Web Crypto API.

Encryption

Three AES-128-GCM keys are created per session:

  1. Output key -- encrypts terminal output before sending to the server
  2. Input key -- encrypts browser input before sending to the server
  3. Bootstrap key -- delivered via the URL hash fragment (never sent to the server), used to securely exchange keys #1 and #2

Keys are rotated after 2^20 messages. IVs are monotonic counters to prevent reuse.

The browser must be in a secure context (HTTPS or localhost).

Deployment

NGINX

upstream termpair_app {
  server 127.0.0.1:8000;
}

server {
    server_name myserver.com;
    listen 443 ssl;
    ssl_certificate fullchain.pem;
    ssl_certificate_key privkey.pem;

    location /termpair/ {
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header Host $host;
        proxy_pass http://termpair_app/;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
    }
}

systemd

# /etc/systemd/system/termpair.service
[Unit]
Description=TermPair terminal sharing server
After=network.target

[Service]
ExecStart=/usr/local/bin/termpair serve --port 8000
Restart=on-failure
RestartSec=1s

[Install]
WantedBy=multi-user.target
sudo systemctl daemon-reload
sudo systemctl enable termpair.service
sudo systemctl restart termpair

TLS

Generate a self-signed certificate:

openssl req -newkey rsa:2048 -nodes -keyout host.key -x509 -days 365 -out host.crt -batch

Then pass it to the server:

termpair serve --certfile host.crt --keyfile host.key

CLI Reference

$ termpair serve [OPTIONS]
  -p, --port <PORT>          port to listen on [default: 8000]
      --host <HOST>          host to bind to [default: localhost]
  -c, --certfile <CERTFILE>  path to SSL certificate for HTTPS
  -k, --keyfile <KEYFILE>    path to SSL private key for HTTPS

$ termpair share [OPTIONS]
      --cmd <CMD>     command to run [default: $SHELL]
  -p, --port <PORT>   server port [default: 443]
      --host <HOST>   server URL [default: https://chadsmith.dev/termpair]
  -r, --read-only     prevent browsers from typing
  -b, --open-browser  open the share link in a browser
      --public        public session (no encryption, read-only)

See Also

sharemyclaude -- share your Claude Code session with a browser. Built on termpair, with a public relay server so you can share instantly without self-hosting.

Core symbols most depended-on inside this repo

$id
called by 44
termpair-rs/frontend/static/app.js
remove
called by 26
termpair-rs/src/server/terminal.rs
generate_key
called by 21
termpair-rs/src/encryption.rs
run
called by 15
termpair/share.py
encrypt
called by 13
termpair-rs/src/encryption.rs
toast
called by 11
termpair-rs/frontend/static/app.js
create_reconnect_token
called by 11
termpair-rs/src/server/signing.rs
base64ToBytes
called by 10
termpair-rs/frontend/static/app.js

Shape

Function 241
Method 40
Class 23
Route 2
Enum 1

Languages

Rust46%
TypeScript32%
Python22%

Modules by API surface

termpair-rs/frontend/static/app.js41 symbols
termpair-rs/src/share/aes_keys.rs31 symbols
termpair/share.py25 symbols
termpair-rs/src/encryption.rs20 symbols
termpair-rs/frontend/static/xterm.min.js17 symbols
termpair-rs/src/server/terminal.rs16 symbols
termpair-rs/src/types.rs13 symbols
termpair-rs/src/server/handlers.rs13 symbols
termpair-rs/src/server/signing.rs12 symbols
termpair/server.py10 symbols
termpair-rs/src/server/mod.rs10 symbols
termpair-rs/src/main.rs10 symbols

For agents

$ claude mcp add termpair \
  -- python -m otcore.mcp_server <graph>

⬇ download graph artifact