Interactive switcher for Claude Code / Codex / OpenCode / Pi proxy profiles.
Quickly switch between API relays, models, and keys: profiles live in local source directories. Claude/Codex apply by replacing the target global config; OpenCode/Pi merge providers into the live config. Optional auth files are updated the same way, with automatic backups.
Implemented as a single Rust binary — no Python / jq runtime required. The repo keeps proxi.py as a legacy reference.
Pick one:
| Method | Notes | Guide |
|---|---|---|
| Rust (recommended) | Build a single binary, no runtime deps | docs/install-rust.md |
| Windows (PowerShell) | winget rustup + install.ps1 one-step installer |
docs/install-windows.md |
| Python + uv | Run proxi.py directly when you don’t want Rust |
docs/install-python-uv.md |
Requires Rust / rustup (build time only). Full steps: Rust setup guide.
git clone https://github.com/APengX/proxi.git
cd proxi
cargo build --release
ln -sfn "$(pwd)/target/release/proxi" ~/.local/bin/proxi # ensure ~/.local/bin is on PATHProfile sources default to setforclaude/, setforcodex/, setforopencode/, and setforpi/ at the repo root (resolved by walking up from the executable; override with env vars).
Needs Python 3.11+ (stdlib tomllib). Prefer uv for the interpreter. Full steps: Python + uv setup guide.
The Python legacy version supports Claude Code / Codex only; use the Rust build for OpenCode or Pi.
# System Python
chmod +x proxi.py
ln -sfn "$(pwd)/proxi.py" ~/.local/bin/proxi
# Or uv (picks 3.12; no manual packages)
uv run --python 3.12 python proxi.py list- Add your profiles from the examples:
# Claude Code
cp setforclaude/settings.example.json setforclaude/settingsmyapi.json
# edit URL / token / model
# Codex
cp setforcodex/config.example.toml setforcodex/configmyapi.toml
cp setforcodex/auth.example.json setforcodex/authmyapi.json
# edit base_url / model / OPENAI_API_KEY
# OpenCode
cp setforopencode/config.example.json setforopencode/configmyapi.json
cp setforopencode/auth.example.json setforopencode/authmyapi.json
# edit provider / baseURL / model / key
# Pi
cp setforpi/models.example.json setforpi/modelsmyapi.json
cp setforpi/settings.example.json setforpi/settingsmyapi.json
cp setforpi/auth.example.json setforpi/authmyapi.json
# edit provider / baseUrl / model / key- Switch:
proxi # interactive: pick claude/codex/opencode/pi, then a profile
proxi claude myapi # apply Claude profile
proxi codex myapi # apply Codex profile
proxi opencode myapi # apply OpenCode profile
proxi pi myapi # apply Pi profile
proxi list # list all
proxi current # show active profileInteractive menu: ↑↓ / j k to move; in the profile list, Enter applies and → edits. For Claude, Codex, OpenCode, and Pi, → edits URL / Key, probes the provider’s model endpoint, then opens a model picker. In a model picker, type any part of a model ID to move the cursor to the best match; Backspace edits the query and Esc cancels. Claude tries the Anthropic-style /v1/models and /models endpoints; OpenAI-compatible targets use /models. OpenCode and Pi also merge the discovered model list into their native model catalogs. In submenus Esc / ← go back, q quits; at the root menu q / Esc cancels.
| Target | Source file | Written to |
|---|---|---|
| Claude Code | setforclaude/settings<name>.json |
~/.claude/settings.json |
| Codex | setforcodex/config<name>.toml |
~/.codex/config.toml |
| Codex auth (optional) | setforcodex/auth<name>.json |
~/.codex/auth.json |
| OpenCode | setforopencode/config<name>.json |
~/.config/opencode/opencode.json |
| OpenCode auth (optional) | setforopencode/auth<name>.json |
~/.local/share/opencode/auth.json |
| Pi models | setforpi/models<name>.json |
~/.pi/agent/models.json |
| Pi settings (optional) | setforpi/settings<name>.json |
~/.pi/agent/settings.json |
| Pi auth (optional) | setforpi/auth<name>.json |
~/.pi/agent/auth.json |
Claude Code / Codex switching is a full file replace (not a field merge).
OpenCode / Pi switching is an append/merge:
- OpenCode: merges
providerentries and shallow-applies other profile top-level keys into the liveopencode.json; merges matching keys intoauth.json. - Pi: merges
providersinto the livemodels.json; shallow-merges profilesettings.json/auth.jsonkeys. Unrelated providers and settings are preserved; same-named providers are overwritten by the selected profile.
Existing targets are backed up as *.bak first.
Profile sources are always the four setfor* directories at the repo root — identical on every OS. Only the targets differ, and proxi resolves them at runtime, so the same profile files work unchanged across machines.
Claude Code, Codex, and Pi anchor their config to the home directory on all three platforms:
| Target | macOS / Linux | Windows |
|---|---|---|
| Claude Code | ~/.claude/settings.json |
%USERPROFILE%\.claude\settings.json |
| Codex | ~/.codex/config.toml · ~/.codex/auth.json |
%USERPROFILE%\.codex\config.toml · auth.json |
| Pi | ~/.pi/agent/models.json · settings.json · auth.json |
%USERPROFILE%\.pi\agent\models.json · … |
OpenCode does not use the OS-native config / data directories. On macOS and Windows it still reads XDG-style paths under the home directory, so proxi resolves them the same way:
| Platform | OpenCode config | OpenCode auth |
|---|---|---|
| Linux | ~/.config/opencode/opencode.json |
~/.local/share/opencode/auth.json |
| macOS | ~/.config/opencode/opencode.json |
~/.local/share/opencode/auth.json |
| Windows | %USERPROFILE%\.config\opencode\opencode.json |
%USERPROFILE%\.local\share\opencode\auth.json |
XDG_CONFIG_HOME and XDG_DATA_HOME are honored on all three platforms (OpenCode honors them too), and an empty value counts as unset. OPENCODE_CONFIG_DIR / OPENCODE_CONFIG still take precedence over both.
Earlier builds derived these from
dirs::config_dir()/dirs::data_dir(), which resolve to~/Library/Application Support/opencodeon macOS and%APPDATA%\opencodeon Windows — directories OpenCode never reads, so switching silently had no effect on those two platforms. If you switched OpenCode profiles on macOS or Windows with an older build, delete those stale directories.
| Behavior | macOS / Linux | Windows |
|---|---|---|
| Install | ln -sfn "$(pwd)/target/release/proxi" ~/.local/bin/proxi |
.\install.ps1 → %USERPROFILE%\.local\bin\proxi.exe, writes a proxi.home repo locator, and sets user PATH / PROXI_HOME |
| Locating profile sources | walks up from the executable (a symlink is resolved first), else $PWD |
PROXI_HOME first, then the proxi.home locator written beside the copied executable |
| Key file permissions | 0600 on every key-bearing file proxi creates or overwrites |
no-op — relies on NTFS ACLs / per-user profile isolation |
proxi <tool> edit editor |
$EDITOR → $VISUAL → vi |
$EDITOR → $VISUAL → notepad |
Every path above can be overridden — see Environment variables.
{
"env": {
"ANTHROPIC_BASE_URL": "https://api.example.com",
"ANTHROPIC_AUTH_TOKEN": "sk-..."
},
"model": "claude-opus-4-6"
}configmyapi.toml + optional matching authmyapi.json:
model_provider = "openai_http"
model = "gpt-5"
[model_providers.openai_http]
name = "My Provider"
base_url = "https://api.example.com/v1"
wire_api = "responses"
requires_openai_auth = true{ "OPENAI_API_KEY": "sk-..." }configmyapi.json + optional matching authmyapi.json:
{
"$schema": "https://opencode.ai/config.json",
"model": "myapi/gpt-5",
"provider": {
"myapi": {
"npm": "@ai-sdk/openai-compatible",
"name": "My API",
"options": { "baseURL": "https://api.example.com/v1" },
"models": { "gpt-5": { "name": "GPT-5" } }
}
}
}{ "myapi": { "type": "api", "key": "sk-..." } }OpenCode apply merges the profile’s providers into the existing global config instead of replacing the whole file. Same-named providers are overwritten; other providers and unrelated keys stay. Auth entries are merged by provider id.
OpenCode’s database, sessions, and state directories are not switched. A project-local opencode.json or .opencode/ may still override the global config.
The backend manages standard JSON files; if you use commented opencode.jsonc, point OPENCODE_CONFIG at a plain JSON profile entry.
modelsmyapi.json + optional matching settingsmyapi.json and authmyapi.json:
{
"providers": {
"myapi": {
"baseUrl": "https://api.example.com/v1",
"api": "openai-completions",
"headers": {
"User-Agent": "codex_cli_rs/0.145.0 (Ubuntu 22.04; x86_64) unknown",
"originator": "codex_cli_rs",
"X-Stainless-Lang": "",
"X-Stainless-Package-Version": "",
"X-Stainless-OS": "",
"X-Stainless-Arch": "",
"X-Stainless-Runtime": "",
"X-Stainless-Runtime-Version": "",
"X-Stainless-Retry-Count": "",
"X-Stainless-Timeout": ""
},
"models": [{ "id": "gpt-5", "name": "GPT-5", "reasoning": true }]
}
}
}{ "defaultProvider": "myapi", "defaultModel": "gpt-5" }{ "myapi": { "type": "api_key", "key": "sk-..." } }Pi apply merges the profile’s providers into the existing models.json, and shallow-merges settings/auth keys. Same-named providers are overwritten; other providers and unrelated settings stay.
Pi sessions, trust decisions, installed extensions, and models-store.json are not switched. A project-local .pi/settings.json may override the global settings.
Pi accepts comments in its own models.json, but proxi profiles intentionally use standard JSON so they can be validated and edited safely.
When a Pi provider uses an OpenAI-shaped API — its api field starts with openai (openai-completions, openai-responses, …) or is absent, which is what proxi pi add writes — proxi adds Codex CLI 0.145.0-compatible User-Agent / originator headers, clears every existing X-Stainless-* value, and writes empty values for the known SDK fingerprint headers. Existing unrelated custom headers are preserved. Model detection requests use the same compatibility headers.
This is not cosmetic: on its OpenAI path Pi sends User-Agent: OpenAI/JS <version>, and some relays reject that user agent outright with 403 Your request was blocked. — regardless of key, model, or request body. Overriding the User-Agent is what gets through. Providers on anthropic-messages / google-generative-ai are deliberately left alone, since they go through different SDKs where a Codex user agent would be wrong.
proxi pick target → pick profile
proxi claude | codex | opencode | pi interactive menu for that tool
proxi claude <name> apply directly
proxi codex <name>
proxi opencode <name>
proxi pi <name>
proxi list [claude|codex|opencode|pi]
proxi current
proxi dir
proxi claude add [<name>] interactive add (URL / Key)
proxi codex add [<name>]
proxi claude edit <name> edit raw files with $EDITOR
proxi codex edit <name>
proxi opencode add [<name>] requires URL / Key / Model
proxi opencode edit <name>
proxi pi add [<name>] URL / Key + Model(s) or auto-detection
proxi pi edit <name>
proxi pi models <name> list configured models
proxi claude edit <name> --url URL --key KEY --model MODEL
proxi codex edit <name> --url URL --key KEY --model MODEL
proxi opencode edit <name> --url URL --key KEY --model MODEL
proxi pi edit <name> --url URL --key KEY --model MODEL
proxi pi models <name> --add MODEL,... [--detect] [--default MODEL]
Add / edit also accept flags:
proxi claude add myapi --url https://api.example.com --key sk-xxx
proxi claude add myapi --url https://api.example.com --key sk-xxx --no-use
proxi claude edit myapi --url https://api.example.com --key sk-new
proxi codex edit myapi --url https://api.example.com/v1 --key sk-new --use
proxi opencode add myapi --url https://api.example.com/v1 --key sk-new --model gpt-5
proxi opencode edit myapi --url https://api.example.com/v1 --model gpt-5 --use
proxi pi add myapi --url https://api.example.com/v1 --key sk-new --model gpt-5
proxi pi add myapi --url https://api.example.com/v1 --key sk-new \
--model gpt-5 --models gpt-5,gpt-4.1,gpt-4o
proxi pi add myapi --url https://api.example.com/v1 --key sk-new --detect-models
proxi pi edit myapi --url https://api.example.com/v1 --model gpt-5 --use
proxi pi edit myapi --models gpt-5.6-sol,gpt-5.6-terra
proxi pi models myapi
proxi pi models myapi --add gpt-5.6-sol,gpt-5.6-terra --default gpt-5.6-sol
proxi pi models myapi --detect --useedit <name> without --url / --key / --model / --models / --detect-models keeps the old behavior and opens $EDITOR. With flags, only those fields are updated; editing the currently active profile syncs to the target config unless you pass --no-use.
For Pi, --model selects the default model while --models adds a list of available models. --detect-models (or pi models <name> --detect) requests the provider base URL with /models appended, accepts common OpenAI-style data[].id and models[] responses, and merges newly found IDs without removing existing model metadata. In the interactive Pi add flow, enter auto at the model prompt to run detection.
| Variable | Purpose |
|---|---|
PROXI_HOME |
Data root (contains the four setfor* source dirs) |
PROXI_DIR / PROXI_CLAUDE_DIR |
Override Claude profile source dir |
PROXI_CODEX_DIR |
Override Codex profile source dir |
PROXI_OPENCODE_DIR |
Override OpenCode profile source dir |
PROXI_PI_DIR |
Override Pi profile source dir |
CLAUDE_CONFIG_DIR |
Override ~/.claude |
CODEX_HOME |
Override ~/.codex |
OPENCODE_CONFIG_DIR |
Override OpenCode global config dir (default ~/.config/opencode on all platforms) |
OPENCODE_CONFIG |
Point at a specific OpenCode config file |
PI_CODING_AGENT_DIR |
Override Pi config dir (default ~/.pi/agent) |
XDG_CONFIG_HOME / XDG_DATA_HOME |
Override OpenCode’s config / data roots — honored on macOS, Linux, and Windows alike |
Crates (clap, serde, toml, …) are fetched at build/release time and linked into the binary — not a user-side package burden.
- Only keep
*.example.*samples in the repo; realsettings*.json/models*.json/config*.toml/config*.json/auth*.jsonare gitignored. - Key-bearing files created or overwritten by proxi use mode
0600on Unix. - Before pushing, confirm
git statusshows no token-bearing files. - Switching creates local backups (
settings.json.bak/config.toml.bak, etc.) — do not commit those either.
Further agent adapters and UX items are tracked in TODO.md (Cursor, Gemini CLI, etc. not yet wired).
MIT
