Pi and OMP share only the JSONL child-process transport while retaining provider-owned launch, RPC, runtime, session, history, and permission behavior. Removes captured fixtures in favor of typed harnesses and real-provider coverage. Closes #2006 Closes #2060
27 KiB
Custom Provider Configuration
Paseo supports configuring custom agent providers through config.json (located at $PASEO_HOME/config.json, typically ~/.paseo/config.json). You can extend built-in providers with different API backends, add ACP-compatible agents, set custom binaries, disable providers, and create multiple profiles for the same underlying provider.
All provider configuration lives under agents.providers in config.json:
{
"version": 1,
"agents": {
"providers": {
"provider-id": { ... }
}
}
}
Provider IDs must be lowercase alphanumeric with hyphens (/^[a-z][a-z0-9-]*$/).
Table of Contents
- Extending a built-in provider
- Z.AI (Zhipu) coding plan
- Alibaba Cloud (Qwen) coding plan
- Codex with a custom OpenAI-compatible endpoint
- Multiple profiles for the same provider
- Custom binary for a provider
- Disabling a provider
- ACP providers
- Provider override reference
Extending a built-in provider
Use extends to create a new provider entry that inherits from a built-in provider (claude, codex, copilot, opencode, pi, omp). The new provider gets its own entry in the provider list, with its own label, environment, and model definitions.
{
"agents": {
"providers": {
"my-claude": {
"extends": "claude",
"label": "My Claude",
"description": "Claude with custom API endpoint",
"env": {
"ANTHROPIC_API_KEY": "sk-ant-...",
"ANTHROPIC_BASE_URL": "https://my-proxy.example.com/v1"
}
}
}
}
}
Required fields for custom providers:
extends— which built-in provider to inherit from (or"acp")label— display name in the UI
See Codex with a custom OpenAI-compatible endpoint below for the dedicated Codex example.
Z.AI (Zhipu) coding plan
Z.AI is a Chinese AI company (Zhipu AI) that offers an Anthropic-compatible API endpoint. Their GLM Coding Plan provides flat-rate access to GLM models through Claude Code's Anthropic API protocol. These are not Anthropic Claude models — they are Zhipu's own GLM models exposed through an Anthropic-compatible API.
Setup
- Register at z.ai and subscribe to a coding plan
- Create an API key from the Z.AI dashboard
- Add a provider entry in config.json:
{
"agents": {
"providers": {
"zai": {
"extends": "claude",
"label": "ZAI",
"env": {
"ANTHROPIC_AUTH_TOKEN": "<your-zai-api-key>",
"ANTHROPIC_BASE_URL": "https://api.z.ai/api/anthropic",
"API_TIMEOUT_MS": "3000000"
},
"disallowedTools": ["WebSearch"],
"models": [
{ "id": "glm-4.5-air", "label": "GLM 4.5 Air" },
{ "id": "glm-5-turbo", "label": "GLM 5 Turbo", "isDefault": true },
{ "id": "glm-5.1", "label": "GLM 5.1" }
]
}
}
}
}
Available models
| Model | Tier |
|---|---|
glm-5.1 |
Advanced (flagship) |
glm-5-turbo |
Advanced |
glm-4.7 |
Standard |
glm-4.5-air |
Lightweight |
Notes
ANTHROPIC_AUTH_TOKENis used instead ofANTHROPIC_API_KEY— this is the z.ai API key- The
API_TIMEOUT_MSenv var extends the request timeout (z.ai can be slower than direct Anthropic) - If you get auth errors, run
/logoutinside Claude Code before switching to the z.ai provider - Web search (
WebSearchtool) is an Anthropic-only server-side feature — third-party endpoints don't support it. Add"disallowedTools": ["WebSearch"]to avoid errors. - Automated setup is also available:
npx @z_ai/coding-helper - Official docs: docs.z.ai/devpack/tool/claude
Alibaba Cloud (Qwen) coding plan
Alibaba Cloud Model Studio offers a coding plan that routes Claude Code requests to Qwen models through an Anthropic-compatible API. Like z.ai, these are not Anthropic Claude models.
Setup
- Go to the Coding Plan page on Alibaba Cloud Model Studio (Singapore region)
- Subscribe to the Pro plan ($50/month)
- Obtain your plan-specific API key (format:
sk-sp-xxxxx) — this is different from a standard Model Studio key - Add a provider entry in config.json:
{
"agents": {
"providers": {
"qwen": {
"extends": "claude",
"label": "Qwen (Alibaba)",
"env": {
"ANTHROPIC_AUTH_TOKEN": "sk-sp-<your-coding-plan-key>",
"ANTHROPIC_BASE_URL": "https://coding-intl.dashscope.aliyuncs.com/apps/anthropic"
},
"disallowedTools": ["WebSearch"],
"models": [
{ "id": "qwen3.5-plus", "label": "Qwen 3.5 Plus", "isDefault": true },
{ "id": "qwen3-coder-next", "label": "Qwen 3 Coder Next" },
{ "id": "kimi-k2.5", "label": "Kimi K2.5" }
]
}
}
}
}
API endpoints
| Mode | Base URL |
|---|---|
| Coding plan (subscription) | https://coding-intl.dashscope.aliyuncs.com/apps/anthropic |
| Pay-as-you-go (no subscription) | https://dashscope-intl.aliyuncs.com/apps/anthropic |
For pay-as-you-go, use ANTHROPIC_API_KEY with a standard Model Studio key (sk-xxxxx) instead of ANTHROPIC_AUTH_TOKEN.
Available models
Recommended for coding plan:
| Model | Notes |
|---|---|
qwen3.5-plus |
Vision capable, recommended |
qwen3-coder-next |
Optimized for coding |
kimi-k2.5 |
Vision capable |
glm-5 |
Zhipu GLM |
MiniMax-M3 |
MiniMax |
Additional models (pay-as-you-go):
qwen3-max, qwen3.5-flash, qwen3-coder-plus, qwen3-coder-flash, qwen3-vl-plus, qwen3-vl-flash
Notes
- API keys must be created in the Singapore region
- The coding plan is for personal use only in interactive coding tools
- Web search (
WebSearchtool) is an Anthropic-only server-side feature — third-party endpoints don't support it. Add"disallowedTools": ["WebSearch"]to avoid errors. - Official docs: alibabacloud.com/help/en/model-studio/claude-code-coding-plan
Codex with a custom OpenAI-compatible endpoint
Codex talks to OpenAI's Responses API by default. Custom providers that extend "codex" can point Codex at any OpenAI-compatible endpoint (OpenRouter, LiteLLM, vLLM, llama.cpp server, an internal gateway, etc.) by setting OPENAI_BASE_URL and OPENAI_API_KEY in the provider env.
Paseo passes those variables through to the Codex app-server process and maps them into Codex's thread config under model_provider / model_providers, because Codex reads provider routing from config rather than from OPENAI_BASE_URL alone.
Setup
{
"agents": {
"providers": {
"my-codex": {
"extends": "codex",
"label": "My Codex",
"description": "Codex via custom OpenAI-compatible endpoint",
"env": {
"OPENAI_API_KEY": "sk-...",
"OPENAI_BASE_URL": "https://custom-relay.example.com"
},
"models": [{ "id": "custom-model", "label": "Custom Model", "isDefault": true }]
}
}
}
}
What Paseo wires up
Under the hood, for each custom Codex provider Paseo injects this into Codex's config:
model_provider = "my-codex"
[model_providers.my-codex]
name = "My Codex"
base_url = "https://custom-relay.example.com/v1"
wire_api = "responses"
env_key = "OPENAI_API_KEY"
requires_openai_auth = false
base_url— taken fromOPENAI_BASE_URL. If it does not already end in/v1, Paseo appends/v1. Trailing slashes are stripped.wire_api— always"responses"(OpenAI Responses API protocol).env_key— set to"OPENAI_API_KEY"when that env var is present and non-empty, so Codex reads the key from the same env var Paseo passes through.requires_openai_auth— forced tofalsewhenOPENAI_API_KEYis provided, so Codex skips its built-in OpenAI login flow.
Notes
- The endpoint must speak the OpenAI Responses API, not just chat completions. Many gateways (OpenRouter, LiteLLM) support both — pick the Responses-compatible route.
- Set
modelsexplicitly. Custom endpoints expose their own model IDs (anthropic/claude-opus-4-7,qwen/qwen3-coder,local/llama, etc.), and Paseo does not discover them automatically for Codex. - To run multiple endpoints side-by-side, define multiple entries that each extend
"codex"with different IDs, labels, and env. Each appears as its own provider in the app. - If you only want to override the binary (e.g. a nightly Codex build) without changing the endpoint, omit
OPENAI_BASE_URLand usecommandinstead — see Custom binary for a provider.
Multiple profiles for the same provider
You can create multiple entries that extend the same built-in provider. Each gets its own entry in the provider list with independent credentials, models, and environment.
Example: two different Anthropic accounts as separate profiles:
{
"agents": {
"providers": {
"claude-work": {
"extends": "claude",
"label": "Claude (Work)",
"description": "Work Anthropic account",
"env": {
"ANTHROPIC_API_KEY": "sk-ant-work-..."
}
},
"claude-personal": {
"extends": "claude",
"label": "Claude (Personal)",
"description": "Personal Anthropic account",
"env": {
"ANTHROPIC_API_KEY": "sk-ant-personal-..."
}
}
}
}
}
Each profile appears as a separate provider in the Paseo app. You can select which one to use when launching an agent.
You can also combine profiles with model overrides to pin specific models per profile:
{
"agents": {
"providers": {
"claude-fast": {
"extends": "claude",
"label": "Claude (Fast)",
"models": [{ "id": "claude-sonnet-4-6", "label": "Sonnet 4.6", "isDefault": true }]
},
"claude-smart": {
"extends": "claude",
"label": "Claude (Smart)",
"models": [{ "id": "claude-opus-4-6", "label": "Opus 4.6", "isDefault": true }]
}
}
}
}
Custom binary for a provider
Override the command used to launch any provider with the command field. This is an array where the first element is the binary and the rest are arguments.
Override a built-in provider's binary
{
"agents": {
"providers": {
"claude": {
"command": ["/opt/claude-nightly/claude"]
}
}
}
}
Use a custom wrapper script
{
"agents": {
"providers": {
"claude": {
"command": ["/usr/local/bin/my-claude-wrapper", "--verbose"]
}
}
}
}
Custom binary on a derived provider
{
"agents": {
"providers": {
"my-codex": {
"extends": "codex",
"label": "Codex (Custom Build)",
"command": ["/home/user/codex-dev/target/release/codex"]
}
}
}
}
The command array completely replaces the default command for that provider. The binary must exist on the system — Paseo checks for its availability and will mark the provider as unavailable if not found.
OMP profiles and Pi-compatible forks
OMP ships as a first-class built-in provider option. It is disabled by default; enable it with:
{
"agents": {
"providers": {
"omp": { "enabled": true }
}
}
}
Custom OMP profiles should extend omp. They inherit the OMP adapter's rpc-ui approvals, native Paseo host tools, provider-managed subagents, and import behavior:
{
"agents": {
"providers": {
"omp-work": {
"extends": "omp",
"label": "Oh My Pi (Work)",
"command": ["omp"],
"env": {
"XDG_CONFIG_HOME": "~/.config/omp-work",
"XDG_STATE_HOME": "~/.local/state/omp-work"
},
"params": {
"sessionDir": "~/.local/state/omp-work/omp/agent/sessions",
"smolModel": "openai/gpt-5-mini",
"slowModel": "anthropic/claude-opus-4-1",
"planModel": "openai/o3"
}
}
}
}
}
params.sessionDir is used only for importing sessions that were started outside Paseo. If command or XDG env vars move OMP's state directory, set params.sessionDir to the resulting OMP JSONL session directory; launching and resuming still go through the configured command.
For other providers that keep Pi's --mode rpc API but write sessions somewhere else, extend pi, replace the command, and provide the JSONL session directory:
{
"agents": {
"providers": {
"my-pi-fork": {
"extends": "pi",
"label": "My Pi Fork",
"command": ["my-pi-fork"],
"params": {
"sessionDir": "~/.my-pi-fork/sessions"
}
}
}
}
}
This session directory is also import-only. Launching and resuming still go through the configured command, so this example resumes with my-pi-fork --mode rpc --session <session-file>.
Disabling a provider
Set enabled: false to hide a provider from the provider list. The provider will not appear in the app or CLI.
{
"agents": {
"providers": {
"copilot": { "enabled": false },
"codex": { "enabled": false }
}
}
}
This works for both built-in and custom providers. To re-enable, set enabled: true or remove the enabled field entirely. Most providers are enabled by default; OMP is intentionally disabled by default and requires enabled: true.
ACP providers
The Agent Client Protocol (ACP) is an open standard for communication between editors and AI coding agents — think LSP but for AI agents. Any agent that supports ACP can be added to Paseo as a custom provider.
ACP agents communicate over JSON-RPC 2.0 on stdio. Paseo spawns the agent process and talks to it through stdin/stdout.
Paseo also ships an in-app ACP provider catalog for common agents, including CodeWhale, Cursor, DeepAgents, DimCode, Gemini CLI, Hermes, Qwen Code, and Kimi Code. Catalog entries create the same extends: "acp" provider config shown below.
Adding a generic ACP provider
Set extends: "acp" and provide a command:
{
"agents": {
"providers": {
"my-agent": {
"extends": "acp",
"label": "My Agent",
"command": ["my-agent-binary", "--acp"],
"env": {
"MY_API_KEY": "..."
}
}
}
}
}
Required fields for ACP providers:
extends: "acp"labelcommand— the command to spawn the agent process (must support ACP over stdio)
Paseo tools such as subagent creation come from the shared internal tool catalog. ACP providers receive those tools through the MCP fallback by default because ACP exposes mcpServers, not Paseo's native tool catalog. Some ACP adapters cannot create sessions when mcpServers is non-empty. Disable injected MCP for those providers with params.supportsMcpServers: false:
{
"agents": {
"providers": {
"my-agent": {
"extends": "acp",
"label": "My Agent",
"command": ["my-agent", "acp"],
"params": {
"supportsMcpServers": false
}
}
}
}
}
ACP agents execute filesystem and terminal operations in their own environment by default. To let a compliant agent delegate those operations to Paseo instead, enable the corresponding client capabilities:
{
"agents": {
"providers": {
"local-agent": {
"extends": "acp",
"label": "Local Agent",
"command": ["local-agent", "acp"],
"params": {
"clientCapabilities": {
"fs": {
"readTextFile": true,
"writeTextFile": true
},
"terminal": true
}
}
}
}
}
}
Only enable capabilities Paseo should execute. When the agent and Paseo run in different environments, configure equivalent absolute workspace paths before delegating filesystem or terminal operations to Paseo.
Generic ACP diagnostics
Paseo diagnostics for extends: "acp" providers report the configured command, resolved launcher binary, version output, ACP initialize, ACP session/new, model count, modes, and final status.
For package-runner commands such as npx -y @google/gemini-cli --acp, the version probe keeps the package spec and runs npx -y @google/gemini-cli --version. This diagnoses the actual agent package instead of only proving that npx exists.
ACP probes use short timeouts and browser-suppression environment variables so agents that enter an auth/browser flow fail as a diagnostic error instead of hanging the provider screen.
Example: Google Gemini CLI
Gemini CLI supports ACP via the --acp flag.
- Install:
npm install -g @google/gemini-clior see Gemini CLI docs - Authenticate with Google (Gemini CLI handles its own auth)
- Add to config.json:
{
"agents": {
"providers": {
"gemini": {
"extends": "acp",
"label": "Google Gemini",
"command": ["gemini", "--acp"]
}
}
}
}
Example: Hermes (Nous Research)
Hermes is an open-source coding agent by Nous Research with persistent memory and multi-provider LLM support. It supports ACP via the acp subcommand.
- Install:
curl -fsSL https://raw.githubusercontent.com/NousResearch/hermes-agent/main/scripts/install.sh | bash - Install ACP support:
pip install -e '.[acp]' - Configure Hermes credentials in
~/.hermes/ - Add to config.json:
{
"agents": {
"providers": {
"hermes": {
"extends": "acp",
"label": "Hermes",
"description": "Nous Research self-improving AI agent",
"command": ["hermes", "acp"]
}
}
}
}
Ref: Hermes ACP docs
How ACP providers work in Paseo
When you launch an agent with an ACP provider:
- Paseo spawns the process using the configured
command - Sends an
initializeJSON-RPC request over stdin - The agent responds with its capabilities, available modes, and models
- Paseo creates a session and sends prompts through the ACP protocol
- The agent streams responses, tool calls, and permission requests back over stdout
Models and modes are discovered dynamically at runtime from the agent process. If you want to override the model list (e.g., to curate which models appear in the UI), use the models field:
{
"agents": {
"providers": {
"my-agent": {
"extends": "acp",
"label": "My Agent",
"command": ["my-agent", "--acp"],
"models": [
{ "id": "fast-model", "label": "Fast", "isDefault": true },
{ "id": "smart-model", "label": "Smart" }
]
}
}
}
}
Profile models (defined in config.json) completely replace runtime-discovered models when present.
If you want to keep runtime-discovered models and add or relabel a few entries, use additionalModels instead.
Example: add an experimental model while keeping every model the provider discovers at runtime:
{
"agents": {
"providers": {
"my-agent": {
"extends": "acp",
"label": "My Agent",
"command": ["my-agent", "--acp"],
"additionalModels": [
{ "id": "experimental-model", "label": "Experimental", "isDefault": true }
]
}
}
}
}
Example: relabel a discovered model without replacing the full list:
{
"agents": {
"providers": {
"my-agent": {
"extends": "acp",
"label": "My Agent",
"command": ["my-agent", "--acp"],
"additionalModels": [{ "id": "provider/model-id", "label": "My Preferred Label" }]
}
}
}
}
When an additionalModels entry has the same id as a discovered model, it updates that model in place.
Provider override reference
Every entry under agents.providers accepts these fields:
| Field | Type | Required | Description |
|---|---|---|---|
extends |
string |
Yes (custom only) | Built-in provider ID to inherit from, or "acp" |
label |
string |
Yes (custom only) | Display name in the UI |
description |
string |
No | Short description shown in the UI |
command |
string[] |
Yes (ACP only) | Command to spawn the agent process |
env |
Record<string, string> |
No | Environment variables to set for the agent process |
params |
Record<string, unknown> |
No | Provider-specific options such as supportsMcpServers: false |
models |
ProviderProfileModel[] |
No | Static model list (overrides runtime discovery) |
additionalModels |
ProviderProfileModel[] |
No | Static model additions (merged with runtime discovery or models) |
disallowedTools |
string[] |
No | Tool names to disable for this provider (e.g. ["WebSearch"]) |
enabled |
boolean |
No | Set to false to hide the provider (default: true) |
order |
number |
No | Sort order in the provider list |
Model definition
Each entry in the models array:
| Field | Type | Required | Description |
|---|---|---|---|
id |
string |
Yes | Model identifier sent to the provider |
label |
string |
Yes | Display name in the UI |
description |
string |
No | Short description |
isDefault |
boolean |
No | Mark as the default model selection |
thinkingOptions |
ThinkingOption[] |
No | Available thinking/reasoning levels |
Thinking option
| Field | Type | Required | Description |
|---|---|---|---|
id |
string |
Yes | Thinking option identifier |
label |
string |
Yes | Display name |
description |
string |
No | Short description |
isDefault |
boolean |
No | Mark as the default thinking option |
Claude settings.json model discovery
The built-in claude provider appends concrete model IDs from ~/.claude/settings.json to its first-party Claude model list. Paseo reads the top-level model field and these env keys: ANTHROPIC_MODEL, ANTHROPIC_SMALL_FAST_MODEL, ANTHROPIC_DEFAULT_OPUS_MODEL, ANTHROPIC_DEFAULT_SONNET_MODEL, and ANTHROPIC_DEFAULT_HAIKU_MODEL.
This lets users who already configured Claude Code for Bedrock, OpenRouter, ollama, Z.AI, or another Anthropic-compatible gateway select the exact model ID in Paseo. When agents.providers.claude.models is set it replaces both the hardcoded first-party Claude list and any settings.json-discovered entries; use agents.providers.claude.additionalModels to keep the first-party list and append curated entries on top.
Gotcha: extends: "claude" with third-party endpoints
When a custom provider extends "claude" but points ANTHROPIC_BASE_URL at a non-Anthropic API (Z.AI, Alibaba/Qwen, proxies), the Claude Agent SDK may try to use Anthropic-only server-side tools like WebSearch. Third-party APIs don't support these tools, causing errors.
Use disallowedTools to disable unsupported tools:
{
"agents": {
"providers": {
"my-proxy": {
"extends": "claude",
"label": "My Proxy",
"env": {
"ANTHROPIC_BASE_URL": "https://my-proxy.example.com/v1"
},
"disallowedTools": ["WebSearch"]
}
}
}
}
Valid extends values
Built-in providers: claude, codex, copilot, opencode, pi, omp
Special value: acp — creates a generic ACP provider (requires command)
Full example
A config.json with multiple custom providers:
{
"version": 1,
"agents": {
"providers": {
"copilot": { "enabled": false },
"zai": {
"extends": "claude",
"label": "ZAI",
"env": {
"ANTHROPIC_AUTH_TOKEN": "<zai-api-key>",
"ANTHROPIC_BASE_URL": "https://api.z.ai/api/anthropic",
"API_TIMEOUT_MS": "3000000"
},
"disallowedTools": ["WebSearch"],
"models": [
{ "id": "glm-4.5-air", "label": "GLM 4.5 Air" },
{ "id": "glm-5-turbo", "label": "GLM 5 Turbo", "isDefault": true },
{ "id": "glm-5.1", "label": "GLM 5.1" }
]
},
"qwen": {
"extends": "claude",
"label": "Qwen (Alibaba)",
"env": {
"ANTHROPIC_AUTH_TOKEN": "sk-sp-<coding-plan-key>",
"ANTHROPIC_BASE_URL": "https://coding-intl.dashscope.aliyuncs.com/apps/anthropic"
},
"disallowedTools": ["WebSearch"],
"models": [
{ "id": "qwen3.5-plus", "label": "Qwen 3.5 Plus", "isDefault": true },
{ "id": "qwen3-coder-next", "label": "Qwen 3 Coder Next" }
]
},
"gemini": {
"extends": "acp",
"label": "Google Gemini",
"command": ["gemini", "--acp"]
},
"hermes": {
"extends": "acp",
"label": "Hermes",
"command": ["hermes", "acp"]
}
}
}
}