···1818binary (which embeds jj-cli with a custom tandem backend) to read and write
1919objects over Cap'n Proto RPC.
20202121-The server is the **point of origin** — it's where git operations happen
2222-(`jj git push`, `jj git fetch`, `gh pr create`). The orchestrator/teamlead
2323-runs these on the server to ship code upstream. The tandem server is the source
2424-of truth, with GitHub as a mirror.
2121+The server is the **point of origin** — it typically runs on a VM/VPS as a
2222+long-running service. It's where git operations happen (`jj git push`,
2323+`jj git fetch`, `gh pr create`). The orchestrator/teamlead runs these on the
2424+server to ship code upstream. The tandem server is the source of truth, with
2525+GitHub as a mirror.
25262627## Installation
2728···119120120121See `docs/design-docs/workflow.md` for the full picture. Summary:
121122122122-1. **Orchestrator** sets up server: `tandem serve --listen 0.0.0.0:13013 --repo /srv/project`
123123+1. **Orchestrator** sets up server on a VM/VPS: `tandem serve --listen 0.0.0.0:13013 --repo /srv/project`
1231242. **Agents** init workspaces: `tandem init --tandem-server=host:13013 ~/work/project`
1241253. **Agents** use stock jj commands: write files, `tandem new -m "feat: add auth"`, etc.
1251264. **Agents** see each other's files: `tandem cat -r <other-commit> src/auth.rs`
+3
ARCHITECTURE.md
···1717## Core model
18181919- Server hosts a **normal jj+git colocated repo** (uses jj's Git backend)
2020+- Server is a **long-running service**, typically on a VM/VPS — it holds the canonical repo. If lost without backups, the data is gone (unless mirrored to GitHub via `jj git push`).
2021- Client keeps **working copy local** (real files on disk)
2122- Client store calls are remote via Cap'n Proto RPC
2223- Backend/OpStore/OpHeadsStore trait implementations route to server
···8182- `jj git fetch` — pull upstream changes into the server's repo
8283- `jj git push` — push agents' work to GitHub
8384- `gh pr create` — create PRs from the server
8585+8686+The server needs git credentials (SSH keys or tokens) for GitHub access.
84878588Agents never touch git. The server is the single point of contact with
8689the outside world. The orchestrator SSHes to the server (or runs commands
+52-42
README.md
···1313```
14141515tandem is a single binary that embeds [jj](https://jj-vcs.com). The server
1616-hosts a jj+git repo. Agents on remote machines get transparent read/write
1717-access over Cap'n Proto RPC. Every stock jj command works — `log`, `new`,
1818-`diff`, `file show`, `bookmark`, `describe` — because tandem implements
1919-jj-lib's `Backend`, `OpStore`, and `OpHeadsStore` traits as RPC stubs.
1616+hosts a jj+git repo — typically on a VM or VPS as a long-running service.
1717+Agents on remote machines get transparent read/write access over Cap'n Proto
1818+RPC. Every stock jj command works — `log`, `new`, `diff`, `file show`,
1919+`bookmark`, `describe` — because tandem implements jj-lib's `Backend`,
2020+`OpStore`, and `OpHeadsStore` traits as RPC stubs.
20212122## Why
2223···105106tandem serve --listen 0.0.0.0:13013 --repo ~/project
106107```
107108109109+For production use, run this on a VM/VPS — see [Deployment setups](#deployment-setups) below.
110110+108111### Connect agents
109112110113```bash
···159162160163## Deployment setups
161164162162-### Local: multiple terminals
165165+### Local: multiple terminals (for testing)
163166164164-The simplest setup. Server and agents on the same machine, different
165165-directories.
167167+The simplest setup for trying tandem out. Server and agents on the same
168168+machine, different directories. Not how you'd run it for real work — see
169169+Remote machines below.
166170167171```bash
168172# Terminal 1 — server
···177181cd /tmp/agent-b && tandem log # sees agent A's commit
178182```
179183180180-Good for trying things out. No network setup, no containers.
184184+### Remote machines: sprites.dev / exe.dev / SSH
185185+186186+The typical production setup. Server on a VPS/VM, agents on separate machines.
187187+188188+```bash
189189+# VPS — server
190190+tandem serve --listen 0.0.0.0:13013 --repo /srv/project
191191+192192+# Machine A — agent A (e.g. sprites.dev sandbox)
193193+# Copy the binary over, or build on the remote machine
194194+scp target/release/tandem agent-a-host:/usr/local/bin/
195195+ssh agent-a-host
196196+ export TANDEM_SERVER=server-host:13013
197197+ tandem init ~/work
198198+ cd ~/work
199199+ # ... write code, commit with tandem new ...
200200+201201+# Machine B — agent B (e.g. exe.dev VM)
202202+scp target/release/tandem agent-b-host:/usr/local/bin/
203203+ssh agent-b-host
204204+ export TANDEM_SERVER=server-host:13013
205205+ tandem init --workspace=agent-b ~/work
206206+ cd ~/work
207207+ tandem log # sees agent A's commits
208208+ tandem file show -r <change-id> src/auth.rs # reads agent A's files
209209+```
210210+211211+Requirements:
212212+- Server port (default 13013) must be reachable from agent machines
213213+- No TLS yet — use SSH tunnels or VPN for untrusted networks
214214+- The `tandem` binary is ~30MB, statically linkable, no runtime deps
181215182216### Docker: 3 agents on a shared network
183217···228262This simulates cross-machine communication. Each container has its own
229263filesystem, its own network identity, and connects to the server by DNS name.
230264Tested — see `qa/v1/cross-machine-report.md`.
231231-232232-### Remote machines: sprites.dev / exe.dev / SSH
233233-234234-Server on one machine, agents on others.
235235-236236-```bash
237237-# Machine 1 — server (your laptop, a VPS, etc.)
238238-tandem serve --listen 0.0.0.0:13013 --repo ~/project
239239-240240-# Machine 2 — agent A (e.g. sprites.dev sandbox)
241241-# Copy the binary over, or build on the remote machine
242242-scp target/release/tandem agent-a-host:/usr/local/bin/
243243-ssh agent-a-host
244244- export TANDEM_SERVER=server-host:13013
245245- tandem init ~/work
246246- cd ~/work
247247- # ... write code, commit with tandem new ...
248248-249249-# Machine 3 — agent B (e.g. exe.dev VM)
250250-scp target/release/tandem agent-b-host:/usr/local/bin/
251251-ssh agent-b-host
252252- export TANDEM_SERVER=server-host:13013
253253- tandem init --workspace=agent-b ~/work
254254- cd ~/work
255255- tandem log # sees agent A's commits
256256- tandem file show -r <change-id> src/auth.rs # reads agent A's files
257257-```
258258-259259-Requirements:
260260-- Server port (default 13013) must be reachable from agent machines
261261-- No TLS yet — use a tunnel (e.g. `ssh -L`) for untrusted networks
262262-- The `tandem` binary is ~30MB, statically linkable, no runtime deps
263265264266### Claude Code: multi-agent with tandem
265267···391393392394## Known limitations
393395394394-- **No TLS** — connections are plaintext. Use SSH tunnels for untrusted networks.
395395-- **No auth** — anyone who can reach the port can read/write the repo.
396396+- **No TLS** — connections are plaintext. For production on a VPS, use SSH tunnels (`ssh -L`) or a VPN.
397397+- **No auth** — anyone who can reach the port can read/write the repo. On a VPS, firewall the port and use SSH tunnels for access.
396398- **No static binary yet** — requires glibc 2.39+. Use matching distro or build locally.
397399- **fsmonitor conflict** — if your jj config has `fsmonitor.backend = "watchman"`,
398400 pass `--config=fsmonitor.backend=none` to tandem commands.
399401- **Description-based revsets** — `description(exact:"...")` may not work for
400402 cross-workspace queries. Use change IDs from `tandem log` instead.
403403+404404+## Running in production
405405+406406+- **Back up the server repo directory** — it's the source of truth. If lost without backups, data is gone (unless mirrored to GitHub via `jj git push`).
407407+- **Use a process manager** (systemd, supervisord, etc.) to keep `tandem serve` running.
408408+- **Git credentials on the server** — the server needs SSH keys or tokens for `jj git push` / `jj git fetch` to GitHub.
409409+- **Monitor disk space** — all agent objects (files, trees, commits) land on the server.
410410+- **Firewall the port** — no auth means network-level access control is your only defense. SSH tunnels or VPN.
401411402412## Project structure
403413
+8-8
docs/design-docs/workflow.md
···99## Roles
10101111**Server (point of origin):**
1212+- Runs on a VM/VPS as a persistent service
1213- Hosts the canonical jj+git repo
1314- Runs `tandem serve`
1415- Is where git operations happen (`jj git push`, `jj git fetch`, `gh pr create`)
···2526### 1. Setup
26272728```bash
2828-# On the server
2929+# On the server (typically a VM/VPS)
2930mkdir /srv/project && cd /srv/project
3031jj git init
3132jj git remote add origin git@github.com:org/project.git
···8990outside world. It's where the orchestrator makes decisions about what
9091ships and what doesn't.
91929292-## Future: tandem as source of truth
9393+## Tandem as source of truth
93949494-The architecture supports a future where the tandem server is THE canonical
9595-store, and GitHub is just a mirror:
9595+The tandem server is the canonical store. GitHub is a mirror.
96969797-- Tandem server holds the complete history
9797+- The server holds the complete history — all agent objects live there
9898- `jj git push` mirrors to GitHub for CI, code review, external visibility
9999- Other teams interact via GitHub as usual
100100-- But the agents and orchestrator work entirely through tandem
100100+- Agents and the orchestrator work entirely through tandem
101101102102-No architecture change is needed — it's the same code, just a different
103103-trust model. The server already has everything.
102102+Back up the server repo directory. If it's lost without backups, the data
103103+is gone (unless you've been pushing to GitHub regularly).