Use ZenMux models in Pi with OAuth 2.0 Authorization Code + PKCE. The extension registers the zenmux provider, discovers the current model catalog, and refreshes OAuth tokens with rotation.
Model requests prefer Anthropic Messages, then OpenAI Responses, and use Chat Completions only as a compatibility fallback. Protocol selection is performed per model from the endpoint adapters advertised by the ZenMux model catalog; the local fallback model uses Anthropic Messages when discovery is unavailable.
Install the package with Pi:
pi install npm:@zenmux/pi-zenmux-oauthIf it is already installed, update only this plugin:
pi update npm:@zenmux/pi-zenmux-oauthTo update all installed Pi extensions instead:
pi update --extensionsAfter updating, restart Pi so it reloads the new extension version. Check the installed package with:
pi listStart Pi and sign in:
/login zenmux
Pi opens the ZenMux authorization page in your browser. After approval, the browser redirects to a temporary loopback listener on 127.0.0.1, which renders https://zenmux.ai/platform/oauth-completed?client=pi in a full-screen iframe. Return to Pi, run /model, and select a ZenMux model.
- The official
https://zenmux.aiservice uses one bundled native public OAuth client ID. - Authorization uses PKCE with
S256; no client secret is stored or distributed. - Existing client IDs are still read from
~/.pi/zenmux-oauth-clients.jsonto keep previously issued credentials working. Non-production origins register and cache a client on first use. - Access and refresh tokens are managed by Pi's provider credential store.
- Refresh tokens rotate on every refresh.
- Model requests use the OAuth access token as a Bearer token. ZenMux API keys are not exposed to the extension.
- The discovered model catalog is cached by Pi in
~/.pi/agent/models-store.json. The extension restores it at startup, refreshes it when network access is allowed, and keeps the last valid catalog when discovery fails or returns empty. - Cached models are scoped to the configured OAuth origin and model catalog URL, so production and development catalogs are not mixed.
The package requests only these scopes:
inference:invokeoffline_access
Production works without additional configuration. These environment variables are available for development and self-hosted testing:
| Variable | Default | Purpose |
|---|---|---|
ZENMUX_OAUTH_ORIGIN |
https://zenmux.ai |
OAuth authorization server origin |
ZENMUX_API_BASE_URL |
https://zenmux.ai/api/v1 |
OpenAI-compatible API base URL |
ZENMUX_ANTHROPIC_BASE_URL |
derived as https://zenmux.ai/api/anthropic |
Anthropic-compatible API base URL |
ZENMUX_MODEL_CATALOG_URL |
https://zenmux.ai/api/frontend/model/available/list |
Rich model catalog containing endpoint protocol adapters |
ZENMUX_TEST_MODEL |
deepseek/deepseek-v4-flash |
Fallback model when discovery is unavailable |
ZENMUX_OAUTH_CLIENT_ID |
bundled for https://zenmux.ai |
Override the public client ID for development or self-hosted environments |
Load the extension directly:
pi -e ./index.mjsRun against the ZenMux pre-release OAuth environment:
npm run devValidate the source and inspect the npm tarball before publishing:
npm test
npm pack --dry-runPi packages execute with the permissions of the Pi process. Review package source before installation. This extension listens only on an ephemeral 127.0.0.1 port during OAuth authorization and verifies the returned OAuth state before exchanging the authorization code.
MIT