Live Coding Together
A native VS Code extension for real-time collaborative pair programming. It synchronizes
editor contents with a Yjs CRDT, renders every collaborator's live cursor, selection and
name tag, and ships an in-editor live text chat — all over a single WebSocket relay.
Features
- Conflict-free editing (CRDT) — text is synced through
yjs + y-websocket, so
concurrent edits merge without clobbering each other.
- Remote cursors & selections — each collaborator gets a colored caret, an optional
selection highlight, name tag and overview-ruler marker.
- Live chat — sidebar chat with sender name, per-user color, timestamp and unread badge.
- Session status bar —
🟢 Live: 3 Users | Room: 8F3K-9PZL.
- Commands —
Start Session, Join Session, Leave Session, Copy Room ID, Focus Chat.
- Self-hosted relay — a tiny Node.js server (
server/index.js) with an optional
localtunnel public URL so the host can share without port forwarding.
Architecture
src/
extension.ts Activation, commands, wiring, session lifecycle
syncEngine.ts Yjs document, WebSocket provider, local/remote edits, presence, chat
decorations.ts Remote cursor + selection decoration types (one per user/color)
chatView.ts WebviewView sidebar (room + participants + chat), unread badge
statusBar.ts Status bar item + tooltip
types.ts Shared types, origins, color palette
util/diff.ts Minimal prefix/suffix text diff for local edits
util/editor.ts VS Code offset/range helpers, Yjs delta -> editor edits
server/
index.js y-protocols relay: sync + awareness + chat routing, health, tunnel
How sync works
- Local edits are captured with
workspace.onDidChangeTextDocument. The changed range is
reduced to a single minimal {start, deleteCount, insertText} diff and applied to the
room's Y.Text inside a transaction tagged live-collab:local.
- Remote transactions are observed on the
Y.Text. The Yjs delta is converted into
surgical VS Code edits (editor.edit) so the document is patched in place instead of
being replaced — this keeps local cursor positions and avoids full-document rewrites.
- A
mirrorText guard plus an applyingRemote flag break the local⇄remote feedback loop.
- Cursor/selection is published on the Yjs awareness channel; chat lives in a shared
Y.Array inside the same document, so both ride the same relay connection.
Prerequisites
- Node.js 18+
- VS Code 1.85+
npm
1. Install
npm install
2. Start the relay server
In a separate terminal (this is what everyone connects to):
npm run server
# or a custom port:
node server/index.js --port 1234
Health check: http://localhost:1234/health.
To expose it publicly without port forwarding:
npm run server:tunnel
This prints a wss://… URL. Share that as the server URL instead of ws://localhost:1234.
(localtunnel is optional; ngrok or a reverse proxy also works.)
3. Compile
npm run compile
# or watch mode while developing:
npm run watch
4. Run via Extension Development Host (F5)
- Open this folder in VS Code.
- Press F5 (Run → Start Debugging). The
Run Extension launch config compiles first
and then opens a second VS Code window titled [Extension Development Host].
- In that window, open the Live Coding Together icon in the Activity Bar.
5. Test collaboration
- In the Extension Development Host, run Live Collab: Start Session
(
Ctrl/Cmd+Shift+P → Live Collab: Start Session). Accept the server URL, enter a name.
The generated Room ID is copied to your clipboard and the status bar turns green.
- Start a second Extension Development Host (press F5 again, or duplicate the window)
representing a peer — or have a teammate open the built
.vsix.
- In the second window run Live Collab: Join Session and paste the Room ID.
- Open the same file in both windows. Type in one — the text, cursor and name tag appear in
the other. Open the sidebar and exchange chat messages; the unread badge appears when the
sidebar is hidden.
Packaging (optional)
npm install -g @vscode/vsce
vsce package
Install the resulting live-collab-0.1.0.vsix in any VS Code via
Extensions → … → Install from VSIX.
Configuration
| Setting |
Default |
Description |
liveCollab.serverUrl |
ws://localhost:1234 |
Relay WebSocket URL |
liveCollab.userName |
(empty) |
Display name (prompted if empty) |
liveCollab.userColor |
(empty) |
Hex color; auto-assigned from name if empty |
liveCollab.maxChatHistory |
500 |
Retained chat messages per session |
Security notes
- The relay has no authentication and rooms are keyed only by a guessable-ish ID. Treat it
as a trusted-network / dev tool. For production, terminate TLS at a reverse proxy (
wss://)
and add a params token check in server/index.js.
- Only the currently active file is bound per client, but every shared file's
Y.Text lives in
the room document, so opening the same file on both sides is what makes edits visible.