Skip to main content

pi-sync

Sync pi agent config between hosts over rsync, using your existing ssh config for routing (so ~/.ssh/config aliases just work).

pi-sync tinfoil                  # push config + extensions
pi-sync --config laptop          # only models.json and settings.json
pi-sync --pull --all tinfoil     # fetch the host's config back
pi-sync --dry-run --all a b      # preview against two hosts

Install

# the PyPI package is pi-sync-cli; it installs the `pi-sync` command
pipx install pi-sync-cli
pipx install git+ssh://git@github.com/say4n/pi-sync   # from source (needs access)

Requires Python 3.10+. uv tool install works in place of pipx install.

What syncs

Only the declarative parts of the agent dir:

Group Files
--config models.json, settings.json
--extensions extensions/
--auth auth.json — secrets, opt-in, warns on push

--all is --config + --extensions (also the default when no flag is given).

Host-local state is deliberately never touched: sessions/, npm/, models-store.json (regenerated from the pi.dev catalog), ayu/, bin/, trust.json.

Flags

Flag Effect
--all / --config / --extensions / --auth what to sync
--pull host → local instead of local → host
--delete mirror extensions/ exactly (deletes extras on the destination)
--dry-run report changes, copy nothing
-x, --exclude PATTERN skip matching files (repeatable)
--install install pi on hosts that lack it, without prompting
--uninstall remove pi from the host instead of syncing (config is kept)
--local-dir default $PI_CODING_AGENT_DIR or ~/.pi/agent
--remote-dir default ~/.pi/agent
-v / --verbose print each rsync command and its output

Multiple hosts are accepted: pi-sync a b c. Exits non-zero if any host is unreachable or any transfer fails.

Host preflight

Each host gets one ssh probe that reports reachability and pi's location in the same round trip.

If pi is missing, pi-sync hands the terminal to pi's own installer (curl -fsSL https://pi.dev/install.sh | sh), which keeps full control: its prompts (its install/uninstall/do-nothing menu, a Node.js install, a sudo password) work normally, and the sync continues once it exits. pi-sync does not add a confirmation of its own, because the installer already asks. Without a terminal it runs unattended under --install, stays quiet otherwise, and --dry-run never installs anything.

The installer's exit status is not treated as proof: its "do nothing" choice exits 0, so the host is re-probed afterwards and reported honestly.

A host without pi is skipped — copying into a host that has never run pi is not useful and usually fails anyway, since there is no agent directory to copy into. That covers an installer run that installed nothing, a failed install, and a non-interactive run without --install; a skipped host makes the run exit non-zero. After a successful install pi-sync creates the agent directory, because rsync will not create intermediate directories on its own.

The probe checks command -v pi plus the usual install locations (~/.local/bin, ~/.pi/bin, ~/.pi/agent/bin, linuxbrew, homebrew, /usr/local/bin), because a non-interactive ssh session does not source the host's shell init — on a linuxbrew host command -v pi alone misses it.

Uninstalling

--uninstall removes pi from the host instead of syncing. It runs npm uninstall -g --prefix <prefix> @earendil-works/pi-coding-agent, deriving the prefix from where pi actually lives (as the official installer does), then re-probes to confirm the binary is really gone — npm can exit 0 having removed nothing. ~/.pi/agent is deliberately left untouched, since that is your config rather than the CLI.

This exists because the official installer can only uninstall through its interactive menu: its unattended mode always installs or reinstalls. If the uninstall fails, that is usually a managed install (PI_EXPERIMENTAL=1, under <agent dir>/install) — run curl -fsSL https://pi.dev/install.sh | sh on the host and choose u.

Shell completions

Host arguments complete from ~/.ssh/config, following Include directives and skipping wildcard entries:

# bash
_PI_SYNC_COMPLETE=bash_source pi-sync > ~/.pi-sync-complete.bash
echo 'source ~/.pi-sync-complete.bash' >> ~/.bashrc

# zsh
_PI_SYNC_COMPLETE=zsh_source pi-sync > ~/.pi-sync-complete.zsh
echo 'source ~/.pi-sync-complete.zsh' >> ~/.zshrc

# fish (config.fish)
_PI_SYNC_COMPLETE=fish_source pi-sync | source

Writing the script out (rather than eval "$(_PI_SYNC_COMPLETE=bash_source pi-sync)" on every shell start) keeps shell startup fast, since the eval form runs the binary each time. PowerShell works the same way via powershell_source.

Completions are read from the config at completion time, so new hosts appear without regenerating anything.

Caveats

  • settings.json is machine-written by pi (lastChangelogVersion bumps, UI toggles), so two hosts pushing it will overwrite each other's local preferences. Sync it when you change packages, not reflexively — and note the overwritten copy is kept as settings.json.backup on the receiving host.
  • Anything pi-sync overwrites is kept on the destination as <name>.backup, and *.backup is never synced, so those copies stay host-local and never trampoline between hosts. --delete suppresses backups for the mirrored directory, because mirroring means "match exactly" — which also sidesteps an openrsync bug where backing up a file it deletes fails with fchownat: Operation not permitted.
  • Extensions that write runtime files inside their own directory (logs, checkpoints) get those files synced too, and each host's copy is overwritten by whichever side pushed last — exclude them with -x '*/logs/*'.
  • Extension versions are whatever each host has installed; pin them in settings.json (npm:pi-lens@1.2.3) if you need hosts identical.
  • --auth copies API keys in the clear. Prefer OPENCODE_API_KEY (and friends) in the environment where you can.
  • Remote paths go through the host's shell, so ~ expands there as usual.

Development

uv sync
uv run pytest
uv run pi-sync --help

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

pi_sync_cli-0.4.0.tar.gz (25.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

pi_sync_cli-0.4.0-py3-none-any.whl (11.3 kB view details)

Uploaded Python 3

File details

Details for the file pi_sync_cli-0.4.0.tar.gz.

File metadata

  • Download URL: pi_sync_cli-0.4.0.tar.gz
  • Upload date:
  • Size: 25.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.12.13 {"installer":{"name":"uv","version":"0.12.13","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for pi_sync_cli-0.4.0.tar.gz
Algorithm Hash digest
SHA256 9a17f1e25987a9eb01a4c27e4b0bce77465d77bfda76d48bcbf41cc7075b4c6e
MD5 3d32cd6e9e6d4cf2ed276a822c74c291
BLAKE2b-256 4117edf0a784cd4762a4e3716c723e10a965b8ca67b21d6ae650eda9f42c9d7a

See more details on using hashes here.

File details

Details for the file pi_sync_cli-0.4.0-py3-none-any.whl.

File metadata

  • Download URL: pi_sync_cli-0.4.0-py3-none-any.whl
  • Upload date:
  • Size: 11.3 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.12.13 {"installer":{"name":"uv","version":"0.12.13","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for pi_sync_cli-0.4.0-py3-none-any.whl
Algorithm Hash digest
SHA256 b136d1dc3936d713d59b62c9edba78b76f6cd8886898e486f57e3087e53a163b
MD5 702c018075e6ba6a35eb370241191305
BLAKE2b-256 098d944c8f9b5a24b4710c055585441eccd791da2f68987a88b4ff2709b1b768

See more details on using hashes here.

Release history Release notifications | RSS feed

0.5.3

2 files

0.5.2

2 files

0.5.1

2 files

0.5.0

2 files

This release

0.4.0 This release

2 files

0.3.0

2 files

0.2.0

2 files

0.1.0

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page