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
--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.

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.
  • 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.2.0.tar.gz (23.0 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.2.0-py3-none-any.whl (9.6 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: pi_sync_cli-0.2.0.tar.gz
  • Upload date:
  • Size: 23.0 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.2.0.tar.gz
Algorithm Hash digest
SHA256 e14031ca8ca968836bd97469fd1a44c42cc954b409bf0e41541815f80e25d040
MD5 9ac119e617f7eb30855b13eea2bde240
BLAKE2b-256 edd2f118291101f053ccc313fc4d4753721d2597b3bc29ea1e345cbd90d73f30

See more details on using hashes here.

File details

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

File metadata

  • Download URL: pi_sync_cli-0.2.0-py3-none-any.whl
  • Upload date:
  • Size: 9.6 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.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 834e42fc057be5ca7e036bd4a05476a0e87f6d606e556c9f754755c2def6d10a
MD5 542b4cee0bd9f54aa9e17a426f3b789d
BLAKE2b-256 6557f64c4249e1e946b6dfa7426a26ed7f405e76a6a17d7b1c3594197d851dad

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

0.4.0

2 files

0.3.0

2 files

This release

0.2.0 This release

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