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 names
  • catalog — 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/:

  • supportsApiFormatSelection
  • supportsAuthHeaders
  • supportsVision
  • 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:

These bridges are intentionally minimal. New features should extend descriptors rather than compatibility code.

Key Source Files

File Purpose
[src/integrations/descriptors.ts](https://github.com/Gitlawb/openclaude/blob/main/src/integrations/descriptors.ts) Core type definitions for all descriptor variants
[src/integrations/define.ts](https://github.com/Gitlawb/openclaude/blob/main/src/integrations/define.ts) Helper functions (defineVendor, defineGateway, defineModel)
[src/integrations/index.ts](https://github.com/Gitlawb/openclaude/blob/main/src/integrations/index.ts) Loader for generated integration artifacts
[src/integrations/registry.ts](https://github.com/Gitlawb/openclaude/blob/main/src/integrations/registry.ts) In-memory registry with typed accessors
[src/integrations/routeMetadata.ts](https://github.com/Gitlawb/openclaude/blob/main/src/integrations/routeMetadata.ts) Route resolution from config and environment
[src/integrations/runtimeMetadata.ts](https://github.com/Gitlawb/openclaude/blob/main/src/integrations/runtimeMetadata.ts) Request-shaping flag derivation
[docs/architecture/integrations.md](https://github.com/Gitlawb/openclaude/blob/main/docs/architecture/integrations.md) Architectural design documentation
[docs/integrations/overview.md](https://github.com/Gitlawb/openclaude/blob/main/docs/integrations/overview.md) Contributor guide for descriptor authoring

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.ts interfaces 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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →