How to Define Custom Provider Descriptors for OpenClaude
To define a custom provider descriptor for OpenClaude, export environment variables prefixed with your provider ID: PROVIDER_BASE_URL, PROVIDER_API_KEY, plus optional PROVIDER_MODEL_MAP, PROVIDER_CONTEXT_WINDOW, and PROVIDER_MAX_OUTPUT_TOKENS.
OpenClaude discovers and interacts with AI providers through provider descriptors. A descriptor tells the CLI how to reach a provider, which environment variables supply its credentials, and how to map model identifiers to the provider's API. When you need a provider that is not shipped out-of-the-box, you create a custom provider descriptor that the runtime consumes using the same code paths as built-in providers.
Required Descriptor Fields
Every custom provider descriptor must specify three core fields. OpenClaude reads these from environment variables and merges them into the internal provider registry at startup.
| Field | Environment Variable Pattern | Purpose |
|---|---|---|
id |
N/A (you choose this) | Short unique name used with --provider <id> |
baseUrl |
{PREFIX}_BASE_URL |
Full HTTP URL of the provider's /v1 endpoint |
apiKeyEnv |
{PREFIX}_API_KEY |
Name of the variable holding the secret key |
The PREFIX is your provider ID uppercased with hyphens replaced by underscores. For a provider named my-custom-provider, the prefix becomes MY_CUSTOM_PROVIDER.
Optional Descriptor Fields
You can extend the descriptor with additional configuration for models that don't expose metadata through standard endpoints.
| Field | Environment Variable Pattern | Purpose |
|---|---|---|
modelMap |
{PREFIX}_MODEL_MAP |
JSON object mapping OpenAI-style names to provider-native identifiers |
contextWindow |
{PREFIX}_CONTEXT_WINDOW |
Maximum context size when not available in /v1/models |
maxOutputTokens |
{PREFIX}_MAX_OUTPUT_TOKENS |
Maximum tokens generated per request |
Where the Descriptor Logic Lives
The OpenClaude source code implements custom provider discovery in three key locations:
- Provider discovery —
src/utils/model/providers.tsnormalizes both built-in and custom descriptors. - Web-search custom provider —
src/tools/WebSearchTool/providers/custom.tsdemonstrates a minimal provider using only a URL template. - CLI flag handling —
src/utils/envFile.tsloads additional environment files via--provider-env-file.
These implementations are documented at docs/integrations/overview.md and docs/integrations/how-to/add-model.md.
Defining a Custom Provider: Complete Example
Step 1: Configure Environment Variables
Create a .env file or export variables directly in your shell:
export MY_CUSTOM_PROVIDER_BASE_URL="https://api.my-model.com/v1"
export MY_CUSTOM_PROVIDER_API_KEY="sk-xxxxxxxxxxxxxxxxxxxx"
export MY_CUSTOM_PROVIDER_MODEL_MAP='{"gpt-4":"my-model-v1","claude-3":"my-model-v2"}'
export MY_CUSTOM_PROVIDER_CONTEXT_WINDOW="1000000"
export MY_CUSTOM_PROVIDER_MAX_OUTPUT_TOKENS="32768"
Step 2: Understand the Runtime Discovery
The getCustomProvider function in src/utils/model/providers.ts resolves your descriptor at runtime:
// src/utils/model/providers.ts (excerpt)
export interface ProviderDescriptor {
id: string; // e.g. "my-custom-provider"
baseUrl: string; // e.g. "https://api.my-model.com/v1"
apiKeyEnv: string; // e.g. "MY_CUSTOM_API_KEY"
modelMap?: Record<string, string>;
contextWindow?: number;
maxOutputTokens?: number;
}
export function getCustomProvider(id: string): ProviderDescriptor | undefined {
const prefix = id.toUpperCase().replace(/-/g, '_');
const baseUrl = process.env[`${prefix}_BASE_URL`];
const apiKeyEnv = `${prefix}_API_KEY`;
if (!baseUrl || !process.env[apiKeyEnv]) return undefined;
const descriptor: ProviderDescriptor = {
id,
baseUrl,
apiKeyEnv,
modelMap: tryParseJson(process.env[`${prefix}_MODEL_MAP`]),
contextWindow: tryParseNumber(process.env[`${prefix}_CONTEXT_WINDOW`]),
maxOutputTokens: tryParseNumber(process.env[`${prefix}_MAX_OUTPUT_TOKENS`]),
};
return descriptor;
}
Step 3: Invoke from the CLI
Reference your custom provider using the --provider flag:
# Load additional env vars from a file (optional)
openclaude --provider-env-file .mycustom.env \
--provider my-custom-provider \
"Write a short poem about sunrise"
Alternative: URL-Template Providers for Web Search
For specialized use cases like custom web search, OpenClaude supports an even leaner pattern. The src/tools/WebSearchTool/providers/custom.ts file implements a provider that requires only a URL template:
// src/tools/WebSearchTool/providers/custom.ts (excerpt)
export const customProvider = {
id: 'custom',
isConfigured: () => Boolean(process.env.WEB_URL_TEMPLATE),
urlTemplate: process.env.WEB_URL_TEMPLATE, // e.g. "https://api.my-search.com/v2?q={query}"
// Re-uses generic WebSearchTool logic — no additional code required
};
This pattern demonstrates how OpenClaude's provider system scales from full API descriptors down to simple configuration-driven integrations.
Global Overrides for Model Metadata
When your custom provider does not publish model metadata through a /v1/models endpoint, you can supply context window and token limits through global environment variables:
export CLAUDE_CODE_OPENAI_CONTEXT_WINDOWS='{"my-model":"1000000"}'
export CLAUDE_CODE_OPENAI_MAX_OUTPUT_TOKENS='{"my-model":"32768"}'
These overrides are documented in docs/advanced-setup.md under the sections for CLADE_CODE_OPENAI_CONTEXT_WINDOWS and CLAUDE_CODE_OPENAI_MAX_OUTPUT_TOKENS. They apply to all providers when per-provider configuration is unavailable.
Key Files Reference
| File | Role |
|---|---|
src/utils/model/providers.ts |
Core aggregation logic for built-in and custom provider descriptors |
src/tools/WebSearchTool/providers/custom.ts |
Minimal provider example using URL templates |
src/utils/envFile.ts |
Extra .env file loading via --provider-env-file |
docs/integrations/overview.md |
High-level provider system documentation |
docs/integrations/how-to/add-model.md |
Step-by-step model addition guide |
docs/advanced-setup.md |
Context-window and max-output-token override details |
Summary
- Custom provider descriptors enable OpenClaude integration with any OpenAI-compatible API endpoint without code changes.
- Required fields:
baseUrlandapiKeyEnv(derived from{PREFIX}_BASE_URLand{PREFIX}_API_KEYenvironment variables). - Optional fields:
modelMap,contextWindow, andmaxOutputTokensfor providers lacking standard metadata endpoints. - Source implementation:
src/utils/model/providers.tshandles runtime discovery and normalization. - CLI usage: Pass
--provider <id>and optionally--provider-env-file <path>to load configuration.
Frequently Asked Questions
How do I name my custom provider ID?
Choose a lowercase string with hyphens separating words, such as my-org-llm. OpenClaude converts this to MY_ORG_LLM when constructing environment variable names. Avoid spaces, special characters, or uppercase letters in the ID itself.
Can I use multiple custom providers simultaneously?
OpenClaude supports one active provider per invocation via --provider. Define multiple providers in your environment by using distinct IDs with unique prefixes, then switch between them by changing the CLI flag value.
What happens if my provider doesn't have an API key?
The getCustomProvider function in src/utils/model/providers.ts returns undefined when {PREFIX}_API_KEY is unset, and OpenClaude falls back to built-in providers or exits with a configuration error. Self-hosted endpoints without authentication still require the variable to exist, potentially with an empty or dummy value.
Where should I store sensitive provider credentials?
Use a dedicated .env file loaded via --provider-env-file rather than exporting variables in your shell history. The src/utils/envFile.ts module parses these files and injects values into process.env before provider discovery runs, keeping secrets out of command history and process listings.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →