npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

pi-config-sync

v0.3.0

Published

Sync your ~/.pi/agent config across machines through a private git repo — with hard guards that keep secrets out.

Readme

pi-config-sync

npm CI

Securely sync your ~/.pi/agent configuration across machines through a git remote — automatically, with hard guards that keep secrets out. It is a pi package and keeps the repository in place (~/.pi/agent is the repo) so its history stays transparent.

Install

pi install npm:pi-config-sync

Quickstart

On the first machine, run /gitsync init. With authenticated GitHub CLI (gh auth login), it detects your account, creates a private pi-agent-config repository, commits the allowed configuration, and pushes it.

Without gh, first create a private remote yourself, then run:

/gitsync init [email protected]:you/pi-agent-config.git

On each additional machine, run /gitsync link (with gh) or /gitsync link <remote-url>. It fetches the remote configuration. A differing local allowed file is moved to <file>.local-backup; it is never deleted, and linking refuses to touch a directory that already has its own git history. Run /reload afterwards; local-only allowed files are committed and pushed by the next sync.

That is the whole setup — from here on, syncing is automatic.

How it works

session start    → auto-sync (rate-limited, default every 5 min across sessions)
                   ensure ignore rules → commit allowlisted changes → fetch
                   → fast-forward or rebase → push
                   → notifies you to /reload when remote changes were pulled
session shutdown → best-effort commit + push (next start reconciles the rest)

Machine-local settings

settings.json uses a git clean/smudge filter: portable settings are committed, while each machine retains its own selected top-level values. By default this is lastChangelogVersion; machine values stay in your live settings file (mirrored to .git-sync/settings.machine.json) and are absent only from committed blobs. On an existing repository, the first sync after upgrading creates a one-time commit that strips those keys from the committed blob and normalizes JSON formatting — the live settings file is unchanged.

The filter is fail-open: a checkout on a machine without pi-config-sync still works, but its machine-local values are not stripped until the package runs again. A newly linked machine gets its sidecar as pi writes its local settings.

The filter script runs under the Node.js that runs pi. When pi ships as a single bundled executable (for example through mise), that executable cannot run the script, so the package uses the first node found on PATH instead and falls back to a disabled filter with a warning. Set nodePath in git-sync.jsonc to pin a specific Node.js binary; the git filter configuration is corrected on the next sync.

Commits look like pi config: auto-sync from <hostname>. Concurrent pi sessions coordinate through a pid-liveness lock, subagent child processes never sync, and a diverged repo aborts the rebase and asks you to resolve manually — nothing is ever forced.

Commands

| Command | Description | | --- | --- | | /gitsync init [name\|owner/name\|url] | Create and connect the first-machine repository | | /gitsync link [name\|owner/name\|url] | Connect another machine | | /gitsync status | Show repository and tracked-secret status | | /gitsync sync | Commit, fetch/rebase, and push | | /gitsync push | Commit and push without pulling | | /gitsync pull | Fetch and integrate remote changes |

Security model

This package uses an allowlist, not a broad config-directory upload.

What syncs

| Path | Contents | | --- | --- | | settings.json | Model defaults, theme, installed package list — committed with machine-local keys stripped | | AGENTS.md | Your global agent instructions | | extensions/, chains/, prompts/, themes/, skills/ | Your custom resources | | .gitignore, git-sync.jsonc | The sync policy itself | | extraPaths entries | Anything safe you add explicitly |

Nothing outside the allowlist ever syncs — new files are ignored by default. Subdirectories of allowed directories sync at any depth, with two exceptions that sync and /gitsync status warn about: a directory that is itself a git repository (a cloned extension) is skipped, so remove its inner .git to sync its files; and a path whose name matches the denylist below (such as extensions/token-counter/) is skipped, so rename it.

What never syncs

| Path / pattern | Why | | --- | --- | | auth* (auth.json) | API keys and OAuth tokens | | *token*, *secret*, *credential*, *.env*, *.local.json | Anything named like a secret | | sessions/, state/, .git-sync/ | Local history and machine state | | logs/ at any depth | Runtime logs, including permission audit/debug logs; retained locally | | npm/, git/, bin/, node_modules | Installed packages — pi reinstalls them from settings.json |

The policy is enforced four ways — a managed allowlist .gitignore, .git/info/exclude, a post-stage hard guard that refuses additions or changes to denied paths, and a push guard that checks the committed tree and outgoing history — so force-staging a denied path does not bypass the commit guard. Deletions remain allowed for cleanup. It never force-pushes.

Ignore rules do not untrack existing files. Use git rm --cached -- <path> to stop tracking a log while retaining the local file. A later deletion does not remove that log from earlier commits: the push guard also checks commits not reachable from locally known origin remote-tracking refs, including on initial and shutdown pushes. Unpushed history containing denied paths must be cleaned before retrying. The package does not rewrite history or revoke exposed credentials. These are path-based checks, not a content secret scanner.

Git commands operate only on the agent directory's own repository — GIT_CEILING_DIRECTORIES stops git from ever discovering a parent repository (such as dotfiles in $HOME), and sync refuses to run until ~/.pi/agent/.git itself exists. GitHub CLI calls are account-level (gh api user, gh repo view/create) and never modify repository contents. Use a private repository. When gh can identify a public GitHub remote, the package warns; it does not block because no credentials are synced.

Configuration

Create ~/.pi/agent/git-sync.jsonc:

{
  "autoSyncIntervalMinutes": 5,
  "includeHostname": true,
  "extraPaths": ["my-safe-directory"],
  "warnOnPublicRemote": true,
  "machineLocalSettings": ["lastChangelogVersion"],
  "nodePath": "/usr/local/bin/node"
}

Unsafe extra paths (secrets, cache names, absolute paths, or ..) are rejected. Set includeHostname to false to omit the machine hostname from automatic commit messages. machineLocalSettings replaces the default list when set; it accepts top-level keys only, and [] disables stripping (the filter still normalizes committed JSON formatting). Useful candidates include shellPath, externalEditor, npmCommand, sessionDir, and trackingId. nodePath is optional and only needed when pi runs as a bundled executable and Node.js is not on PATH, or to pin a specific interpreter for the settings.json filter.

Conflicts and uninstall

On a sync conflict, rebase is aborted and the repository is left untouched for manual resolution:

cd ~/.pi/agent
git status
git pull --rebase

Remove the package with pi remove npm:pi-config-sync. Your local repository and remote remain until you delete them yourself.

If migrating from a hand-rolled extensions/git-sync.ts, delete that file first to avoid duplicate /gitsync registration.

Onboarding flow inspired by opencode-synced.

Alternatives

  • pi-git-sync — manual-first /sync with interactive conflict handling, including agent-assisted merges and force-push / hard-reset options.
  • pi-sync-config — background sync through a separate staging clone, with settings.json machine-key stripping, SSH-only remotes, and fast-forward-only pulls.

pi-config-sync differs from both: your agent directory itself is the repository (transparent history, no copy step), sync is fully automatic, onboarding can create the private repo through gh, and no destructive git operation exists in any code path. All three register different commands and can coexist.

Releases

Tags matching v* publish automatically through the included GitHub Action using npm trusted publishing (OIDC) — no registry tokens exist anywhere in the pipeline. Every release carries a provenance attestation linking the tarball to its exact source commit, verifiable on the npm package page.