Turn any Claude Code session into a live pair-programming session.
Pair-Claude wraps the Claude Code CLI in a pseudo-terminal, adds a tiny web server, and lets your teammates watch and type into the same session — right from their browser.
$ pair-claude
[pair-claude] ready · share with: \share (server idle on :8765)
> \share
[pair-claude] share URL (read-write): http://simon-laptop.tail.ts.net:8765/s/a1b2c3...
[pair-claude] (copied to clipboard)
[pair-claude] viewer joined (1 connected)
Your colleague opens the link, sees a live terminal with a statusbar, and can type alongside you. That's it. No screen-share lag, no "can you scroll up?", no waiting for someone to share their screen.
You're knee-deep in an investigation. Claude is helping you trace a bug. A colleague on Slack says "can I look at what you're seeing?"
With a regular screen share, they watch passively. With Pair-Claude, they join your terminal — full read/write access, real-time, zero setup. Both of you talk to Claude, both of you see the output, both of you can steer.
┌─────────────────────────────┐
│ Your Terminal │
│ (pair-claude wraps claude)│
└──────────┬──────────────────┘
│ PTY
┌──────┴──────┐
│ Broadcast │──── Web Server (:8765)
│ Hub │ │
└─────────────┘ ┌────┴─────┐
│ Browser │ colleague's xterm.js terminal
└──────────┘
- Single binary. No Docker, no Node, no runtime dependencies (besides
claudein your PATH). - Cross-platform. macOS, Linux, Windows 10/11. Native PTY on each (Unix PTY / ConPTY).
- Tailnet-native. Designed for Tailscale networks. Auto-discovers your MagicDNS hostname. No TLS needed — Tailscale encrypts end-to-end.
- Instant replay. Late joiners see the last 64 KB of terminal output — enough context to jump right in.
- Zero config. Start it, share the link, done.
# From source (requires Go 1.22+)
go install github.com/dxfrontier/pair-claude/cmd/pair-claude@latest
# Or clone and build
git clone https://github.com/dxfrontier/Pair-Claude.git
cd Pair-Claude
go build -o pair-claude ./cmd/pair-claude# Start a shared Claude session
pair-claude
# Auto-share on startup (copies URL to clipboard — just paste!)
pair-claude --auto-share
# Pass arguments to claude as usual
pair-claude --model sonnet
pair-claude --resumeInside the session, use backslash commands:
| Command | Description |
|---|---|
\share |
Generate a share URL — read-write (copies to clipboard) |
\share --readonly |
Generate a read-only URL (alias: \share -r) |
\revoke |
Revoke all tokens, disconnect all viewers |
\status |
Show active share info and client count |
\help |
List available commands |
With --auto-share, the share URL is generated before Claude starts and automatically copied to your clipboard. You just paste it to your colleague — no need to type any commands:
$ pair-claude --auto-share
[pair-claude] ready · share with: \share (server idle on :8765)
[pair-claude] share URL copied to clipboard — just paste!
If the clipboard isn't available (e.g. headless server), the URL is printed to stderr instead.
- Type
\sharein your running session - Send the URL to your colleague (it's also copied to your clipboard automatically)
- They open it in any browser — instant live terminal with statusbar
Multiple colleagues can connect simultaneously. Everyone sees the same output, everyone can type. You'll see [pair-claude] viewer joined (N connected) in your terminal when someone connects.
Want someone to observe without being able to type?
> \share --readonly
[pair-claude] share URL (read-only): http://simon-laptop.tail.ts.net:8765/s/f9e8d7...
Read-only viewers see the full live terminal but their keyboard input is silently dropped. Read-write and read-only links use separate tokens — revoking invalidates both.
- Type
\revoketo kill the share and disconnect all clients - Or just exit Claude normally — the server shuts down cleanly
- Tokens auto-expire after 8 hours (configurable via
PAIR_TOKEN_TTL)
Pair-Claude exposes a local HTTP API for automation — Claude Code hooks, scripts, Slack bots, you name it.
# Generate a share token and get the URL
curl -X POST http://localhost:8765/api/share
# → {"token":"a1b2c3...","url":"http://..."}
# Revoke the active token
curl -X POST http://localhost:8765/api/revoke
# → {"status":"revoked"}
# Check status
curl http://localhost:8765/api/status
# → {"active":true,"clients":2,"url":"http://..."}Auto-share every session by adding a hook to .claude/settings.json:
{
"hooks": {
"SessionStart": [
{
"command": "curl -s -X POST http://localhost:8765/api/share | jq -r .url"
}
]
}
}All configuration via environment variables. Sensible defaults — you probably don't need to change anything.
| Variable | Default | Description |
|---|---|---|
PAIR_PORT |
8765 |
Web server port |
PAIR_HOSTNAME |
(auto) | Override hostname in share URL |
PAIR_TOKEN_TTL |
8h |
Token lifetime |
PAIR_REPLAY_BYTES |
65536 |
Replay buffer size (bytes) |
PAIR_CLAUDE_BIN |
claude |
Path to Claude binary |
PAIR_BIND |
0.0.0.0 |
Bind address |
- Trust boundary = your Tailnet. If someone can reach the port, they're on your network.
- Token-protected URLs. 32 random bytes, hex-encoded, timing-safe comparison. Protects against accidental access, not determined attackers on the same network.
- No TLS. Tailscale already encrypts everything end-to-end.
- Tokens are ephemeral. In-memory only, gone when the process exits.
- Read-write by default.
\sharegives full access — pair programming means both people drive. Use\share --readonlyfor observers.
make build # current platform
make build-all # all platforms
# Individual targets
make build-linux-amd64
make build-linux-arm64
make build-mac-amd64
make build-mac-arm64
make build-windowsOutputs go to dist/.
cmd/pair-claude/ Entry point, lifecycle, goroutine wiring
pty/ Platform PTY abstraction (Unix + Windows ConPTY)
broadcast/ Hub (pub/sub) + ring buffer for replay + viewer events
server/ HTTP server, WebSocket, Control API, embedded frontend
control/ Input parser for \-commands
config/ ENV var handling
tailscale/ Hostname auto-discovery
internal/rawmode/ Platform raw-mode for stdin
internal/clipboard/ Platform clipboard copy
The frontend is a single HTML file with vendored xterm.js — no npm, no build step, no CDN. Everything is embedded in the binary via go:embed.
Built by dxfrontier — we help teams ship faster with Claude Code and AI-assisted development.
- 🐛 Bug or feature idea? Open an issue
- 💬 Question or show-and-tell? Start a discussion
- 🔒 Security report? See SECURITY.md
- 🤝 Want to contribute? See CONTRIBUTING.md
Built with Claude, for people who pair with Claude.