pi-proxy-router
Per-model and auth-flow proxy routing for pi with session commands (/proxy, /noproxy, /allproxy) and dedicated proxy-router.json rules
Package details
Install pi-proxy-router from npm and Pi will load the resources declared by the package manifest.
$ pi install npm:pi-proxy-router- Package
pi-proxy-router- Version
1.2.2- Published
- Sep 10, 2026
- Downloads
- 624/mo · 26/wk
- Author
- leench
- License
- MIT
- Types
- extension
- Size
- 51.7 KB
- Dependencies
- 2 dependencies · 2 peers
Pi manifest JSON
{
"extensions": [
"./index.ts"
]
}Security note
Pi packages can execute code and influence agent behavior. Review the source before installing third-party packages.
README
pi-proxy-router
Per-model and auth-flow proxy routing extension for the Pi coding agent. Route each model and in-session OAuth flow through its own proxy (SOCKS5 / HTTP) with per-session toggles — no provider config changes required.
See CHANGELOG.md for release compatibility and upgrade notes.
Features
- Per-model rules: match
provider/modelpatterns (*wildcard), each model gets its own proxy or direct connection - Per-provider auth rules: route in-session OAuth login, token exchange, refresh, and device-code requests by provider
- Multiple protocols:
socks5h://,http://,https://proxies, ordirectto force a direct connection - Dedicated config: rules are read first from
~/.pi/agent/proxy-router.jsonor project.pi/proxy-router.json, with automatic mtime-based reload; legacysettings.jsonrules remain supported - Startup flag:
pi --noproxydisables all proxy rules - Session commands:
/allproxy <url>— force Pi HTTP(S) traffic and all models through one proxy (session-only, nothing persisted)/noproxy [on|off]— disable/restore rules/proxy [provider/model]— show current proxy status (including environment variables)
- Works for subagents: background children may load this extension; foreground children still inherit the parent process's endpoint fallback even when ambient extensions are disabled
Install
# Global install (~/.pi/agent/extensions/)
mkdir -p ~/.pi/agent/extensions/pi-proxy-router
cd ~/.pi/agent/extensions/pi-proxy-router
# copy this package's files (index.ts, socks-dispatcher.ts, package.json) here
npm install
Then run /reload in pi, or restart — you should see [proxy-router] loaded in the startup log.
Project-local install: put it in
.pi/extensions/pi-proxy-router/(requires trusting the project first).
Or install as a pi package:
pi install npm:pi-proxy-router
Compatibility and upgrade
1.2.1supports the Undici 8 Dispatcher used by Pi 0.85.x while retaining compatibility with the Undici 7 Dispatcher.- If Pi exits with
handler.onHeaders is not a function, update the extension and restart Pi; existing proxy configuration does not need to change. - The unreleased routing changes also cover all model API types and foreground subagents; see
CHANGELOG.mdfor details.
Configuration
Use a dedicated config file: global ~/.pi/agent/proxy-router.json, or project .pi/proxy-router.json. Project rules override the same keys from the global file; global rules provide defaults. A dedicated file may use models / auth at the root, and the wrapped proxy-router form is also accepted:
{
"models": {
"openai-codex/*": "socks5h://127.0.0.1:7890",
"openai/*": "socks5h://127.0.0.1:7890",
"opencode-go/gpt*": "socks5h://proxy.example.test:7890",
"opencode-go/deepseek*": "direct",
"opencode-go/glm*": "direct"
},
"auth": {
"openai-codex": "socks5h://127.0.0.1:7890"
}
}
For migration, legacy global/project settings.json entries under proxy-router are still read, and the old model-proxy key is also supported. They are lower-priority fallbacks in this order: legacy global settings.json → legacy project settings.json → dedicated global config → dedicated project config.
Rule syntax
- models key:
provider/model-pattern,*matches any characters (e.g.openai-codex/gpt*,opencode-go/*) - auth key: provider id (e.g.
openai-codex), matched only against Pi's known auth endpoints - value:
- Proxy URL:
socks5h://(recommended, remote DNS resolution),socks5://(normalized to socks5h),http://,https:// direct: explicitly bypass the proxy
- Proxy URL:
- First matching
modelsrule in merged declaration order wins; models not listed use Pi's default pipeline - An
authrule applies only to that provider's supported auth flow; unconfigured auth uses Pi's default pipeline
Priority
--noproxy / /noproxy (disable) > /allproxy (temporary process proxy) > dedicated config rule > legacy settings rule > Pi's default pipeline
In-session OAuth authentication
auth rules currently cover these built-in endpoints:
openai-codex:auth.openai.com/oauth/token,auth.openai.com/api/accounts/deviceauth/usercode,auth.openai.com/api/accounts/deviceauth/tokenanthropic:platform.claude.com/v1/oauth/tokengithub-copilot: GitHub device/OAuth endpoints andapi.github.com/api.individual.githubcopilot.comCopilot token endpointskimi-coding:auth.kimi.com/api/oauth/device_authorization,auth.kimi.com/api/oauth/tokenopenrouter:openrouter.ai/api/v1/auth/keysxai:auth.x.ai/oauth2/device/code,auth.x.ai/oauth2/token
Token exchange, refresh, and device-code requests from an in-session /login flow use the provider rule. Browser authorization pages are outside the extension, and the standalone pi auth ... command does not load extensions; use HTTP_PROXY / HTTPS_PROXY for that process.
Commands
| Command | Description |
|---|---|
/proxy |
Show current status: flags, toggles, allproxy, environment variables, model and auth rules |
/proxy openai-codex/gpt-5.6-luna |
With an argument, also shows the resolved route for that model |
/allproxy http://127.0.0.1:7890 |
Force Pi HTTP(S) traffic, OAuth refresh, and all models through this proxy (session-only, not persisted) |
/allproxy |
Cancel the temporary proxy, fall back to rules |
/noproxy |
Toggle disable/restore (toggles when no argument) |
/noproxy on / /noproxy off |
Explicitly set |
pi --noproxy |
Disable all proxy rules at startup |
How it works
This extension has three routing layers:
modelswrapsstream/streamSimplein the current session's model registry, resolves rules by model id for every API type, and injects undici fetch with a custom dispatcher.The process-wide dispatcher also routes known model endpoints by their
baseUrl, covering foreground children and HTTP APIs that bypass the provider wrapper.authinstalls a process-wide wrapper around Pi's default dispatcher. It selects a provider dispatcher only for known OAuth endpoints and delegates all other requests to Pi's original pipeline.http:///https://→ undiciProxyAgentsocks5h://→ built-inSocksDispatcher(implements the undici Dispatcher interface oversocks-proxy-agent, forwarded to node http/https.request)
While /allproxy is active, the routing wrapper sends Pi's default HTTP(S) requests, including OAuth, and all model requests through the temporary proxy. It is not read from settings.json and is disabled when /allproxy is cancelled. Routed model requests use an explicit dispatcher instead of environment proxies. Codex requests are forced to SSE when proxied because the default WebSocket transport does not accept the injected fetch dispatcher; foreground children use the endpoint fallback and are forced from a routed WebSocket to SSE as well.
URL matching (planned)
Arbitrary URL or hostname rules such as the following are intentionally not supported yet:
"urls": {
"*.abc.com": "socks5h://127.0.0.1:7890"
}
If needed later, this will be evaluated as an explicit urls section with separate semantics for host, port, path, redirects, and precedence. It will remain separate from models and auth rather than becoming a general-purpose GFWList.
Environment variables
Pi installs an EnvHttpProxyAgent globally at startup, so all fetch calls read HTTP_PROXY / HTTPS_PROXY. This means:
- Models matching a rule use the explicit dispatcher (rules win, environment not consulted)
- Known model endpoints used by foreground children use the same rules
- While
/allproxyis active, Pi's default HTTP(S) pipeline (including OAuth) uses the selected dispatcher - Models without a matching rule still use Pi's default pipeline; if proxy environment variables are set, they will go through the HTTP proxy
Known limitations
- The endpoint fallback relies on
baseUrlfrom the current model registry. If different models share one base URL but have different proxy rules, URL-level routing cannot distinguish them; the first matching route is retained and a debug log is emitted. Use the same proxy rule for those models or separate endpoints. /allproxycovers Pi's process HTTP(S) traffic only while it is active; it does not cover browser navigation, arbitrary child-process networking, unrelated native WebSocket clients, or the standalonepi auth ...command handled before extensions load.authonly covers built-in provider auth endpoint mappings; adding a provider requires adding its endpoint mapping, not an arbitrary URL wildcard.
License
MIT