pi-p2p-sync
Standalone CLI that pulls a Pi agent config from one reachable machine onto another over SSH.
Package details
Security note
Pi packages can execute code and influence agent behavior. Review the source before installing third-party packages.
README
pi-p2p-sync
Pull your Pi agent config from one machine onto another over SSH. Set up a new machine in one command, then keep your machines from drifting apart.
It mirrors ~/.pi/agent from a source machine onto the machine you run it on. Source is authoritative and never touched. Only the machine you run the command on changes, and only after you confirm.
Secrets (API keys, auth tokens) are synced on purpose. They travel only over SSH, machine to machine. This is a plain CLI: no agent, no LLM, nothing in between ever sees your config.
Why
Setting up Pi on a new machine means reinstalling extensions, recreating settings, copying API keys, and hoping you did not miss anything. Over time your two machines drift and behave differently.
pi-p2p-sync makes that one command:
pi-p2p-sync pull desktop
New machine becomes a mirror of desktop. Run it again anytime to re-sync.
Requirements
- Node.js 20 or newer on both machines.
- SSH access from the machine you are setting up to the source machine, already working (key auth, reachable host). pi-p2p-sync does not set up SSH or punch through NAT. If
ssh desktopworks, you are ready. - pi-p2p-sync installed on both machines. The source runs a read-only helper over SSH, so it needs the CLI too.
Install
On both machines:
npm install -g pi-p2p-sync
From source instead:
git clone https://github.com/anh-chu/pi-p2p-sync.git
cd pi-p2p-sync
npm install
npm run build
npm install -g .
Or use the bundled installer with a path or git URL:
bash install.sh https://github.com/anh-chu/pi-p2p-sync.git
Verify:
pi-p2p-sync pull # prints "missing host", which means the CLI is installed
Usage
Set up a new machine
On the new machine, with the source machine reachable as an SSH host:
pi-p2p-sync pull desktop
desktop is any SSH target: a host from ~/.ssh/config, or user@host. The command:
- Asks the source for a list of its config files and their hashes.
- Compares that against what you have locally.
- Prints a plan and waits for your confirmation.
- Mirrors the files, then offers to remove packages that the source no longer has.
After it finishes, restart Pi. Missing extensions and skills install themselves on startup from the synced package list.
Re-sync later
Same command. It only moves what changed since last time.
pi-p2p-sync pull desktop
Preview without changing anything
pi-p2p-sync pull desktop --dry-run
Prints the plan and exits. Writes nothing.
Undo the last pull
pi-p2p-sync undo
Restores every file the last pull changed, from the backup it took before writing.
The confirm step
Before anything is written, you see a plan:
plan -> this machine:
+ 12 new
~ 8 overwrite (3 modified locally !)
- 1 delete
= 4 skip
pkgs: -2 remove (batch)
apply? [y]es [n]o [e]dit selection >
+ newfiles only on the source.~ overwritefiles that differ. The!count is files you changed locally since the last pull. Those are flagged so you do not lose local edits without noticing.- deletefiles removed on the source, removed here too (backed up first).= skipfiles that match or are out of scope.
Choices:
yapply everything in the plan.ncancel, write nothing.epick which locally-modified (!) files to keep. The rest still apply.
After files are applied, if the source dropped any packages you still have, you get a separate prompt to remove them in one batch.
Flags
| Flag | Effect |
|---|---|
--dry-run |
Print the plan, change nothing. |
--yes |
Skip all prompts. For scripts. Applies the plan and removes dropped packages. |
--conflict=mirror |
Default. Source wins on every file. Locally-modified files are flagged but still overwritten unless you skip them with e. |
--conflict=skip-modified |
Keep every locally-modified file, apply the rest. |
--remote-cmd <cmd> |
How to invoke pi-p2p-sync on the source if it is not on the default PATH. |
What gets synced
From ~/.pi/agent on the source:
- Config files (
settings.json,mcp.json,models.json, and the rest). - Secrets:
auth.json,opencode-keys.json, API keys inside config files. AGENTS.md,APPEND_SYSTEM.md.agents/,prompts/,themes/.- Real files and folders under
extensions/andskills/.
What does not get synced
npm/andgit/package installs. These are large and rebuildable. Pi reinstalls them from the synced package list on the next startup.sessions/conversation history, per machine.memory/the memory database, per machine.- Caches, logs, temp files, runtime state.
- Symlinks. Anything that is a symlink is left alone, since the target rarely exists on the new machine.
How it stays safe
- Nothing is written until you confirm.
--dry-runshows you exactly what would happen. - Every overwrite and delete is backed up first, under
~/.pi/agent/.p2p-sync/backups/<timestamp>/.pi-p2p-sync undorestores the most recent one. - A report of each pull is written to
~/.pi/agent/.p2p-sync/last-pull.md. - The source machine is read-only during a pull. A misconfigured new machine cannot push bad config or empty secrets back to your good machine.
- Files with machine-specific paths (your home directory, your Node version) are rewritten for the target machine on the way in. Anything that still cannot be resolved is listed in the report instead of breaking silently.
How it works
pull is a one-way mirror. The source is the source of truth. To make a lasting change, edit on the source machine, then pull on the others.
Transport is SSH only. The source runs pi-p2p-sync serve over your existing SSH connection to hand back its manifest and the requested files. The SSH connection is the only thing that touches your data in transit, which is why secrets can travel safely without a separate encryption layer.
serve manifest and serve send are the host-side commands the client runs over SSH. You do not run them by hand.
Limitations
- One direction only. There is no push and no two-way merge. Edit on the source.
- SSH only. No relay, no NAT traversal. The host must already be reachable.
- Symlinked skills and any skills living outside
~/.pi/agentare not synced yet.
License
MIT