How Reinstate syncs coding-agent sessions
Reinstate uses per-agent adapters, structural path remapping, client-side age encryption, immutable snapshots, and an encrypted remote manifest to move vendor-native sessions without becoming a coding harness.
┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│ Claude Code │ │ Codex │ │ Future agents│ ...
│ ~/.claude │ │ ~/.codex │ │ (roadmap) │
└──────┬──────┘ └──────┬──────┘ └──────┬──────┘
│ │ │
▼ ▼ ▼
┌──────────────────────────────────────────────────┐
│ Agent Adapters (per tool) │
│ locate · parse · exclude secrets · project IDs │
└──────────────────────┬───────────────────────────┘
▼
┌──────────────────────────────────────────────────┐
│ Normalizer │
│ structural path tokens · project IDs │
│ credential hard-excludes │
└──────────────────────┬───────────────────────────┘
▼
┌──────────────────────────────────────────────────┐
│ Encryption (age / scrypt passphrase recipient) │
│ client-side only — remote never sees plaintext │
└──────────────────────┬───────────────────────────┘
▼
┌──────────────────────────────────────────────────┐
│ Sync Engine │
│ immutable snapshots · encrypted JSON manifest │
│ conflict detection · atomic restore + backup │
└──────────────────────┬───────────────────────────┘
▼
┌──────────────────────────────────────────────────┐
│ Backends: R2 · S3-compatible (Phase 1) │
└──────────────────────────────────────────────────┘
Design principles
- Local-first — agents remain the sole executors of sessions; Reinstate relocates files, it does not re-interpret or re-run them.
- Zero-knowledge remote — ciphertext on object storage, apart from
keyring.v1.json, which is plaintext by design, holds no usable key, and names the account and its enrolled devices. - Native resume is same-vendor — restore puts bytes where
claude --resume/codex resumealready know how to read them. - Cross-agent handoffs are explicit — never silently
translated.
rein handoffstarts a new destination session. translate native transcripts between vendors. - Fail-safe conflicts — never overwrite; fork and surface.
- Adapter isolation — format churn in one agent cannot break others.
- Normalize configuration intent — later configuration adapters render a canonical desired-state profile into verified native harness formats.
- Secrets stay local — profiles contain references, never raw API keys, OAuth tokens, cookies, or vendor credential stores.
Pipeline stages
1. Adapters
Each adapter knows:
| Concern | Example (Claude Code) |
|---|---|
| Root path | ~/.claude/projects/ |
| Session format | Append-only JSONL |
| Project key | Munged absolute path directory name |
| Resume entry | claude --resume [id] |
| Exclude globs | plugins, caches, credentials |
Adapters implement a small Go interface under internal/adapter/.
Configuration adapters (roadmap)
Session and configuration support are separate. Later configuration adapters will import, diff, and render supported MCP servers, skills/instructions, hooks/loops, plugins, marketplaces, and safe settings:
native config ↔ configuration adapter ↔ Reinstate desired state
↕ encrypted sync
another device
They must preserve unrelated settings, report unsupported/lossy mappings, preview and back up changes, write atomically, and fail closed on unverified schemas. See Universal agent configuration.
2. Path normalizer (internal/pathmap)
The make-or-break feature for Windows ↔ macOS dual setups:
- Store the released portable tokens
${HOME}and${REPO:<id>}. - Keep the lower-level
${WORK:<alias>}primitive explicitly unwired until configuration, adapter integration, and compatibility tests ship. - On push: rewrite recognized structural path fields → tokens
- On pull: rewrite tokens → this machine’s absolute paths
- Maintain a canonical project ID (git remote + name, or user alias) mapped to per-device roots so munged slugs / hashes recompute correctly
- Do not rewrite arbitrary prose, prompts, tool output, or unknown fields
3. Encryption (internal/crypto)
- Default: age passphrase encryption
- Enter the same passphrase on every device; no keyfile is copied or stored
- File modes:
0600for secrets,0700for config dirs
4. Sync engine (internal/sync)
- Versioned local sync state stored as atomic JSON
- Immutable, UUID-addressed encrypted snapshots
- Encrypted remote JSON manifest with conditional ETag updates
- Streamed full-snapshot transfer with authenticated metadata, size, and SHA-256 validation
- Full snapshots in Phase 1; chunking and append-aware deltas are roadmap work
statusanddiffcurrently require access to the remote manifest
5. Restore path
- Pull ciphertext → decrypt
- Path-rewrite into local layout
- If target exists: copy to
~/.reinstate/backups/<timestamp>/ - Atomic write (temp + rename)
- Refuse or warn if agent process holds the file open (liveness check)
What is explicitly not synced
See the security model. Defaults exclude:
auth.json, OAuth/credential stores- Plugin caches /
node_modules/ venvs - Machine-local logs
- User-defined globs
Future configuration sync carries non-secret declarations and secret references, never vendor auth stores or whole tool directories.
Why not CRDTs / real-time collab?
Dominant pattern is sequential multi-device use (desktop by day, laptop by night). Last-writer-wins with conflict detection and safe forks matches reality without tripling complexity.
Tech stack
| Layer | Choice | Why |
|---|---|---|
| Language | Go | Single static binary, cross-compile, proven by peers |
| Crypto | age | Passphrase UX + auditability |
| Storage | S3-compatible first | R2 free tier; rclone-style backends later |
| Local state | Versioned JSON | Small, inspectable, atomically replaced |
| Remote index | Encrypted JSON manifest | Conditional updates and conflict detection |
Related diagrams
| Asset | Description |
|---|---|
| 01_landscape.svg | Agent scope vs state portability |
| 02_demand_timeline.svg | Demand signals on vendor trackers |
| 03_traction.svg | GitHub traction landscape |
| 04_market.svg | Market context |
| 05_architecture.svg | MVP architecture |
Package layout
cmd/reinstate/ # CLI entrypoint (install as reinstate + rein)
internal/
adapter/ # per-agent adapters
config/ # local config + path_map
crypto/ # age encryption
pathmap/ # portable path rewriting
sync/ # manifest, push/pull, conflicts
backend/ # R2/S3-compatible
docs/ # human docs
testdata/ # golden fixtures (per adapter)