pi-bridge

Transparent filesystem bridge that makes pi run natively on a remote machine over SSH

Package details

package

Install pi-bridge from npm and Pi will load the resources declared by the package manifest.

$ pi install npm:pi-bridge
Package
pi-bridge
Version
0.2.6
Published
May 4, 2026
Downloads
110/mo · 110/wk
Author
zeflq
License
MIT
Types
package
Size
68.6 KB
Dependencies
0 dependencies · 0 peers

Security note

Pi packages can execute code and influence agent behavior. Review the source before installing third-party packages.

README

pi-bridge

Transparent filesystem bridge that makes pi run natively on a remote machine — no internet required on the remote, no tools to install beyond Node.js.

Pi runs on your local machine (needs internet for auth and Claude API). Your project lives on a remote Linux machine. pi-bridge intercepts all of pi's filesystem calls and redirects them over SSH to a tiny HTTP server running on the remote. Pi thinks it's running locally — it finds AGENTS.md, skills, context files, and git state natively, without knowing they're remote.

Prerequisites

  • Node.js ≥ 18 on the local machine
  • Node.js on the remote machine
  • SSH access to the remote machine with key-based auth (no password prompt)
  • pi installed locally

Installation

npm install -g pi-bridge

Usage

Use pii exactly like pi, adding --ssh to point at your remote project:

# Absolute path
pii --ssh user@host:/root/projects/my-app

# With SSH alias (configured in ~/.ssh/config)
pii --ssh myserver:/root/projects/my-app

# Tilde path (expanded by remote shell)
pii --ssh user@host:~/projects/my-app

Everything works natively — pi discovers AGENTS.md, skills, and context files on the remote without any extra flags or extensions.

Updating

npm update -g pi-bridge

How It Works

Local machine                          Remote (Linux)
─────────────────────────────          ──────────────────────
pii (bin/pii.js)
  └─ node --require preload.js pi
       ├─ upload server bundle via SSH
       ├─ start HTTP server on remote
       │    → prints PORT:TOKEN:PID to stdout
       ├─ SSH port forward localhost:PORT
       ├─ create fake local dir:
       │    /tmp/pi-bridge/root/projects/my-app
       ├─ process.chdir(fakeLocalCwd)
       ├─ strip --ssh from process.argv
       ├─ patch fs.*  (sync + promises)     remote/index.js
       └─ patch child_process.*               listens on 127.0.0.1:PORT
                                              validates token
pi loads — unaware of bridge               restricts to remoteCwd
  fs.readFileSync(...)  ──GET──→           reads real remote files
  fs.readdirSync(...)   ──GET──→           ← returns data
  spawn('git', ...)     ──SSH──→           runs on remote
  → finds AGENTS.md ✓
  → finds skills ✓
  → git branch in footer ✓

What Gets Patched

API Covered
fs sync — read, write, stat, readdir, mkdir, rm, copy, rename, realpath, access, watch
fs.promises — all async equivalents
fs/promises module (ES module static imports)
child_process.spawn / spawnSync — runs in remote cwd via SSH
fs.watch / fs.watchFile — polls remote via HTTP (git branch updates)

Security

Layer Protection
Loopback only HTTP server binds 127.0.0.1 — not reachable from the network
SSH tunnel All HTTP traffic encrypted end-to-end
Random token 32-byte random token required on every request
Path restriction Server rejects paths outside remoteCwd (403)
Token in stdout Token never appears in ps aux args

Development

git clone https://github.com/zeflq/pi-bridge
cd pi-bridge
npm install

Test against a real remote without installing pi:

SSH_TARGET=user@host:/root/projects/my-app npm run dev

Run tests:

npm test

Troubleshooting

Command failed: ssh … syntax error near unexpected token Your SSH alias requires BatchMode=yes. Add to ~/.ssh/config:

Host myserver
  BatchMode yes

Files show as empty / ENOENT The fake local directory (/tmp/pi-bridge/…) is intentionally empty — all reads go to the remote. If you see ENOENT, the bridge may not have started correctly. Check that Node.js is available on the remote (node --version).

Branch name not updating The footer polls .git every second. Switching branches from outside a pi session is reflected within ~1s. If the branch is stuck, restart pii.

Windows: pii can't find pi Ensure the OpenSSH client is enabled (Windows 10+: Settings → Apps → Optional Features → OpenSSH Client) and pi is installed globally (npm install -g pi).