{"id":48835207,"url":"https://github.com/workos/oagen","last_synced_at":"2026-05-06T02:05:44.042Z","repository":{"id":346385434,"uuid":"1172975903","full_name":"workos/oagen","owner":"workos","description":"A framework for building custom SDK generators from OpenAPI","archived":false,"fork":false,"pushed_at":"2026-04-30T23:11:50.000Z","size":1644,"stargazers_count":2,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"main","last_synced_at":"2026-05-01T01:19:09.288Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/workos.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-03-04T22:13:24.000Z","updated_at":"2026-04-30T23:11:45.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/workos/oagen","commit_stats":null,"previous_names":["workos/oagen"],"tags_count":23,"template":false,"template_full_name":null,"purl":"pkg:github/workos/oagen","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/workos%2Foagen","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/workos%2Foagen/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/workos%2Foagen/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/workos%2Foagen/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/workos","download_url":"https://codeload.github.com/workos/oagen/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/workos%2Foagen/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32659106,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-05T11:29:49.557Z","status":"ssl_error","status_checked_at":"2026-05-05T11:29:48.587Z","response_time":54,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2026-04-14T23:06:22.336Z","updated_at":"2026-05-06T02:05:44.008Z","avatar_url":"https://github.com/workos.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# oagen\n\noagen is a framework for building custom SDK generators from OpenAPI 3.x specifications.\n\nIts core job is narrow:\n\n- parse an OpenAPI spec into a typed intermediate representation (IR)\n- let language emitters turn that IR into files\n- regenerate the SDK when the spec changes\n\nMore advanced workflows, such as preserving the public API of an existing SDK during a migration to generation, is also supported.\n\n## Who This Is For\n\noagen is a fit if you:\n\n- need more control than off-the-shelf generators give you\n- want to build or maintain a custom emitter for one or more languages\n- care about generated output being idiomatic for a specific SDK style\n\noagen is probably not a fit if you:\n\n- just want a turnkey SDK generator with batteries included\n- do not want to maintain emitter code\n- do not need a reusable IR or generation framework\n\n## Core Concept\n\noagen has a small core:\n\n- **Parser**: OpenAPI 3.x -\u003e `ApiSpec` IR\n- **Emitter runtime**: `ApiSpec` -\u003e `GeneratedFile[]`\n- **Diffing**: compare spec versions and map changes to generated output\n\nAdvanced 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.\n\n## Quickstart\n\nInstall the package:\n\n```bash\nnpm install @workos/oagen\n```\n\nInspect a spec:\n\n```bash\noagen parse --spec openapi.yml\n```\n\nCreate an emitter project:\n\n```bash\noagen init --lang ruby --project ./my-emitter\ncd ./my-emitter\n```\n\nGenerate files with your emitter:\n\n```bash\nnpm run sdk:generate -- --spec ../openapi.yml --namespace MyService\n```\n\nFor the shortest end-to-end setup, see [Minimal Quickstart](docs/core/quickstart.md).\n\n## The Core API\n\nThe default `@workos/oagen` entrypoint is intentionally focused on the framework core:\n\n```ts\nimport {\n  defaultSdkBehavior,\n  mergeSdkBehavior,\n  diffSpecs,\n  generate,\n  generateFiles,\n  getEmitter,\n  parseSpec,\n  planOperation,\n  registerEmitter,\n  toCamelCase,\n  toPascalCase,\n  toSnakeCase,\n} from \"@workos/oagen\";\nimport type {\n  ApiSpec,\n  SdkBehavior,\n  Emitter,\n  EmitterContext,\n  GeneratedFile,\n  Model,\n  Enum,\n  Service,\n  OperationPlan,\n} from \"@workos/oagen\";\n```\n\nAdvanced compat and verification APIs are available through explicit subpaths:\n\n```ts\nimport {\n  buildOverlayLookup,\n  patchOverlay,\n  registerExtractor,\n} from \"@workos/oagen/compat\";\nimport { runCompatCheck, runOverlayRetryLoop } from \"@workos/oagen/verify\";\n```\n\n## Building an Emitter\n\nEmitters are pure functions over the IR. They receive typed IR nodes and return `GeneratedFile[]`.\n\n```ts\nimport type { Emitter } from \"@workos/oagen\";\n\nconst myEmitter: Emitter = {\n  language: \"go\",\n  generateModels: (models, ctx) =\u003e [\n    /* ... */\n  ],\n  generateEnums: (enums, ctx) =\u003e [\n    /* ... */\n  ],\n  generateResources: (services, ctx) =\u003e [\n    /* ... */\n  ],\n  generateClient: (spec, ctx) =\u003e [\n    /* ... */\n  ],\n  generateErrors: () =\u003e [],\n  generateTests: () =\u003e [],\n  fileHeader: () =\u003e \"// Auto-generated by oagen. Do not edit.\",\n};\n```\n\nStart with:\n\n- [Reference Emitter](examples/reference-emitter/) — a working TypeScript emitter with tests against a GitHub-flavored fixture spec\n- [Minimal Quickstart](docs/core/quickstart.md)\n- [Emitter Contract](docs/architecture/emitter-contract.md)\n- [IR Type System Reference](docs/architecture/ir-types.md)\n\n## SDK Behavior\n\n`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).\n\nEmitters read policy from `ctx.spec.sdk` instead of hardcoding values:\n\n```ts\nfunction generateHttpClient(ctx: EmitterContext) {\n  const sdk = ctx.spec.sdk;\n  const retryCodes = sdk.retry.retryableStatusCodes; // [429, 500, 502, 503, 504]\n  const maxRetries = sdk.retry.maxRetries; // 3\n  const backoff = sdk.retry.backoff; // { initialDelay: 1, multiplier: 2, maxDelay: 30, jitterFactor: 0.5 }\n  // ...generate code using these values\n}\n```\n\nOverride defaults per-SDK via `oagen.config.ts`:\n\n```ts\n// oagen.config.ts — Python SDK overrides\nexport default {\n  sdkBehavior: {\n    retry: { backoff: { initialDelay: 0.5, maxDelay: 8.0 } },\n    timeout: {\n      defaultTimeoutSeconds: 30,\n      timeoutEnvVar: \"WORKOS_REQUEST_TIMEOUT\",\n    },\n    pagination: { autoPageDelayMs: 0 },\n  },\n};\n```\n\nSee [`src/ir/sdk-behavior.ts`](src/ir/sdk-behavior.ts) for all interfaces and default values.\n\n## Operation Resolution\n\n`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.\n\nEmitters consume `ctx.resolvedOperations` instead of computing names independently, ensuring all SDKs use the same method names (converted to each language's convention).\n\nConfigure hints and mount rules in `oagen.config.ts`:\n\n```ts\nexport default {\n  operationHints: {\n    'GET /sso/authorize': { name: 'get_authorization_url' },\n    'POST /user_management/authenticate': {\n      split: [\n        { name: 'authenticate_with_password', targetVariant: 'PasswordRequest', ... },\n      ],\n    },\n  },\n  mountRules: {\n    Connections: 'SSO',           // All Connections ops mount on SSO\n    DirectoryGroups: 'DirectorySync',\n  },\n  modelHints: {\n    // Pin a model's placement when \"first service to reference it wins\"\n    // would otherwise drift as the spec evolves.\n    User: 'UserManagementUsers',\n  },\n};\n```\n\nReview resolved names with `oagen resolve`:\n\n```bash\noagen resolve --spec openapi.yml --format table   # Markdown review table\noagen resolve --spec openapi.yml --format json     # JSON for programmatic use\n```\n\nSee [`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.\n\n## Commands\n\n| Command          | Purpose                                             |\n| ---------------- | --------------------------------------------------- |\n| `oagen parse`    | Parse a spec and print IR JSON                      |\n| `oagen init`     | Scaffold an emitter project                         |\n| `oagen generate` | Run a registered emitter                            |\n| `oagen resolve`  | Review resolved operation names (table or JSON)     |\n| `oagen diff`     | Compare two specs and output a diff report          |\n| `oagen extract`  | Advanced: extract an SDK API surface for compat use |\n| `oagen verify`   | Advanced: smoke-test output and run compat checks   |\n\nSee [CLI Reference](docs/cli.md).\n\n## Documentation\n\n- [Docs Overview](docs/index.md)\n- [Core Docs](docs/core/index.md)\n- [Advanced Docs](docs/advanced/index.md)\n- [Contributor Docs](docs/contributor/index.md)\n- [Public API Policy](docs/contributor/public-api.md)\n- [Versioning and Migration](docs/contributor/versioning.md)\n\n## Advanced Workflows\n\noagen also includes tooling for a more opinionated migration workflow:\n\n- extract the public API of an existing SDK\n- generate a replacement while preserving names and exports\n- verify the generated SDK against smoke tests and compatibility checks\n- integrate generated files into a live SDK tree\n\nThose workflows are documented separately because they are not required to use the core framework:\n\n- [Workflows](docs/architecture/workflows.md)\n- [Extractor Contract](docs/architecture/extractor-contract.md)\n- [CLI Reference](docs/cli.md)\n\n## AI / Plugin Tooling\n\nThis repo ships with Claude Code plugin assets and skills for scaffold-and-verify workflows. The framework is usable without any agent tooling.\n\nIf you need them, start here:\n\n- [Agent Docs](docs/agents/architecture.md)\n- [Emitter Agent Docs](docs/agents/emitters.md)\n- [Testing Agent Docs](docs/agents/testing.md)\n\n## Development\n\n```bash\nnpm install\nnpm run build\nnpm test\nnpm run typecheck\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fworkos%2Foagen","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fworkos%2Foagen","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fworkos%2Foagen/lists"}