# Server host/interface to bind to. Default is empty ("") to bind all interfaces (IPv4 + IPv6).# Use "127.0.0.1" or "localhost" to restrict access to local machine only.host: "" # Server portport: 8317 # TLS settings for HTTPS. When enabled, the server listens with the provided certificate and key.tls: enable: false cert: "" key: "" # Management API settingsremote-management: # Whether to allow remote (non-localhost) management access. # When false, only localhost can access management endpoints (a key is still required). allow-remote: false # Management key. If a plaintext value is provided here, it will be hashed on startup. # All management requests (even from localhost) require this key. # Leave empty to disable the Management API entirely (404 for all /v0/management routes). secret-key: "" # Disable the bundled management control panel asset download and HTTP route when true. disable-control-panel: false # Disable automatic periodic background updates of the management panel from GitHub (default: false). # When enabled, the panel is only downloaded on first access if missing, and never auto-updated afterward. # disable-auto-update-panel: false # GitHub repository for the management control panel. Accepts a repository URL or releases API URL. panel-github-repository: "https://github.com/router-for-me/Cli-Proxy-API-Management-Center" # Authentication directory (supports ~ for home directory)auth-dir: "~/.cli-proxy-api" # API keys for authenticationapi-keys: - "your-api-key-1" - "your-api-key-2" - "your-api-key-3" # Enable debug loggingdebug: false # Enable pprof HTTP debug server (host:port). Keep it bound to localhost for safety.pprof: enable: false addr: "127.0.0.1:8316" # Enable local network mDNS / DNS-SD service discovery (RFC 6762 / RFC 6763).# When enabled, broadcasts _ai-gateway._tcp with API protocol subtypes on the local network.# NOTE for Docker users: Link-local multicast (224.0.0.251) cannot cross default NAT bridge networks.# To broadcast across the physical LAN, run the container with host networking (--net=host / network_mode: host).discovery: enabled: false # service-name: "" # Optional name prefix. Advertised as CPA-<ShortID> or <name>-<ShortID> (e.g. office-8F3B) # service-type: "_ai-gateway._tcp" # Service type (RFC 6335 compliant) # subtypes: # DNS-SD API protocol subtypes to advertise # - "_chat-completions" # - "_responses" # - "_messages" # - "_generate-content" # - "_interactions" # interfaces: # include: [] # White-listed interfaces (empty: auto-detect physical interfaces) # exclude: [] # Additional interface patterns to exclude # auth-required: true # Advertise that credentials are required # Credential concurrency is configured by Home in Home mode. The synthesized Home config is# authoritative and local values, including the values below, are ignored. Do not use local# configuration to override a Home concurrency policy.# credential-concurrency:# lifecycle-config-revision: 1# observation-barrier-revision: 0# cpa-heartbeat-timeout: "3s"# cpa-cancel-bound: "5s"# reclaim-grace: "5s"# cleanup-interval: "5s"# release-flush-interval: 250ms# release-max-backoff: 2s# busy-retry-min: 250ms# busy-retry-max: 1s# max-limit: 1000000 # Credential in-flight observation snapshot contract.# credential-in-flight:# snapshot-interval: 2s# stale-after: 10s# max-part-bytes: 262144# max-part-count: 64# max-revision-bytes: 16777216# max-aggregate-groups: 100000# max-details: 10000# max-string-bytes: 256# staging-retention: 1m # Standard dynamic library plugins are trusted in-process code. They are disabled by default.# Build Go examples with go build -buildmode=c-shared for the target GOOS/GOARCH.# Other languages can implement the same C ABI and JSON method protocol.# Plugin executors require a matching auth record with the same provider key.# If the same provider is configured as OpenAI-compatible, the native executor wins.# Plugin command-line flags and Management API routes are optional capabilities.# Existing native flags/routes and higher-priority plugin flags/routes cannot be replaced.# Plugin list Management API reads Logo and ConfigFields from plugin metadata for management UI display.# Per-plugin enabled only controls plugins.configs.<pluginID>.enabled and does not implicitly change global plugins.enabled.plugins: enabled: false dir: "plugins" # Additional plugin store registries. The built-in official registry is always included. # store-sources: # - "https://example.com/cliproxy-plugins/registry.json" # Optional plugin store auth rules. Values are read from environment variables; # tokens are not written into plugin manifests or node status. # store-auth: # - match: "https://example.com/cliproxy-plugins/" # apply-to: ["registry", "artifact"] # type: bearer # token-env: "CLIPROXY_PLUGIN_STORE_TOKEN" configs: example: enabled: true priority: 1 config1: true config2: "string" config3: 3 mode: "safe" # enum example: safe, fast # When true, disable high-overhead request logging and HTTP middleware features to reduce per-request memory usage under high concurrency.commercial-mode: false # When true, write application logs to rotating files instead of stdoutlogging-to-file: false # Maximum total size (MB) of log files under the logs directory. When exceeded, the oldest log# files are deleted until within the limit. Set to 0 to disable.logs-max-total-size-mb: 0 # Maximum number of error log files retained when request logging is disabled.# When exceeded, the oldest error log files are deleted. Default is 10. Set to 0 to disable cleanup.error-logs-max-files: 10 # When false, disable in-memory usage statistics aggregationusage-statistics-enabled: false # How long (in seconds) usage queue items are retained in memory for the Management API.# The local Redis RESP usage output is disabled.# Default: 60. Max: 3600.redis-usage-queue-retention-seconds: 60 # Proxy URL. Supports socks5/http/https protocols. Example: socks5://user:pass@192.168.1.1:1080/# Per-entry proxy-url also supports "direct" or "none" to bypass both the global proxy-url and environment proxies explicitly.proxy-url: "" # When true, unprefixed model requests only use credentials without a prefix (except when prefix == model name).force-model-prefix: false # When true, forward filtered upstream response headers to downstream clients.# Default is false (disabled).passthrough-headers: false # Number of additional credential retry rounds after the first round exhausts# its eligible credentials. Round 0 is the initial round; round r only admits# credentials whose effective request-retry is at least r. Explicit non-negative# credential/provider overrides take precedence; omitted or negative overrides# inherit this global value, and explicit 0 only admits round 0. New CPA nodes# send retry_round=0 for the initial round and increment it for additional rounds;# legacy dispatch methods omit the field and keep old semantics.# Additional rounds apply to HTTP 403, 408, 429, 500, 502, 503, and 504 failures.# Individual credential/provider overrides take precedence; 0 disables additional# rounds, while an omitted or negative override inherits this global setting.request-retry: 3 # Maximum number of different credentials to try in each credential retry round# after per-credential round filtering. Set to 0 to try all available# credentials. Credentials skipped by this cap still age with the global round,# so the cap does not guarantee a fixed number of actual retries per credential.max-retry-credentials: 0 # Maximum cooldown wait in seconds between retry rounds.# Set to 0 or below to never wait for credential cooldown.# Retry rounds that need no wait remain controlled by request-retry.max-retry-interval: 30 # When true, disable auth/model cooldown scheduling globally (prevents blackout windows after failure states).# A credential/provider disable-cooling value, when present, overrides this global value.disable-cooling: false # When true, persist per-auth cooldown status as .cds files next to auth files.# Default is false; when false, cooldown status is kept in memory only.save-cooldown-status: false # Cooldown duration in seconds for transient upstream errors (408/500/502/503/504/520-526).# Set to 0 to keep the legacy 60-second cooldown; set to -1 to disable transient error cooldowns.transient-error-cooldown-seconds: 0 # When true, globally disable Claude request cloaking (the Claude Code CLI disguise and# system prompt replacement), so the original system prompt is passed through to Claude as-is.# Individual credentials can still override this: a claude-api-key entry via its "cloak.mode",# or a Claude OAuth/token file via a "cloak_mode" value. Default false keeps the per-client# "auto" behavior (cloak only non-Claude-Code clients).disable-claude-cloak-mode: false # Claude Code compatibility settings.claude-code: # When true, return original model IDs in Anthropic model list responses instead of cloaked IDs. disable-cloaking-model-list: false # disable-image-generation supports: false (default), true, "chat", or "passthrough".# - true: disable image_generation everywhere (also returns 404 for /v1/images/generations and /v1/images/edits).# - "chat": disable image_generation injection on non-images endpoints, but keep /v1/images/generations and /v1/images/edits enabled.# - "passthrough": never inject or strip image_generation on non-images endpoints (forward the client payload unchanged); behaves like "chat" on /v1/images/* endpoints.disable-image-generation: false # Base model used by the legacy hosted image_generation tool path when a Codex image request is not proxied directly through the Image API.# Must start with "gpt-" (case-insensitive). If unset or invalid, defaults to "gpt-5.4-mini".# gpt-image-2-base-model: "gpt-5.4-mini" # How long video IDs returned by /openai/v1/videos and xAI video creation stay bound# to the credential that created them. Default: 3h.video-result-auth-cache-ttl: "3h" # Core auth auto-refresh and manual refresh-all worker pool size (OAuth/file-based auth token refresh).# When > 0, overrides the default worker count (16).# auth-auto-refresh-workers: 16 # Quota exceeded behaviorquota-exceeded: switch-project: true # Whether to automatically switch to another project when a quota is exceeded switch-preview-model: true # Whether to automatically switch to a preview model when a quota is exceeded antigravity-credits: true # Whether to use credits as last-resort fallback when all free-tier auths are exhausted for Claude models # Routing strategy for selecting credentials when multiple match.routing: strategy: "round-robin" # round-robin (default), weighted-round-robin, fill-first # weighted-round-robin uses each credential's integer weight (default 1, maximum 1,000,000). # Non-positive weights exclude the credential while this strategy is active. # For OAuth/file credentials, add a top-level numeric "weight" field to the auth JSON. # Enable universal session-sticky routing for all clients. # Explicit Claude Code, Codex, OpenCode, and pi session headers are preferred, # followed by prompt_cache_key, Responses conversation IDs, legacy body IDs, # execution or derived session identity, and the existing first-message hash fallback. # Automatic failover is always enabled when bound auth becomes unavailable. # An established binding outranks credential priority: once a session is bound, that # credential is kept even if a higher-priority credential recovers. Credential priority # still decides cold bindings, requests without a session, and post-failover rebinding. session-affinity: false # default: false # How long session-to-auth bindings are retained. Default: 1h session-affinity-ttl: "1h" # When true (default), subagents (child sessions with parent references) inherit and bind # to the parent's upstream credential across all providers (Claude, Codex, Antigravity, Gemini), # maximizing Prompt/KV Cache reuse and minimizing TTFT. # When false, subagents are distributed across the credential pool via the fallback selector # for maximum parallel concurrency. # Ignored when routing.session-affinity is false. session-affinity-subagents: true # Codex provider behavior.codex: # When true, and routing.strategy is fill-first or routing.session-affinity is true, # remap Codex prompt_cache_key and installation identity per selected auth. # Some superstitious users believe request tracking identifiers can be used # as evidence for TOS enforcement bans; this option only satisfies those odd concerns. identity-confuse: false # Disable forcing the official Codex User-Agent and Originator headers on HTTP/SSE and WebSocket requests. disable-codex-cloaking: false # Hold back the frames that carry nothing the client has seen - the handshake (response.created, # response.in_progress, the websocket metadata frames), keepalive heartbeats, and the *.added # announcements of an item or part that is still empty - until the upstream emits its first # generated event. Anything else, including a server-side tool item such as web_search_call and # any frame not on that list, releases the stream immediately. On the SSE transport the lines that # are not `data:` frames - comments, `event:` lines, blank separators - are held alongside them. # The hold is bounded by a frame budget and a 1 MiB byte budget, not by wall-clock time: an # upstream that trickles frames holds the response headers for as long as the client will wait. # Why: the upstream smuggles `server_is_overloaded` rejections *inside* an HTTP 200 stream, # right after those handshake events, instead of returning 503 on the wire. Buffering them # keeps the downstream response headers uncommitted long enough to transparently retry on # another credential. Only overload/rate-limit rejections trigger failover; every other terminal # failure is still delivered in-stream exactly as before. One pre-existing behaviour is worth # knowing, because this option makes the window it lives in much longer: if the stream ends while # the bootstrap is still holding, the attempt ends instead of the error reaching the client, and # whether another credential is then tried depends on how it ended. A clean end with no terminal # event is request-scoped on SSE, so nothing else is tried; a websocket close, or a transport error # such as a dropped connection on either transport, is not, so the request may be retried on # another credential. None of that is new, but before this option the hold ended at the first # keepalive, so it was rare; now it can span the whole reasoning phase. # Trade-off: response headers are delayed until generation starts. Because heartbeats are held # too, the delay now ends at the first generated token rather than at the first heartbeat. The # budget bounds how much is held, not how long: 48 SSE lines, which measures out as 15 heartbeats # of the three-line event:/data:/blank shape, 23 of a two-line ": keepalive" comment followed by # its blank separator, or 47 of a bare ": keepalive" with no separator - one short of the obvious # division, because the rejection frame's own event: line comes out of the same budget before its # data: line is parsed. An upstream that sends the rejection as a bare data: line with no event: # line gets the round number instead. At a 10s upstream heartbeat that is 150s, 230s or 470s of # uncommitted response headers depending on the framing the upstream picks, all of it past nginx's # 60s default proxy_read_timeout, so raise the timeouts in front of the proxy before enabling this. # Those seconds bound what the buffer holds, not when the response headers are committed. Headers # are committed on the first chunk the downstream translator actually produces, so for a format # that renders the handshake as nothing - Chat Completions and Gemini do - they stay uncommitted # past the budget, until the first generated token. That is not specific to the budget: any frame # that releases the buffer has always behaved this way. # The websocket transport spends the same 48 differently - one per message read, whether the loop # holds it or skips it, with no framing to divide by - so there it is 48 heartbeats, about 480s. # Two cases no budget covers: a websocket peer that sends only ping frames, which the library # answers inside the read call, leaving only the 5 minute websocket read deadline; and an upstream # that stops mid-line on SSE, where the scanner never returns and only the request context ends the # wait. Neither is made worse by this option - with it off the same stalled line stalls the # conductor instead, which waits on the same context - but a client-side request timeout, not # proxy_read_timeout, is what bounds them. # Default: false stream-bootstrap-buffering: false # Optional maximum duration to hold back uncommitted response headers during bootstrap buffering. # When set (e.g. "20s"), if the time ceiling is reached before the first generated token, # the stream is released to the client and further in-stream overloads are delivered rather # than failed over. This bounds how long trickled heartbeats or early empty frames can delay # response headers before streaming begins. # Recommendation: If your CPA is deployed behind a reverse proxy with a strict read timeout # (e.g. Nginx default proxy_read_timeout 60s or Cloudflare 100s timeout), setting this to "20s" # is strongly recommended to guarantee headers commit well before proxy timeouts while retaining # a comfortable 20s window to fail over early scheduling overloads. # Note: The timeout check is evaluated as upstream frames arrive; it never aborts the upstream # connection. Downstream headers are committed as soon as the downstream translator emits chunks # (for formats that render handshake/heartbeats, headers commit immediately on release; for # formats like Chat Completions and Gemini that render nothing until the first text token, headers # commit when that first token arrives). # When unset or set to "0", "0s", "none", "unlimited", "disabled", "off", or "never", no time ceiling # is applied, and buffering relies purely on the 48-frame and 1MB byte budget. # Default: "0" (unlimited) stream-bootstrap-timeout: "0" # When true, optimize Codex Desktop, codex-tui, and codex_cli_rs requests for multi-agent v2. # This refreshes Codex spawn_agent model details, removes message parameter encryption, # normalizes encrypted agent_message content for Codex, and converts agent_message input # into standard user messages for non-Codex upstream protocols. optimize-multi-agent-v2: false # When true, enable opt-in compatibility for orphan Codex delegation outputs. # Converts orphan function_call_output items from codex_app/create_thread and # codex_app/send_message_to_thread (which lack a valid call_id or matching function_call) # into standard user messages across Responses and non-Codex protocols when the request # header contains X-Openai-Subagent: collab_spawn. orphan-delegation-compatibility: false # When true, scope Codex usage_limit_reached quota cooldowns to the requested model rather # than cooling down the entire credential across all sibling models. # Default: false model-level-cooling: false # Terminate and relay Codex Live WebRTC audio and DataChannel traffic in this process. # This requires inbound UDP reachability. Keep disabled to preserve direct media behavior. live-media-relay: enabled: false # Maximum concurrent media sessions. Zero uses the default of 32. max-sessions: 32 # Reject downstream SDP candidates that target private, loopback, link-local, or unspecified IPs. # Keep false for local or trusted-network Codex Desktop connections. disable-private-remote-ips: false # Public IPv4 or IPv6 address advertised when CPA is behind 1:1 NAT. public-ip: "" # Optional UDP allocation range. Both values must be set together and provide at least two ports per session. udp-port-min: 0 udp-port-max: 0 # Optional STUN/TURN servers. TURN credentials are never returned by the JSON config API. # Without a concrete global/per-auth proxy-url, WebRTC uses normal direct ICE/STUN/TURN connectivity. # With http, https, socks5, or socks5h proxy-url, the OpenAI-facing leg is forced through # authenticated ICE-TCP over that proxy and never falls back to UDP or a direct connection. # The Codex Desktop-facing leg remains direct, and configured ICE servers still apply to it. # ice-servers: # - urls: # - "stun:stun.example.com:3478" # - urls: # - "turn:turn.example.com:3478?transport=udp" # username: "user" # credential: "secret" # Antigravity provider behavior.# antigravity:# sensitive-words: # optional: words to obfuscate with zero-width characters in system instructions# - "API"# - "proxy"# connection-pool: # optional: upstream HTTP connection pool settings# enabled: false # whether to enable connection pooling (default: false; set to true to enable connection pooling)# idle-conn-timeout: "30s" # idle keep-alive timeout (default: 30s, capped at 210s)# max-idle-conns-per-host: 2 # max idle connections per host per credential (default: 2) # Devin provider behavior.# devin:# sensitive-words: # optional: words to obfuscate with zero-width characters in system instructions and prompts# - "API"# - "proxy" # xAI provider behavior.xai: # When true, inject the native x_search tool when the request does not declare it. # The injected tool is also added to tool_choice.allowed_tools when applicable. inject-x-search: false # When true, enable authentication for the WebSocket API (/v1/ws).ws-auth: true # When > 0, emit blank lines every N seconds for non-streaming responses to prevent idle timeouts.nonstream-keepalive-interval: 0# Streaming behavior (SSE keep-alives + safe bootstrap retries).# streaming:# keepalive-seconds: 15 # Default: 0 (disabled). <= 0 disables keep-alives.# bootstrap-retries: 1 # Default: 0 (disabled). Retries before first byte is sent. # Signature cache validation for thinking blocks (Antigravity/Claude).# When true (default), cached signatures are preferred and validated.# When false, client signatures are used directly after normalization (bypass mode for testing).# antigravity-signature-cache-enabled: true # Bypass mode signature validation strictness (only applies when signature cache is disabled).# When true, validates full Claude protobuf tree (Field 2 -> Field 1 structure).# When false (default), only checks R/E prefix + base64 + first byte 0x12.# antigravity-signature-bypass-strict: false # Gemini API keys# gemini-api-key:# - api-key: "AIzaSy...01"# weight: 5 # optional: weighted-round-robin share; omitted defaults to 1; maximum 1,000,000# prefix: "test" # optional: require calls like "test/gemini-3-pro-preview" to target this credential# disable-cooling: false # optional override: true disables cooling, false enables it; omit to inherit global# request-retry: 3 # optional per-auth override; 0 disables additional rounds; omit or set < 0 to inherit global# request-scoped-errors: # optional: custom rules to classify upstream errors by status and body patterns# - status: 400 # HTTP status code to match# match: # optional: string contains matching# - "maximum_context_length"# - "context_length_exceeded"# match-regexr: # optional: regular expression matching# - "maximum_context_length$"# - "^context_length_exceeded"# action: "stop" # "stop" (return error, no cooling), "stop-and-cooldown" (return error and cool down),# # "continue" (try next credential, no cooling), "continue-and-cooldown" (try next credential and cool down)# base-url: "https://generativelanguage.googleapis.com"# headers:# X-Custom-Header: "custom-value"# # Values starting with "$" dynamically copy the header value from downstream client requests.# # If the client did not send the specified header, the header is omitted.# # X-Claude-Code-Session-Id: "$ABC" # copies client's "ABC" header# proxy-url: "socks5://proxy.example.com:1080"# # proxy-url: "direct" # optional: explicit direct connect for this credential# models:# - name: "gemini-2.5-flash" # upstream model name# alias: "gemini-flash" # client alias mapped to the upstream model# display-name: "Gemini Flash" # optional catalog display name# max-context-length: 1048576 # optional: override Codex client context window metadata# is-compat: false # optional: preserve thinking blocks with empty signatures for compatible upstreams# thinking: # optional: exact thinking capability for this configured model# levels: ["high", "medium", "low", "none", "auto"]# excluded-models:# - "gemini-2.5-pro" # exclude specific models from this provider (exact match)# - "gemini-2.5-*" # wildcard matching prefix (e.g. gemini-2.5-flash, gemini-2.5-pro)# - "*-preview" # wildcard matching suffix (e.g. gemini-3-pro-preview)# - "*flash*" # wildcard matching substring (e.g. gemini-2.5-flash-lite)# - api-key: "AIzaSy...02" # Native Interactions API keys# These keys are used only for direct /v1beta/interactions execution. Regular gemini-api-key entries still# send Gemini generateContent/streamGenerateContent requests when the client enters through the interactions API.# interactions-api-key:# - api-key: "AIzaSy...03"# weight: 5 # optional: weighted-round-robin share; omitted defaults to 1; maximum 1,000,000# prefix: "native" # optional: require calls like "native/gemini-3-pro-preview" to target this credential# disable-cooling: false # optional override: true disables cooling, false enables it; omit to inherit global# request-retry: 3 # optional per-auth override; 0 disables additional rounds; omit or set < 0 to inherit global# request-scoped-errors: # optional: custom rules to classify upstream errors by status and body patterns# - status: 400# match:# - "invalid_argument"# action: "continue"# base-url: "https://generativelanguage.googleapis.com"# headers:# X-Custom-Header: "custom-value"# # Values starting with "$" dynamically copy the header value from downstream client requests.# # If the client did not send the specified header, the header is omitted.# # X-Claude-Code-Session-Id: "$ABC" # copies client's "ABC" header# proxy-url: "socks5://proxy.example.com:1080"# # proxy-url: "direct" # optional: explicit direct connect for this credential# models:# - name: "gemini-2.5-flash" # upstream model name# alias: "native-gemini-flash" # client alias mapped to the upstream model# max-context-length: 1048576 # optional: override Codex client context window metadata# is-compat: false # optional: preserve thinking blocks with empty signatures for compatible upstreams# thinking: # optional: exact thinking capability for this configured model# levels: ["high", "medium", "low", "none", "auto"]# excluded-models:# - "gemini-2.5-pro" # Codex API keys# codex-api-key:# - api-key: "sk-atSM..."# weight: 5 # optional: weighted-round-robin share; omitted defaults to 1; maximum 1,000,000# prefix: "test" # optional: require calls like "test/gpt-5-codex" to target this credential# disable-cooling: false # optional override: true disables cooling, false enables it; omit to inherit global# request-retry: 3 # optional per-auth override; 0 disables additional rounds; omit or set < 0 to inherit global# request-scoped-errors: # optional: custom rules to classify upstream errors by status and body patterns# - status: 400# match:# - "context_window_exceeded"# action: "stop-and-cooldown"# base-url: "https://www.example.com" # use the custom codex API endpoint# alpha-search: false # optional: allow this key to serve /v1/alpha/search via base-url + /alpha/searchLines 1–500 of 989. Load more
# Server host/interface to bind to. Default is empty ("") to bind all interfaces (IPv4 + IPv6). # Use "127.0.0.1" or "localhost" to restrict access to local machine only. host: "" # Server port port: 8317 # TLS settings for HTTPS. When enabled, the server listens with the provided certificate and key. tls: enable: false cert: "" key: "" # Management API settings remote-management: # Whether to allow remote (non-localhost) management access. # When false, only localhost can access management endpoints (a key is still required). allow-remote: false # Management key. If a plaintext value is provided here, it will be hashed on startup. # All management requests (even from localhost) require this key. # Leave empty to disable the Management API entirely (404 for all /v0/management routes). secret-key: "" # Disable the bundled management control panel asset download and HTTP route when true. disable-control-panel: false # Disable automatic periodic background updates of the management panel from GitHub (default: false). # When enabled, the panel is only downloaded on first access if missing, and never auto-updated afterward. # disable-auto-update-panel: false # GitHub repository for the management control panel. Accepts a repository URL or releases API URL. panel-github-repository: "https://github.com/router-for-me/Cli-Proxy-API-Management-Center" # Authentication directory (supports ~ for home directory) auth-dir: "~/.cli-proxy-api" # API keys for authentication api-keys: - "your-api-key-1" - "your-api-key-2" - "your-api-key-3" # Enable debug logging debug: false # Enable pprof HTTP debug server (host:port). Keep it bound to localhost for safety. pprof: enable: false addr: "127.0.0.1:8316" # Enable local network mDNS / DNS-SD service discovery (RFC 6762 / RFC 6763). # When enabled, broadcasts _ai-gateway._tcp with API protocol subtypes on the local network. # NOTE for Docker users: Link-local multicast (224.0.0.251) cannot cross default NAT bridge networks. # To broadcast across the physical LAN, run the container with host networking (--net=host / network_mode: host). discovery: enabled: false # service-name: "" # Optional name prefix. Advertised as CPA-<ShortID> or <name>-<ShortID> (e.g. office-8F3B) # service-type: "_ai-gateway._tcp" # Service type (RFC 6335 compliant) # subtypes: # DNS-SD API protocol subtypes to advertise # - "_chat-completions" # - "_responses" # - "_messages" # - "_generate-content" # - "_interactions" # interfaces: # include: [] # White-listed interfaces (empty: auto-detect physical interfaces) # exclude: [] # Additional interface patterns to exclude # auth-required: true # Advertise that credentials are required # Credential concurrency is configured by Home in Home mode. The synthesized Home config is # authoritative and local values, including the values below, are ignored. Do not use local # configuration to override a Home concurrency policy. # credential-concurrency: # lifecycle-config-revision: 1 # observation-barrier-revision: 0 # cpa-heartbeat-timeout: "3s" # cpa-cancel-bound: "5s" # reclaim-grace: "5s" # cleanup-interval: "5s" # release-flush-interval: 250ms # release-max-backoff: 2s # busy-retry-min: 250ms # busy-retry-max: 1s # max-limit: 1000000 # Credential in-flight observation snapshot contract. # credential-in-flight: # snapshot-interval: 2s # stale-after: 10s # max-part-bytes: 262144 # max-part-count: 64 # max-revision-bytes: 16777216 # max-aggregate-groups: 100000 # max-details: 10000 # max-string-bytes: 256 # staging-retention: 1m # Standard dynamic library plugins are trusted in-process code. They are disabled by default. # Build Go examples with go build -buildmode=c-shared for the target GOOS/GOARCH. # Other languages can implement the same C ABI and JSON method protocol. # Plugin executors require a matching auth record with the same provider key. # If the same provider is configured as OpenAI-compatible, the native executor wins. # Plugin command-line flags and Management API routes are optional capabilities. # Existing native flags/routes and higher-priority plugin flags/routes cannot be replaced. # Plugin list Management API reads Logo and ConfigFields from plugin metadata for management UI display. # Per-plugin enabled only controls plugins.configs.<pluginID>.enabled and does not implicitly change global plugins.enabled. plugins: enabled: false dir: "plugins" # Additional plugin store registries. The built-in official registry is always included. # store-sources: # - "https://example.com/cliproxy-plugins/registry.json" # Optional plugin store auth rules. Values are read from environment variables; # tokens are not written into plugin manifests or node status. # store-auth: # - match: "https://example.com/cliproxy-plugins/" # apply-to: ["registry", "artifact"] # type: bearer # token-env: "CLIPROXY_PLUGIN_STORE_TOKEN" configs: example: enabled: true priority: 1 config1: true config2: "string" config3: 3 mode: "safe" # enum example: safe, fast # When true, disable high-overhead request logging and HTTP middleware features to reduce per-request memory usage under high concurrency. commercial-mode: false # When true, write application logs to rotating files instead of stdout logging-to-file: false # Maximum total size (MB) of log files under the logs directory. When exceeded, the oldest log # files are deleted until within the limit. Set to 0 to disable. logs-max-total-size-mb: 0 # Maximum number of error log files retained when request logging is disabled. # When exceeded, the oldest error log files are deleted. Default is 10. Set to 0 to disable cleanup. error-logs-max-files: 10 # When false, disable in-memory usage statistics aggregation usage-statistics-enabled: false # How long (in seconds) usage queue items are retained in memory for the Management API. # The local Redis RESP usage output is disabled. # Default: 60. Max: 3600. redis-usage-queue-retention-seconds: 60 # Proxy URL. Supports socks5/http/https protocols. Example: socks5://user:pass@192.168.1.1:1080/ # Per-entry proxy-url also supports "direct" or "none" to bypass both the global proxy-url and environment proxies explicitly. proxy-url: "" # When true, unprefixed model requests only use credentials without a prefix (except when prefix == model name). force-model-prefix: false # When true, forward filtered upstream response headers to downstream clients. # Default is false (disabled). passthrough-headers: false # Number of additional credential retry rounds after the first round exhausts # its eligible credentials. Round 0 is the initial round; round r only admits # credentials whose effective request-retry is at least r. Explicit non-negative # credential/provider overrides take precedence; omitted or negative overrides # inherit this global value, and explicit 0 only admits round 0. New CPA nodes # send retry_round=0 for the initial round and increment it for additional rounds; # legacy dispatch methods omit the field and keep old semantics. # Additional rounds apply to HTTP 403, 408, 429, 500, 502, 503, and 504 failures. # Individual credential/provider overrides take precedence; 0 disables additional # rounds, while an omitted or negative override inherits this global setting. request-retry: 3 # Maximum number of different credentials to try in each credential retry round # after per-credential round filtering. Set to 0 to try all available # credentials. Credentials skipped by this cap still age with the global round, # so the cap does not guarantee a fixed number of actual retries per credential. max-retry-credentials: 0 # Maximum cooldown wait in seconds between retry rounds. # Set to 0 or below to never wait for credential cooldown. # Retry rounds that need no wait remain controlled by request-retry. max-retry-interval: 30 # When true, disable auth/model cooldown scheduling globally (prevents blackout windows after failure states). # A credential/provider disable-cooling value, when present, overrides this global value. disable-cooling: false # When true, persist per-auth cooldown status as .cds files next to auth files. # Default is false; when false, cooldown status is kept in memory only. save-cooldown-status: false # Cooldown duration in seconds for transient upstream errors (408/500/502/503/504/520-526). # Set to 0 to keep the legacy 60-second cooldown; set to -1 to disable transient error cooldowns. transient-error-cooldown-seconds: 0 # When true, globally disable Claude request cloaking (the Claude Code CLI disguise and # system prompt replacement), so the original system prompt is passed through to Claude as-is. # Individual credentials can still override this: a claude-api-key entry via its "cloak.mode", # or a Claude OAuth/token file via a "cloak_mode" value. Default false keeps the per-client # "auto" behavior (cloak only non-Claude-Code clients). disable-claude-cloak-mode: false # Claude Code compatibility settings. claude-code: # When true, return original model IDs in Anthropic model list responses instead of cloaked IDs. disable-cloaking-model-list: false # disable-image-generation supports: false (default), true, "chat", or "passthrough". # - true: disable image_generation everywhere (also returns 404 for /v1/images/generations and /v1/images/edits). # - "chat": disable image_generation injection on non-images endpoints, but keep /v1/images/generations and /v1/images/edits enabled. # - "passthrough": never inject or strip image_generation on non-images endpoints (forward the client payload unchanged); behaves like "chat" on /v1/images/* endpoints. disable-image-generation: false # Base model used by the legacy hosted image_generation tool path when a Codex image request is not proxied directly through the Image API. # Must start with "gpt-" (case-insensitive). If unset or invalid, defaults to "gpt-5.4-mini". # gpt-image-2-base-model: "gpt-5.4-mini" # How long video IDs returned by /openai/v1/videos and xAI video creation stay bound # to the credential that created them. Default: 3h. video-result-auth-cache-ttl: "3h" # Core auth auto-refresh and manual refresh-all worker pool size (OAuth/file-based auth token refresh). # When > 0, overrides the default worker count (16). # auth-auto-refresh-workers: 16 # Quota exceeded behavior quota-exceeded: switch-project: true # Whether to automatically switch to another project when a quota is exceeded switch-preview-model: true # Whether to automatically switch to a preview model when a quota is exceeded antigravity-credits: true # Whether to use credits as last-resort fallback when all free-tier auths are exhausted for Claude models # Routing strategy for selecting credentials when multiple match. routing: strategy: "round-robin" # round-robin (default), weighted-round-robin, fill-first # weighted-round-robin uses each credential's integer weight (default 1, maximum 1,000,000). # Non-positive weights exclude the credential while this strategy is active. # For OAuth/file credentials, add a top-level numeric "weight" field to the auth JSON. # Enable universal session-sticky routing for all clients. # Explicit Claude Code, Codex, OpenCode, and pi session headers are preferred, # followed by prompt_cache_key, Responses conversation IDs, legacy body IDs, # execution or derived session identity, and the existing first-message hash fallback. # Automatic failover is always enabled when bound auth becomes unavailable. # An established binding outranks credential priority: once a session is bound, that # credential is kept even if a higher-priority credential recovers. Credential priority # still decides cold bindings, requests without a session, and post-failover rebinding. session-affinity: false # default: false # How long session-to-auth bindings are retained. Default: 1h session-affinity-ttl: "1h" # When true (default), subagents (child sessions with parent references) inherit and bind # to the parent's upstream credential across all providers (Claude, Codex, Antigravity, Gemini), # maximizing Prompt/KV Cache reuse and minimizing TTFT. # When false, subagents are distributed across the credential pool via the fallback selector # for maximum parallel concurrency. # Ignored when routing.session-affinity is false. session-affinity-subagents: true # Codex provider behavior. codex: # When true, and routing.strategy is fill-first or routing.session-affinity is true, # remap Codex prompt_cache_key and installation identity per selected auth. # Some superstitious users believe request tracking identifiers can be used # as evidence for TOS enforcement bans; this option only satisfies those odd concerns. identity-confuse: false # Disable forcing the official Codex User-Agent and Originator headers on HTTP/SSE and WebSocket requests. disable-codex-cloaking: false # Hold back the frames that carry nothing the client has seen - the handshake (response.created, # response.in_progress, the websocket metadata frames), keepalive heartbeats, and the *.added # announcements of an item or part that is still empty - until the upstream emits its first # generated event. Anything else, including a server-side tool item such as web_search_call and # any frame not on that list, releases the stream immediately. On the SSE transport the lines that # are not `data:` frames - comments, `event:` lines, blank separators - are held alongside them. # The hold is bounded by a frame budget and a 1 MiB byte budget, not by wall-clock time: an # upstream that trickles frames holds the response headers for as long as the client will wait. # Why: the upstream smuggles `server_is_overloaded` rejections *inside* an HTTP 200 stream, # right after those handshake events, instead of returning 503 on the wire. Buffering them # keeps the downstream response headers uncommitted long enough to transparently retry on # another credential. Only overload/rate-limit rejections trigger failover; every other terminal # failure is still delivered in-stream exactly as before. One pre-existing behaviour is worth # knowing, because this option makes the window it lives in much longer: if the stream ends while # the bootstrap is still holding, the attempt ends instead of the error reaching the client, and # whether another credential is then tried depends on how it ended. A clean end with no terminal # event is request-scoped on SSE, so nothing else is tried; a websocket close, or a transport error # such as a dropped connection on either transport, is not, so the request may be retried on # another credential. None of that is new, but before this option the hold ended at the first # keepalive, so it was rare; now it can span the whole reasoning phase. # Trade-off: response headers are delayed until generation starts. Because heartbeats are held # too, the delay now ends at the first generated token rather than at the first heartbeat. The # budget bounds how much is held, not how long: 48 SSE lines, which measures out as 15 heartbeats # of the three-line event:/data:/blank shape, 23 of a two-line ": keepalive" comment followed by # its blank separator, or 47 of a bare ": keepalive" with no separator - one short of the obvious # division, because the rejection frame's own event: line comes out of the same budget before its # data: line is parsed. An upstream that sends the rejection as a bare data: line with no event: # line gets the round number instead. At a 10s upstream heartbeat that is 150s, 230s or 470s of # uncommitted response headers depending on the framing the upstream picks, all of it past nginx's # 60s default proxy_read_timeout, so raise the timeouts in front of the proxy before enabling this. # Those seconds bound what the buffer holds, not when the response headers are committed. Headers # are committed on the first chunk the downstream translator actually produces, so for a format # that renders the handshake as nothing - Chat Completions and Gemini do - they stay uncommitted # past the budget, until the first generated token. That is not specific to the budget: any frame # that releases the buffer has always behaved this way. # The websocket transport spends the same 48 differently - one per message read, whether the loop # holds it or skips it, with no framing to divide by - so there it is 48 heartbeats, about 480s. # Two cases no budget covers: a websocket peer that sends only ping frames, which the library # answers inside the read call, leaving only the 5 minute websocket read deadline; and an upstream # that stops mid-line on SSE, where the scanner never returns and only the request context ends the # wait. Neither is made worse by this option - with it off the same stalled line stalls the # conductor instead, which waits on the same context - but a client-side request timeout, not # proxy_read_timeout, is what bounds them. # Default: false stream-bootstrap-buffering: false # Optional maximum duration to hold back uncommitted response headers during bootstrap buffering. # When set (e.g. "20s"), if the time ceiling is reached before the first generated token, # the stream is released to the client and further in-stream overloads are delivered rather # than failed over. This bounds how long trickled heartbeats or early empty frames can delay # response headers before streaming begins. # Recommendation: If your CPA is deployed behind a reverse proxy with a strict read timeout # (e.g. Nginx default proxy_read_timeout 60s or Cloudflare 100s timeout), setting this to "20s" # is strongly recommended to guarantee headers commit well before proxy timeouts while retaining # a comfortable 20s window to fail over early scheduling overloads. # Note: The timeout check is evaluated as upstream frames arrive; it never aborts the upstream # connection. Downstream headers are committed as soon as the downstream translator emits chunks # (for formats that render handshake/heartbeats, headers commit immediately on release; for # formats like Chat Completions and Gemini that render nothing until the first text token, headers # commit when that first token arrives). # When unset or set to "0", "0s", "none", "unlimited", "disabled", "off", or "never", no time ceiling # is applied, and buffering relies purely on the 48-frame and 1MB byte budget. # Default: "0" (unlimited) stream-bootstrap-timeout: "0" # When true, optimize Codex Desktop, codex-tui, and codex_cli_rs requests for multi-agent v2. # This refreshes Codex spawn_agent model details, removes message parameter encryption, # normalizes encrypted agent_message content for Codex, and converts agent_message input # into standard user messages for non-Codex upstream protocols. optimize-multi-agent-v2: false # When true, enable opt-in compatibility for orphan Codex delegation outputs. # Converts orphan function_call_output items from codex_app/create_thread and # codex_app/send_message_to_thread (which lack a valid call_id or matching function_call) # into standard user messages across Responses and non-Codex protocols when the request # header contains X-Openai-Subagent: collab_spawn. orphan-delegation-compatibility: false # When true, scope Codex usage_limit_reached quota cooldowns to the requested model rather # than cooling down the entire credential across all sibling models. # Default: false model-level-cooling: false # Terminate and relay Codex Live WebRTC audio and DataChannel traffic in this process. # This requires inbound UDP reachability. Keep disabled to preserve direct media behavior. live-media-relay: enabled: false # Maximum concurrent media sessions. Zero uses the default of 32. max-sessions: 32 # Reject downstream SDP candidates that target private, loopback, link-local, or unspecified IPs. # Keep false for local or trusted-network Codex Desktop connections. disable-private-remote-ips: false # Public IPv4 or IPv6 address advertised when CPA is behind 1:1 NAT. public-ip: "" # Optional UDP allocation range. Both values must be set together and provide at least two ports per session. udp-port-min: 0 udp-port-max: 0 # Optional STUN/TURN servers. TURN credentials are never returned by the JSON config API. # Without a concrete global/per-auth proxy-url, WebRTC uses normal direct ICE/STUN/TURN connectivity. # With http, https, socks5, or socks5h proxy-url, the OpenAI-facing leg is forced through # authenticated ICE-TCP over that proxy and never falls back to UDP or a direct connection. # The Codex Desktop-facing leg remains direct, and configured ICE servers still apply to it. # ice-servers: # - urls: # - "stun:stun.example.com:3478" # - urls: # - "turn:turn.example.com:3478?transport=udp" # username: "user" # credential: "secret" # Antigravity provider behavior. # antigravity: # sensitive-words: # optional: words to obfuscate with zero-width characters in system instructions # - "API" # - "proxy" # connection-pool: # optional: upstream HTTP connection pool settings # enabled: false # whether to enable connection pooling (default: false; set to true to enable connection pooling) # idle-conn-timeout: "30s" # idle keep-alive timeout (default: 30s, capped at 210s) # max-idle-conns-per-host: 2 # max idle connections per host per credential (default: 2) # Devin provider behavior. # devin: # sensitive-words: # optional: words to obfuscate with zero-width characters in system instructions and prompts # - "API" # - "proxy" # xAI provider behavior. xai: # When true, inject the native x_search tool when the request does not declare it. # The injected tool is also added to tool_choice.allowed_tools when applicable. inject-x-search: false # When true, enable authentication for the WebSocket API (/v1/ws). ws-auth: true # When > 0, emit blank lines every N seconds for non-streaming responses to prevent idle timeouts. nonstream-keepalive-interval: 0 # Streaming behavior (SSE keep-alives + safe bootstrap retries). # streaming: # keepalive-seconds: 15 # Default: 0 (disabled). <= 0 disables keep-alives. # bootstrap-retries: 1 # Default: 0 (disabled). Retries before first byte is sent. # Signature cache validation for thinking blocks (Antigravity/Claude). # When true (default), cached signatures are preferred and validated. # When false, client signatures are used directly after normalization (bypass mode for testing). # antigravity-signature-cache-enabled: true # Bypass mode signature validation strictness (only applies when signature cache is disabled). # When true, validates full Claude protobuf tree (Field 2 -> Field 1 structure). # When false (default), only checks R/E prefix + base64 + first byte 0x12. # antigravity-signature-bypass-strict: false # Gemini API keys # gemini-api-key: # - api-key: "AIzaSy...01" # weight: 5 # optional: weighted-round-robin share; omitted defaults to 1; maximum 1,000,000 # prefix: "test" # optional: require calls like "test/gemini-3-pro-preview" to target this credential # disable-cooling: false # optional override: true disables cooling, false enables it; omit to inherit global # request-retry: 3 # optional per-auth override; 0 disables additional rounds; omit or set < 0 to inherit global # request-scoped-errors: # optional: custom rules to classify upstream errors by status and body patterns # - status: 400 # HTTP status code to match # match: # optional: string contains matching # - "maximum_context_length" # - "context_length_exceeded" # match-regexr: # optional: regular expression matching # - "maximum_context_length$" # - "^context_length_exceeded" # action: "stop" # "stop" (return error, no cooling), "stop-and-cooldown" (return error and cool down), # # "continue" (try next credential, no cooling), "continue-and-cooldown" (try next credential and cool down) # base-url: "https://generativelanguage.googleapis.com" # headers: # X-Custom-Header: "custom-value" # # Values starting with "$" dynamically copy the header value from downstream client requests. # # If the client did not send the specified header, the header is omitted. # # X-Claude-Code-Session-Id: "$ABC" # copies client's "ABC" header # proxy-url: "socks5://proxy.example.com:1080" # # proxy-url: "direct" # optional: explicit direct connect for this credential # models: # - name: "gemini-2.5-flash" # upstream model name # alias: "gemini-flash" # client alias mapped to the upstream model # display-name: "Gemini Flash" # optional catalog display name # max-context-length: 1048576 # optional: override Codex client context window metadata # is-compat: false # optional: preserve thinking blocks with empty signatures for compatible upstreams # thinking: # optional: exact thinking capability for this configured model # levels: ["high", "medium", "low", "none", "auto"] # excluded-models: # - "gemini-2.5-pro" # exclude specific models from this provider (exact match) # - "gemini-2.5-*" # wildcard matching prefix (e.g. gemini-2.5-flash, gemini-2.5-pro) # - "*-preview" # wildcard matching suffix (e.g. gemini-3-pro-preview) # - "*flash*" # wildcard matching substring (e.g. gemini-2.5-flash-lite) # - api-key: "AIzaSy...02" # Native Interactions API keys # These keys are used only for direct /v1beta/interactions execution. Regular gemini-api-key entries still # send Gemini generateContent/streamGenerateContent requests when the client enters through the interactions API. # interactions-api-key: # - api-key: "AIzaSy...03" # weight: 5 # optional: weighted-round-robin share; omitted defaults to 1; maximum 1,000,000 # prefix: "native" # optional: require calls like "native/gemini-3-pro-preview" to target this credential # disable-cooling: false # optional override: true disables cooling, false enables it; omit to inherit global # request-retry: 3 # optional per-auth override; 0 disables additional rounds; omit or set < 0 to inherit global # request-scoped-errors: # optional: custom rules to classify upstream errors by status and body patterns # - status: 400 # match: # - "invalid_argument" # action: "continue" # base-url: "https://generativelanguage.googleapis.com" # headers: # X-Custom-Header: "custom-value" # # Values starting with "$" dynamically copy the header value from downstream client requests. # # If the client did not send the specified header, the header is omitted. # # X-Claude-Code-Session-Id: "$ABC" # copies client's "ABC" header # proxy-url: "socks5://proxy.example.com:1080" # # proxy-url: "direct" # optional: explicit direct connect for this credential # models: # - name: "gemini-2.5-flash" # upstream model name # alias: "native-gemini-flash" # client alias mapped to the upstream model # max-context-length: 1048576 # optional: override Codex client context window metadata # is-compat: false # optional: preserve thinking blocks with empty signatures for compatible upstreams # thinking: # optional: exact thinking capability for this configured model # levels: ["high", "medium", "low", "none", "auto"] # excluded-models: # - "gemini-2.5-pro" # Codex API keys # codex-api-key: # - api-key: "sk-atSM..." # weight: 5 # optional: weighted-round-robin share; omitted defaults to 1; maximum 1,000,000 # prefix: "test" # optional: require calls like "test/gpt-5-codex" to target this credential # disable-cooling: false # optional override: true disables cooling, false enables it; omit to inherit global # request-retry: 3 # optional per-auth override; 0 disables additional rounds; omit or set < 0 to inherit global # request-scoped-errors: # optional: custom rules to classify upstream errors by status and body patterns # - status: 400 # match: # - "context_window_exceeded" # action: "stop-and-cooldown" # base-url: "https://www.example.com" # use the custom codex API endpoint # alpha-search: false # optional: allow this key to serve /v1/alpha/search via base-url + /alpha/search