ai-nomad
v0.2.1
Published
Your AI session, anywhere. Continue Claude Code, Codex and Cursor sessions on any machine and in any of the three tools, end-to-end encrypted in your own private GitHub repo.
Maintainers
Readme
ai-nomad
Your AI session, anywhere. · ai-nomad.magnificalabs.dev
Share AI coding sessions between any machine and any AI tool (Claude Code, Codex, Cursor), with no server. Sessions are encrypted on your machine and stored in a private GitHub repo you own.

laptop GitHub (private repo) desktop
┌──────────────┐ encrypt+push ┌──────────────────────┐ pull+decrypt ┌──────────────┐
│ Claude Code │ ─────────────▶ │ meta/<hmac>.enc │ ────────────▶ │ claude --resume
│ Codex │ │ sessions/<hmac>.enc │ │ codex resume │
│ Cursor │ ◀───────────── │ keycheck.enc │ ◀──────────── │ handoff → any AI
└──────────────┘ └──────────────────────┘ └──────────────┘
▲ MCP server (list / search / get_session) works inside all three tools ▲Install
Requires Node ≥ 22.5 and git. The GitHub CLI (gh) is optional but makes setup easier.
1. Create or join your vault (once per machine)
First machine. This creates a private GitHub repo and a new key:
npx ai-nomad init yourname/ai-sessions --createSave the printed nomad1-… key in your password manager.
Every other machine:
npx ai-nomad join yourname/ai-sessions # paste the key when prompted2. Add the plugin to your tools
Each plugin bundles the same three things: the ai-nomad MCP server, commands for listing and continuing sessions, and hooks that pull when a session starts and push when it stops.
| Tool | Install | Then use |
|---|---|---|
| Claude Code | npx ai-nomad install claude | /ai-nomad:sessions, /ai-nomad:continue <id>, /ai-nomad:sync |
| Codex | npx ai-nomad install codexthen /plugins → ai-nomad → Install | $ai-nomad-sessions, $ai-nomad-continue <id>, $ai-nomad-sync (or just ask) |
| Cursor | npx ai-nomad install cursorthen Developer: Reload Window | /ai-nomad-sessions, /ai-nomad-continue <id>, /ai-nomad-sync |
Or run npx ai-nomad install all to do all three. For tool versions without plugin support, npx ai-nomad install codex --manual / cursor --manual writes the MCP server and hook straight into the tool's config instead.
Use
Run these with npx ai-nomad …, or install it once with npm i -g ai-nomad.
ai-nomad push # encrypt + upload new/changed sessions (incremental)
ai-nomad pull # fetch what other machines pushed
ai-nomad list # all sessions from all machines, newest first
ai-nomad search "stripe webhook"
ai-nomad show <id> # transcript as markdown
ai-nomad open <id> # same tool: native resume (claude --resume / codex resume)
ai-nomad open <id> --in claude # other tool: writes .ai-nomad/handoff-<id>.md + prints the command
ai-nomad open <id> --in codex --exec # ...and launches itFrom inside any AI that has the MCP server: "list my sessions from the canmatch project and continue the one about the web build". The AI calls list_sessions, then get_session, and carries on.
How the "any AI" part works
| From → To | How |
|---|---|
| Claude → Claude, Codex → Codex | Native. The original JSONL is restored into ~/.claude/projects/… or ~/.codex/sessions/…, with the working directory remapped to this machine, and resumed with the tool's own resume command. |
| Anything → anything else | Handoff. A markdown transcript gets the opening request plus as much recent history as fits a budget, with tool calls condensed. Use it through the MCP get_session tool or a .ai-nomad/handoff-*.md file. |
| → Cursor | Always a handoff. Cursor's chat history lives in an internal SQLite DB that isn't safe to write from outside. |
Security model
- End-to-end encryption. Every file is AES-256-GCM, with keys derived via HKDF from one random 256-bit key. The key is generated locally and is never pushed anywhere. GitHub (or anyone who gets the repo) sees only ciphertext.
- Nothing readable in the repo. File names are keyed HMACs of
(tool, sessionId), so they don't reveal tools, projects or titles. Commits are authored asai-nomad <ai-nomad@localhost>with messages likesync 3 sessions from 1a2b3c4d. - Tamper-evident. Each blob's repo path is bound in as GCM associated data, so blobs can't be swapped or renamed undetected. A
keycheck.encfile rejects a wrong key up front. - Secret scrubbing. Before encryption, common credentials are redacted from transcripts: API keys, GitHub/GitLab/Slack/Stripe/npm tokens, AWS key IDs, JWTs, private keys, and
user:pass@in URLs. This is defense in depth in case a handoff goes to another provider or the key leaks. Turn it off with"redact": falsein~/.config/ai-nomad/config.json. - Visibility check.
ai-nomad init/joinrefuse a public repo unless you pass--allow-public. - Local files. The key is stored in
~/.config/ai-nomad/key(mode 600). You can supply it viaAI_NOMAD_KEYinstead.
What's not hidden: the number of sessions, their approximate sizes, and when you sync.
Things to know
- Repo growth. Each update to a session stores a new gzipped blob. Run
ai-nomad compactoccasionally to squash history to one commit; other machines handle that automatically on their next pull. - Hook pushes are debounced. At most one push per session every 10 minutes, plus a final push on Claude's
SessionEnd. Pushes run in the background so they never slow the tool down. - Conflicts. A session continued on machine B is never overwritten by an older copy from machine A. The newest
updatedAtwins. - Size limit. Sessions whose encrypted blob exceeds ~45 MB keep the normalized transcript (handoff still works) but drop the raw file (no native resume).
- Codex native resume writes the rollout file and
session_index.jsonlentry. Very new Codex builds that index threads only in their SQLite state may not list it in the picker.codex resume <id>and handoff still work.
Support
Questions or problems: [email protected]
