What Is the Descriptor-First Provider System in OpenClaude?
OpenClaude's descriptor-first provider system replaces hard-coded provider logic with declarative metadata objects stored in src/integrations/, enabling new AI vendors to be added without modifying routing or transport code.
The descriptor-first architecture in OpenClaude (Gitlawb/openclaude) centralizes all provider, model, gateway, and brand metadata into type-safe descriptor files. This design transforms provider management from scattered conditional logic into a data-driven pipeline where metadata—not code—determines available routes and capabilities.
How the Descriptor System Works
At its core, the system treats every integration as a descriptor object defined using helper functions in src/integrations/define.ts. These descriptors capture everything needed to route and shape requests: authentication modes, base URLs, transport protocols, and model catalogs.
The architecture operates through five coordinated layers:
| Layer | Key File | Responsibility |
|---|---|---|
| Type definitions | src/integrations/descriptors.ts |
TypeScript interfaces for all descriptor shapes |
| Registration | src/integrations/index.ts + registry.ts |
Loads generated manifest into in-memory registry |
| Route resolution | src/integrations/routeMetadata.ts |
Maps user config/env vars to concrete descriptor IDs |
| Runtime metadata | src/integrations/runtimeMetadata.ts |
Derives request-shaping flags from active descriptor |
| Compatibility bridges | compatibility.ts, providerFlag.ts |
Preserves legacy env-based API contracts |
According to the Integrations Architecture doc, "the primary source of truth now lives in these layers" and "descriptor metadata should decide which route exists and what it supports; runtime code should execute that metadata, not replace it with a parallel provider matrix."
Anatomy of a Descriptor File
Descriptors follow a consistent pattern using define* helpers. Here is a complete gateway descriptor from src/integrations/gateways/acme.ts:
import { defineGateway, defineCatalog } from '../define.js';
const catalog = defineCatalog({
source: 'static',
models: [
{
id: 'acme-fast',
apiName: 'acme/fast',
modelDescriptorId: 'acme-fast',
},
],
});
export default defineGateway({
id: 'acme',
label: 'Acme AI',
category: 'hosted',
defaultBaseUrl: 'https://api.acme.example/v1',
defaultModel: 'acme/fast',
setup: {
requiresAuth: true,
authMode: 'api-key',
credentialEnvVars: ['ACME_API_KEY'],
},
transportConfig: {
kind: 'openai-compatible',
openaiShim: {
supportsApiFormatSelection: false,
supportsAuthHeaders: true,
},
},
catalog,
});
Key fields include:
transportConfig.kind— the routing contract (e.g.,'openai-compatible')setup— authentication requirements and environment variable namescatalog— model-specific entries with their own capability flags
The Descriptor Lifecycle at Runtime
The descriptor-first system processes providers through a four-phase pipeline:
1. Generation
The bun run integrations:generate command scans all descriptor files and compiles src/integrations/generated/integrationArtifacts.generated.ts. This artifact contains the complete, type-safe manifest of all integrations.
2. Loading
src/integrations/index.ts imports the generated artifact and registers each descriptor via registry.ts, exposing typed accessors like getVendor(), getGateway(), and getModel().
3. Route Selection
routeMetadata.ts evaluates:
- Environment variables (e.g.,
OPENAI_API_KEY,ANTHROPIC_API_KEY) - Saved user profiles
- CLI flags like
--provider
The result is a concrete descriptor ID identifying the active integration.
4. Request Shaping
runtimeMetadata.ts merges the selected descriptor with the chosen model's catalog entry, producing flags consumed by the OpenAI-shim transport layer in src/services/api/openaiShim/:
supportsApiFormatSelectionsupportsAuthHeaderssupportsVision- Other capability-derived settings
Adding a New Provider: Complete Contributor Workflow
The descriptor-first system enables zero-code integration additions. To add a new vendor:
Step 1: Create a descriptor file at src/integrations/vendors/myco.ts:
import { defineVendor } from '../define.js';
export default defineVendor({
id: 'myco',
label: 'MyCo AI',
category: 'hosted',
defaultBaseUrl: 'https://api.myco.com/v1',
setup: {
requiresAuth: true,
authMode: 'api-key',
credentialEnvVars: ['MYCO_API_KEY'],
},
});
Step 2: Regenerate the integration manifest:
bun run integrations:generate
Step 3: The vendor automatically appears in CLI commands:
openclaude provider list
openclaude --provider=myco chat
No changes to routing logic, transport code, or registry files are required.
Using Descriptor Metadata in Application Code
Runtime code accesses descriptor-derived capabilities through utility functions. For model-specific feature detection:
import { getModelDescriptor } from '../../utils/model/providers';
const descriptor = getModelDescriptor('gpt-4o-mini');
if (descriptor?.capabilities?.supportsVision) {
request.images = [...attachments];
}
The capabilities object originates directly from the model's descriptor entry (e.g., src/integrations/models/gpt.ts).
For provider enumeration in CLI interfaces:
// From src/commands/provider/provider.test.tsx
import { useProviders } from '../../utils/providerFlag';
const providers = useProviders(); // Returns descriptor-generated list
Legacy Compatibility Bridges
While descriptors are the source of truth, narrow compatibility layers preserve existing workflows:
src/integrations/compatibility.ts— maps historic preset names to descriptor route IDssrc/utils/providerFlag.ts— maintains legacy--providerenv variable writessrc/utils/model/providers.ts— preservesAPIProvider/LegacyAPIProvidertypes for older callers
These bridges are intentionally minimal. New features should extend descriptors rather than compatibility code.
Key Source Files
Summary
- Descriptor-first architecture centralizes provider metadata in
src/integrations/instead of scattering logic across the codebase - Five-layer pipeline (definitions → generation → registration → routing → runtime) converts declarative descriptors into executable request configuration
- Zero-code provider addition is possible: create a descriptor file, run
bun run integrations:generate, and the integration appears automatically - Type safety is enforced through
descriptors.tsinterfaces and generated artifacts - Legacy compatibility is maintained through narrow bridge layers, with new functionality directed toward descriptors
Frequently Asked Questions
What is a descriptor in OpenClaude?
A descriptor is a declarative metadata object—created with helpers like defineVendor(), defineGateway(), or defineModel()—that fully specifies an AI provider's identity, authentication requirements, transport protocol, and available models. Descriptors live as individual files under src/integrations/ and serve as the single source of truth for provider behavior.
How do I add a new AI provider to OpenClaude?
Create a new descriptor file in the appropriate src/integrations/ subdirectory (e.g., vendors/, gateways/), define the provider using the relevant define* helper, then run bun run integrations:generate. The provider automatically becomes available in CLI commands and API routes without modifying any transport or routing code.
Where does OpenClaude store provider authentication settings?
Authentication requirements are declared in each descriptor's setup field, which specifies authMode (e.g., 'api-key'), credentialEnvVars array, and whether auth is required. Runtime code reads these values from routeMetadata.ts and runtimeMetadata.ts to configure headers and connection parameters.
Can I use descriptor metadata to check model capabilities at runtime?
Yes. Import getModelDescriptor() from src/utils/model/providers to retrieve the full descriptor for any model ID. The returned object's capabilities field contains boolean flags like supportsVision, supportsToolCalling, and supportsApiFormatSelection that originated from the model's catalog entry in its descriptor file.
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 →