https://github.com/workos/oagen
A framework for building custom SDK generators from OpenAPI
https://github.com/workos/oagen
Last synced: about 2 months ago
JSON representation
A framework for building custom SDK generators from OpenAPI
- Host: GitHub
- URL: https://github.com/workos/oagen
- Owner: workos
- License: mit
- Created: 2026-03-04T22:13:24.000Z (4 months ago)
- Default Branch: main
- Last Pushed: 2026-04-30T23:11:50.000Z (about 2 months ago)
- Last Synced: 2026-05-01T01:19:09.288Z (about 2 months ago)
- Language: TypeScript
- Homepage:
- Size: 1.57 MB
- Stars: 2
- Watchers: 2
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- License: LICENSE.txt
Awesome Lists containing this project
README
# oagen
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.
## Who This Is For
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
## Core Concept
oagen has a small core:
- **Parser**: OpenAPI 3.x -> `ApiSpec` IR
- **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.
## Quickstart
Install the package:
```bash
npm install @workos/oagen
```
Inspect a spec:
```bash
oagen parse --spec openapi.yml
```
Create an emitter project:
```bash
oagen init --lang ruby --project ./my-emitter
cd ./my-emitter
```
Generate files with your emitter:
```bash
npm run sdk:generate -- --spec ../openapi.yml --namespace MyService
```
For the shortest end-to-end setup, see [Minimal Quickstart](docs/core/quickstart.md).
## The Core API
The default `@workos/oagen` entrypoint is intentionally focused on the framework core:
```ts
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:
```ts
import {
buildOverlayLookup,
patchOverlay,
registerExtractor,
} from "@workos/oagen/compat";
import { runCompatCheck, runOverlayRetryLoop } from "@workos/oagen/verify";
```
## Building an Emitter
Emitters are pure functions over the IR. They receive typed IR nodes and return `GeneratedFile[]`.
```ts
import type { Emitter } from "@workos/oagen";
const myEmitter: Emitter = {
language: "go",
generateModels: (models, ctx) => [
/* ... */
],
generateEnums: (enums, ctx) => [
/* ... */
],
generateResources: (services, ctx) => [
/* ... */
],
generateClient: (spec, ctx) => [
/* ... */
],
generateErrors: () => [],
generateTests: () => [],
fileHeader: () => "// Auto-generated by oagen. Do not edit.",
};
```
Start with:
- [Reference Emitter](examples/reference-emitter/) — a working TypeScript emitter with tests against a GitHub-flavored fixture spec
- [Minimal Quickstart](docs/core/quickstart.md)
- [Emitter Contract](docs/architecture/emitter-contract.md)
- [IR Type System Reference](docs/architecture/ir-types.md)
## SDK Behavior
`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:
```ts
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`:
```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`](src/ir/sdk-behavior.ts) for all interfaces and default values.
## Operation Resolution
`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`:
```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',
},
modelHints: {
// Pin a model's placement when "first service to reference it wins"
// would otherwise drift as the spec evolves.
User: 'UserManagementUsers',
},
};
```
Review resolved names with `oagen resolve`:
```bash
oagen resolve --spec openapi.yml --format table # Markdown review table
oagen resolve --spec openapi.yml --format json # JSON for programmatic use
```
See [`src/ir/operation-hints.ts`](src/ir/operation-hints.ts) for types and [`docs/architecture/ir-types.md`](docs/architecture/ir-types.md) for the full reference.
## Commands
| 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](docs/cli.md).
## Documentation
- [Docs Overview](docs/index.md)
- [Core Docs](docs/core/index.md)
- [Advanced Docs](docs/advanced/index.md)
- [Contributor Docs](docs/contributor/index.md)
- [Public API Policy](docs/contributor/public-api.md)
- [Versioning and Migration](docs/contributor/versioning.md)
## Advanced Workflows
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:
- [Workflows](docs/architecture/workflows.md)
- [Extractor Contract](docs/architecture/extractor-contract.md)
- [CLI Reference](docs/cli.md)
## AI / Plugin Tooling
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:
- [Agent Docs](docs/agents/architecture.md)
- [Emitter Agent Docs](docs/agents/emitters.md)
- [Testing Agent Docs](docs/agents/testing.md)
## Development
```bash
npm install
npm run build
npm test
npm run typecheck
```