cclink: Accountless Claude Code Session Handoff over DHT

Claude Code sessions are machine-local by default. cclink breaks that constraint: publish your session from one machine, pick it up on another — no accounts, no relay, no signup tokens.

Why I Built This

Claude Code sessions are tied to the machine where they start. Moving between a desktop and a laptop — or handing off to a remote machine — breaks the session. Claude Code's native /remote-control feature handles terminal-to-mobile UI control, but it depends on Anthropic's infrastructure. It doesn't solve the "which box runs the session" problem for developers who want to stay local-first.

The goal was a tool that handles session handoff with no accounts, no central relay, and no signup tokens. Your PKARR key is your identity. The Mainline DHT is the rendezvous. What crosses the wire is age-encrypted ciphertext — the session ID, hostname, and project path are all inside the encrypted payload blob; the DHT sees only opaque bytes. You own the keys, you own the transport, you see exactly what crosses the wire.

Machine A                              Machine B
$ cclink                               $ cclink pickup
Session: abc12345 in ~/myproject       Resuming session abc12345...
Published!                             claude --resume abc12345
  Run on another machine:
  cclink pickup

How It Works

cclink grabs the current Claude Code session ID, encrypts it with your Ed25519/PKARR keypair, signs the record, and publishes it to the Mainline DHT as a PKARR SignedPacket. On another machine, cclink pickup resolves, verifies, decrypts, and launches claude --resume automatically.

                   publish (signed + encrypted)
  ┌──────────┐    ─────────────────────────────►    ┌───────────────┐
  │  cclink   │       PKARR SignedPacket            │   Mainline    │
  │  (Rust)   │                                     │     DHT       │
  │           │    ◄─────────────────────────────    │               │
  └──────────┘       pickup (verify + decrypt)      └───────────────┘

Dual Ed25519 signatures — a PKARR packet signature for DHT authentication and an inner signature over canonical JSON — protect against forgery at either layer. The security model explicitly addresses DHT-node eavesdropping (age-encrypted payload), forged records (dual signatures), replay attacks (TTL plus optional burn-after-read), and key compromise (Argon2id+age encryption at rest with memory-zeroing after use).

Three encryption modes cover different scenarios. Self mode (default) encrypts to your own keypair so only you can pick up from another machine with the same key. Shared mode encrypts to a specific recipient's public key for handing off to a colleague. PIN mode uses Argon2id to derive a shared secret from a passphrase — no key exchange needed, just a shared PIN of at least eight characters. Modes combine: --burn --pin creates a PIN-protected, single-use handoff.

What I Learned

The hardest multi-machine setup problem turned out to be session data locality. cclink transfers the session ID, not the session data — Claude Code stores sessions in ~/.claude/projects/ and claude --resume needs those files locally. The tool's documentation makes this explicit and walks through syncing options (Syncthing, rsync, NFS, Tailscale/SSH). It's a deliberate scope boundary: cclink handles the handoff credential; moving local files is a separate concern that existing tools already solve.

The design tension between usability and security shows up clearly in the passphrase contract. All passphrase input is non-interactive-first: environment variable, file (mode 0600), or file descriptor. The --passphrase <value> argument is rejected outright because it would leak via ps output. That constraint forced better defaults from the start rather than as an afterthought.

cclink and cipherpost share a cryptographic stack — PKARR, age, Argon2id, dual signatures. The distinction is at the payload level: cclink encodes a Claude Code session ID with hostname and project path; cipherpost encodes typed cryptographic material (SSH keys, X.509 certs, PGP keys, generic secrets) with an explicit acceptance step and signed receipts. Two different workflows, one shared trust model.


Your key, your transport, your Claude session — on any machine.