oagen is a framework for building custom SDK generators from OpenAPI 3.x specifications.
Its core job is narrow:
- parse an OpenAPI spec into a typed intermediate representation (IR)
- let language emitters turn that IR into files
- regenerate the SDK when the spec changes
More advanced workflows, such as preserving the public API of an existing SDK during a migration to generation, is also supported.
oagen is a fit if you:
- need more control than off-the-shelf generators give you
- want to build or maintain a custom emitter for one or more languages
- care about generated output being idiomatic for a specific SDK style
oagen is probably not a fit if you:
- just want a turnkey SDK generator with batteries included
- do not want to maintain emitter code
- do not need a reusable IR or generation framework
oagen has a small core:
- Parser: OpenAPI 3.x ->
ApiSpecIR - Emitter runtime:
ApiSpec->GeneratedFile[] - Diffing: compare spec versions and map changes to generated output
Advanced features such as API-surface extraction, compatibility overlays, smoke verification, and live-SDK integration are available, but they are optional. You can ignore them until you need them.
Install the package:
npm install @workos/oagenInspect a spec:
oagen parse --spec openapi.ymlCreate an emitter project:
oagen init --lang ruby --project ./my-emitter
cd ./my-emitterGenerate files with your emitter:
npm run sdk:generate -- --spec ../openapi.yml --namespace MyServiceFor the shortest end-to-end setup, see Minimal Quickstart.
The default @workos/oagen entrypoint is intentionally focused on the framework core:
import {
defaultSdkBehavior,
mergeSdkBehavior,
diffSpecs,
generate,
generateFiles,
getEmitter,
parseSpec,
planOperation,
registerEmitter,
toCamelCase,
toPascalCase,
toSnakeCase,
} from "@workos/oagen";
import type {
ApiSpec,
SdkBehavior,
Emitter,
EmitterContext,
GeneratedFile,
Model,
Enum,
Service,
OperationPlan,
} from "@workos/oagen";Advanced compat and verification APIs are available through explicit subpaths:
import {
buildOverlayLookup,
patchOverlay,
registerExtractor,
} from "@workos/oagen/compat";
import { runCompatCheck, runOverlayRetryLoop } from "@workos/oagen/verify";Emitters are pure functions over the IR. They receive typed IR nodes and return GeneratedFile[].
import type { Emitter } from "@workos/oagen";
const myEmitter: Emitter = {
language: "go",
generateModels: (models, ctx) => [
/* ... */
],
generateEnums: (enums, ctx) => [
/* ... */
],
generateResources: (services, ctx) => [
/* ... */
],
generateClient: (spec, ctx) => [
/* ... */
],
generateErrors: () => [],
generateConfig: () => [],
generateTests: () => [],
fileHeader: () => "// Auto-generated by oagen. Do not edit.",
};Start with:
- Reference Emitter — a working TypeScript emitter with tests against a GitHub-flavored fixture spec
- Minimal Quickstart
- Emitter Contract
- IR Type System Reference
ApiSpec.sdk contains language-agnostic runtime policies — retry logic, error mapping, telemetry, pagination delays, User-Agent construction, and more. It is always populated (via defaultSdkBehavior() during parsing).
Emitters read policy from ctx.spec.sdk instead of hardcoding values:
function generateHttpClient(ctx: EmitterContext) {
const sdk = ctx.spec.sdk;
const retryCodes = sdk.retry.retryableStatusCodes; // [429, 500, 502, 503, 504]
const maxRetries = sdk.retry.maxRetries; // 3
const backoff = sdk.retry.backoff; // { initialDelay: 1, multiplier: 2, maxDelay: 30, jitterFactor: 0.5 }
// ...generate code using these values
}Override defaults per-SDK via oagen.config.ts:
// oagen.config.ts — Python SDK overrides
export default {
sdkBehavior: {
retry: { backoff: { initialDelay: 0.5, maxDelay: 8.0 } },
timeout: {
defaultTimeoutSeconds: 30,
timeoutEnvVar: "WORKOS_REQUEST_TIMEOUT",
},
pagination: { autoPageDelayMs: 0 },
},
};See src/ir/sdk-behavior.ts for all interfaces and default values.
resolveOperations(spec, hints?, mountRules?) derives method names and mount targets for every operation in the spec. The algorithm produces a snake_case name from the HTTP method and path, then applies optional overrides from a hint map.
Emitters consume ctx.resolvedOperations instead of computing names independently, ensuring all SDKs use the same method names (converted to each language's convention).
Configure hints and mount rules in oagen.config.ts:
export default {
operationHints: {
'GET /sso/authorize': { name: 'get_authorization_url' },
'POST /user_management/authenticate': {
split: [
{ name: 'authenticate_with_password', targetVariant: 'PasswordRequest', ... },
],
},
},
mountRules: {
Connections: 'SSO', // All Connections ops mount on SSO
DirectoryGroups: 'DirectorySync',
},
};Review resolved names with oagen resolve:
oagen resolve --spec openapi.yml --format table # Markdown review table
oagen resolve --spec openapi.yml --format json # JSON for programmatic useSee src/ir/operation-hints.ts for types and docs/architecture/ir-types.md for the full reference.
| Command | Purpose |
|---|---|
oagen parse |
Parse a spec and print IR JSON |
oagen init |
Scaffold an emitter project |
oagen generate |
Run a registered emitter |
oagen resolve |
Review resolved operation names (table or JSON) |
oagen diff |
Compare two specs and output a diff report |
oagen extract |
Advanced: extract an SDK API surface for compat use |
oagen verify |
Advanced: smoke-test output and run compat checks |
See CLI Reference.
oagen also includes tooling for a more opinionated migration workflow:
- extract the public API of an existing SDK
- generate a replacement while preserving names and exports
- verify the generated SDK against smoke tests and compatibility checks
- integrate generated files into a live SDK tree
Those workflows are documented separately because they are not required to use the core framework:
This repo ships with Claude Code plugin assets and skills for scaffold-and-verify workflows. The framework is usable without any agent tooling.
If you need them, start here:
npm install
npm run build
npm test
npm run typecheck