* docs: rename to lowercase + drop leftover plans Rename docs in docs/ to lowercase kebab-case for consistency and update all references in CLAUDE.md, CONTRIBUTING.md, CHANGELOG.md, packages/server/CLAUDE.md, and inter-doc links. Drop two leftover design plan docs: - docs/ATTACHMENT_BASED_REVIEW_CONTEXT_PLAN.md - docs/plan-approval-normalization.md * docs: drop stale uppercase entries from case-insensitive rename * feat(website): power /docs from public-docs/ markdown tree Move website docs out of TSX route components and into a root-level public-docs/ directory of plain markdown files with frontmatter (title, description, nav, order). - Add packages/website/src/docs.ts loader using import.meta.glob with ?raw to compile the markdown into the bundle at build time. - Replace the 9 hand-written docs/*.tsx routes with a single $.tsx catch-all that renders any slug via react-markdown. - Drive the docs sidebar nav from frontmatter order/nav. - Auto-discover docs routes in vite.config.ts so the sitemap stays in sync without manual edits. * fix(website): bind dev server to 0.0.0.0 so port collisions trigger fallback `host: "127.0.0.1"` (or unset) lets macOS coexist with another process holding an IPv6 dual-stack `*:8082` socket, so Vite never sees EADDRINUSE and silently binds alongside it. Forcing IPv4 wildcard makes the conflict real, and Vite's default `strictPort: false` falls through to the next free port. * fix(website): restore docs page styling after markdown migration Add a .docs-prose class that mirrors the styling the original docs/*.tsx components hand-rolled (h1/h2/h3 sizes, paragraph/list spacing, link colors, code blocks, callout-style blockquotes). ReactMarkdown was emitting unstyled HTML because the previous wrapper class only had inline-code rules — headings and code blocks fell back to user-agent defaults.
19 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
- 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). 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
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"
},
"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"
},
"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-M2.5 |
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
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.
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 (providers are enabled by default).
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.
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)
Example: Google Gemini CLI
Gemini CLI supports ACP via the --acp flag.
- Install:
npm install -g @anthropic-ai/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 |
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 |
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
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"
},
"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"
},
"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"]
}
}
}
}