Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Orchestrate multi-language SDK generation from OpenAPI specifications. Configure OpenAPI Generator per language, apply custom templates and post-processing, handle edge cases and custom extensions, and validate generated code compilation.
.claude/skills/a5c-ai-openapi-codegen-orchestrator/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-01 | ✗→✓ | ▲ Improved | 204% | 0% |
| case-02 | ✗→✓ | ▲ Improved | 12% | 0% |
| case-16 | ✗→✓ | ▲ Improved | 60% | 0% |
| case-20 | ✗→✓ | ▲ Improved | 186% | 0% |
| case-10 | ✓→✗ | ▼ Worse | 128% | 0% |
You are openapi-codegen-orchestrator - a specialized skill for orchestrating multi-language SDK generation from OpenAPI specifications, enabling consistent, high-quality SDK production across diverse programming ecosystems.
This skill enables AI-powered SDK code generation including:
Configure OpenAPI Generator for multiple languages:
yaml# openapi-generator-config.yaml generatorConfigs: typescript-axios: generatorName: typescript-axios output: ./sdks/typescript additionalProperties: npmName: "@company/api-client" npmVersion: "1.0.0" supportsES6: true withInterfaces: true withSeparateModelsAndApi: true modelPropertyNaming: camelCase enumPropertyNaming: UPPERCASE templateDir: ./templates/typescript globalProperties: skipFormModel: false python: generatorName: python output: ./sdks/python additionalProperties: packageName: company_api_client packageVersion: "1.0.0" projectName: company-api-client generateSourceCodeOnly: false templateDir: ./templates/python java: generatorName: java output: ./sdks/java additionalProperties: groupId: com.company.api artifactId: api-client artifactVersion: "1.0.0" library: native useJakartaEe: true dateLibrary: java8 serializationLibrary: jackson templateDir: ./templates/java go: generatorName: go output: ./sdks/go additionalProperties: packageName: apiclient packageVersion: "1.0.0" isGoSubmodule: true generateInterfaces: true
Orchestrate SDK generation across languages:
javascript// generate-sdks.js import { execSync } from 'child_process'; import { readFileSync, writeFileSync } from 'fs'; import yaml from 'yaml'; const config = yaml.parse(readFileSync('openapi-generator-config.yaml', 'utf8')); const specPath = process.env.OPENAPI_SPEC || './openapi.yaml'; async function generateSDK(language, langConfig) { console.log(`Generating ${language} SDK...`); const args = [ 'generate', '-i', specPath, '-g', langConfig.generatorName, '-o', langConfig.output, '--skip-validate-spec' ]; // Add additional properties if (langConfig.additionalProperties) { for (const [key, value] of Object.entries(langConfig.additionalProperties)) { args.push('--additional-properties', `${key}=${value}`); } } // Add template directory if (langConfig.templateDir) { args.push('-t', langConfig.templateDir); } // Add global properties if (langConfig.globalProperties) { for (const [key, value] of Object.entries(langConfig.globalProperties)) { args.push('--global-property', `${key}=${value}`); } } try { execSync(`npx @openapitools/openapi-generator-cli ${args.join(' ')}`, { stdio: 'inherit' }); console.log(`Successfully generated ${language} SDK`); return { language, status: 'success' }; } catch (error) { console.error(`Failed to generate ${language} SDK:`, error.message); return { language, status: 'failed', error: error.message }; } } async function generateAllSDKs() { const results = []; for (const [language, langConfig] of Object.entries(config.generatorConfigs)) { const result = await generateSDK(language, langConfig); results.push(result); } console.log('\n=== Generation Summary ==='); results.forEach(r => { console.log(`${r.language}: ${r.status}`); }); return results; } generateAllSDKs();
Create and manage custom Mustache templates:
mustache{{! templates/typescript/apiInner.mustache }} {{#operations}} {{#operation}} /** * {{summary}} * {{notes}} {{#allParams}} * @param {{paramName}} {{description}} {{/allParams}} * @throws {ApiError} if the request fails */ public async {{operationId}}({{#allParams}}{{paramName}}{{^required}}?{{/required}}: {{{dataType}}}{{^-last}}, {{/-last}}{{/allParams}}): Promise<{{{returnType}}}{{^returnType}}void{{/returnType}}> { const response = await this.{{operationId}}Raw({{#allParams}}{{paramName}}{{^-last}}, {{/-last}}{{/allParams}}); {{#returnType}} return await response.value(); {{/returnType}} } {{/operation}} {{/operations}}
Apply transformations after generation:
javascript// post-process.js import { glob } from 'glob'; import { readFileSync, writeFileSync } from 'fs'; import path from 'path'; const postProcessors = { typescript: async (outputDir) => { // Add ESLint disable comments for generated code const files = await glob(`${outputDir}/**/*.ts`); for (const file of files) { let content = readFileSync(file, 'utf8'); // Add header comment if (!content.startsWith('/* eslint-disable */')) { content = `/* eslint-disable */\n/**\n * Auto-generated by OpenAPI Generator\n * Do not edit manually\n */\n\n${content}`; } // Fix common issues content = content .replace(/any\[\]/g, 'unknown[]') // Replace any[] with unknown[] .replace(/: any;/g, ': unknown;'); // Replace any with unknown writeFileSync(file, content); } // Generate barrel exports const models = await glob(`${outputDir}/models/*.ts`); const exports = models .map(f => path.basename(f, '.ts')) .filter(n => n !== 'index') .map(n => `export * from './${n}';`) .join('\n'); writeFileSync(`${outputDir}/models/index.ts`, exports + '\n'); }, python: async (outputDir) => { // Fix Python imports and type hints const files = await glob(`${outputDir}/**/*.py`); for (const file of files) { let content = readFileSync(file, 'utf8'); // Add future annotations for Python 3.8 compatibility if (!content.includes('from __future__ import annotations')) { content = `from __future__ import annotations\n\n${content}`; } writeFileSync(file, content); } }, java: async (outputDir) => { // Add Lombok annotations const files = await glob(`${outputDir}/**/model/*.java`); for (const file of files) { let content = readFileSync(file, 'utf8'); // Add Lombok imports if not present if (!content.includes('lombok')) { content = content.replace( 'package ', 'import lombok.Builder;\nimport lombok.Data;\n\npackage ' ); } writeFileSync(file, content); } } }; async function runPostProcessing(language, outputDir) { if (postProcessors[language]) { console.log(`Running post-processing for ${language}...`); await postProcessors[language](outputDir); console.log(`Post-processing complete for ${language}`); } }
Validate generated SDKs compile and pass linting:
javascript// validate-sdks.js import { execSync } from 'child_process'; const validators = { 'typescript-axios': { install: 'npm install', build: 'npm run build', lint: 'npm run lint', test: 'npm test' }, python: { install: 'pip install -e .[dev]', build: 'python -m build', lint: 'ruff check .', test: 'pytest' }, java: { install: 'mvn install -DskipTests', build: 'mvn compile', lint: 'mvn checkstyle:check', test: 'mvn test' }, go: { install: 'go mod download', build: 'go build ./...', lint: 'golangci-lint run', test: 'go test ./...' } }; async function validateSDK(language, outputDir) { const steps = validators[language]; if (!steps) { console.log(`No validator for ${language}`); return { language, status: 'skipped' }; } const results = { language, steps: {} }; for (const [step, command] of Object.entries(steps)) { try { console.log(`[${language}] Running ${step}...`); execSync(command, { cwd: outputDir, stdio: 'inherit' }); results.steps[step] = 'passed'; } catch (error) { console.error(`[${language}] ${step} failed:`, error.message); results.steps[step] = 'failed'; results.status = 'failed'; break; } } results.status = results.status || 'passed'; return results; }
Handle custom OpenAPI extensions:
javascript// extension-handler.js const extensionHandlers = { 'x-sdk-operation-group': (operation, value) => { // Group operations into namespaced clients operation.operationGroup = value; }, 'x-sdk-ignore': (operation, value) => { // Skip generation for this operation operation.vendorExtensions['x-skip-generation'] = value; }, 'x-sdk-paginated': (operation, value) => { // Generate pagination helpers operation.vendorExtensions['x-pagination'] = { enabled: true, pageParam: value.pageParam || 'page', limitParam: value.limitParam || 'limit', resultPath: value.resultPath || 'data' }; }, 'x-sdk-deprecated-date': (operation, value) => { // Add deprecation with sunset date operation.vendorExtensions['x-deprecation'] = { date: value, message: `This operation will be removed after ${value}` }; } }; function processExtensions(spec) { // Process path-level extensions for (const [path, pathItem] of Object.entries(spec.paths)) { for (const [method, operation] of Object.entries(pathItem)) { if (typeof operation !== 'object') continue; for (const [ext, value] of Object.entries(operation)) { if (ext.startsWith('x-sdk-') && extensionHandlers[ext]) { extensionHandlers[ext](operation, value); } } } } return spec; }
GitHub Actions workflow for SDK generation:
yamlname: Generate SDKs on: push: paths: - 'openapi.yaml' - 'templates/**' workflow_dispatch: inputs: languages: description: 'Languages to generate (comma-separated or "all")' default: 'all' jobs: generate: runs-on: ubuntu-latest strategy: matrix: language: [typescript, python, java, go] steps: - uses: actions/checkout@v4 - name: Setup Node.js uses: actions/setup-node@v4 with: node-version: '20' - name: Setup language toolchain uses: ./.github/actions/setup-${{ matrix.language }} - name: Install OpenAPI Generator run: npm install -g @openapitools/openapi-generator-cli - name: Generate SDK run: | openapi-generator-cli generate \ -i openapi.yaml \ -g ${{ matrix.language }} \ -o ./sdks/${{ matrix.language }} \ -c ./config/${{ matrix.language }}.yaml - name: Run post-processing run: node scripts/post-process.js ${{ matrix.language }} - name: Validate SDK run: node scripts/validate-sdk.js ${{ matrix.language }} - name: Upload SDK artifact uses: actions/upload-artifact@v4 with: name: sdk-${{ matrix.language }} path: ./sdks/${{ matrix.language }} publish: needs: generate runs-on: ubuntu-latest if: github.ref == 'refs/heads/main' steps: - name: Download all SDKs uses: actions/download-artifact@v4 - name: Publish SDKs run: | for sdk in sdk-*; do echo "Publishing $sdk..." # Language-specific publish commands done
Validate generator configuration:
json{ "$schema": "http://json-schema.org/draft-07/schema#", "type": "object", "properties": { "generatorConfigs": { "type": "object", "additionalProperties": { "type": "object", "required": ["generatorName", "output"], "properties": { "generatorName": { "type": "string", "enum": ["typescript-axios", "typescript-fetch", "python", "java", "go", "csharp", "rust"] }, "output": { "type": "string" }, "additionalProperties": { "type": "object" }, "templateDir": { "type": "string" }, "globalProperties": { "type": "object" } } } } } }
This skill can leverage the following MCP servers for enhanced capabilities:
| Server | Description | Installation | |--------|-------------|--------------| | mcp-openapi-schema | Explore OpenAPI schemas | GitHub | | openapi-mcp-server | Navigate complex OpenAPIs | GitHub | | swagger-mcp | Analyze OpenAPI specifications | GitHub |
This skill integrates with the following processes:
sdk-code-generation-pipeline.js - Main generation workflowmulti-language-sdk-strategy.js - Language-specific configurationsapi-design-specification.js - Spec preparationpackage-distribution.js - SDK publishingWhen executing operations, provide structured output:
json{ "operation": "generate", "specPath": "./openapi.yaml", "specVersion": "3.0.3", "generatedSDKs": [ { "language": "typescript", "generator": "typescript-axios", "outputPath": "./sdks/typescript", "status": "success", "validation": { "compile": "passed", "lint": "passed", "test": "passed" }, "files": 42, "models": 15, "apis": 8 } ], "duration": "45s", "warnings": ["Deprecated endpoint /v1/legacy detected"] }
| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-01 | fail→pass | 16,378 | 20,698 | +26% | 1 | 1 | 0% | 2,608 | 7,929 | +204% | 0 | 0 | — |
case-02 | fail→pass | 40,840 | 25,733 | -37% | 1 | 1 | 0% | 7,919 | 8,907 | +12% | 0 | 0 | — |
case-03 | fail→fail | 31,854 | 28,587 | -10% | 1 | 1 | 0% | 5,603 | 9,346 | +67% | 0 | 0 | — |
case-04 | fail→fail | 12,743 | 11,131 | -13% | 1 | 1 | 0% | 1,523 | 5,390 | +254% | 0 | 0 | — |
case-05 | fail→fail | 17,710 | 14,612 | -17% | 1 | 1 | 0% | 3,324 | 6,084 | +83% | 0 | 0 | — |
case-06 | fail→fail | 16,468 | 7,581 | -54% | 1 | 1 | 0% | 2,014 | 5,516 | +174% | 0 | 0 | — |
case-07 | fail→fail | 13,835 | 13,793 | -0% | 1 | 1 | 0% | 1,579 | 5,574 | +253% | 0 | 0 | — |
case-08 | fail→fail | 23,280 | 23,884 | +3% | 1 | 1 | 0% | 3,619 | 7,953 | +120% | 0 | 0 | — |
case-09 | fail→fail | 16,802 | 18,667 | +11% | 1 | 1 | 0% | 3,234 | 6,846 | +112% | 0 | 0 | — |
case-10 | pass→fail | 20,955 | 14,542 | -31% | 1 | 1 | 0% | 3,140 | 7,154 | +128% | 0 | 0 | — |
case-11 | pass→pass | 16,538 | 24,227 | +46% | 1 | 1 | 0% | 3,039 | 7,857 | +159% | 0 | 0 | — |
case-12 | fail→fail | 17,179 | 18,151 | +6% | 1 | 1 | 0% | 3,435 | 7,771 | +126% | 0 | 0 | — |
case-13 | fail→fail | 13,671 | 12,131 | -11% | 1 | 1 | 0% | 1,783 | 5,581 | +213% | 0 | 0 | — |
case-14 | fail→fail | 18,836 | 11,713 | -38% | 1 | 1 | 0% | 2,608 | 5,587 | +114% | 0 | 0 | — |
case-15 | fail→fail | 20,734 | 16,381 | -21% | 1 | 1 | 0% | 2,912 | 7,298 | +151% | 0 | 0 | — |
case-16 | fail→pass | 27,227 | 20,357 | -25% | 1 | 1 | 0% | 4,563 | 7,286 | +60% | 0 | 0 | — |
case-17 | pass→pass | 14,975 | 15,430 | +3% | 1 | 1 | 0% | 2,911 | 7,385 | +154% | 0 | 0 | — |
case-18 | pass→pass | 22,242 | 25,837 | +16% | 1 | 1 | 0% | 2,889 | 8,164 | +183% | 0 | 0 | — |
case-19 | fail→fail | 13,037 | 16,020 | +23% | 1 | 1 | 0% | 1,670 | 6,498 | +289% | 0 | 0 | — |
case-20 | fail→pass | 13,180 | 21,328 | +62% | 1 | 1 | 0% | 2,604 | 7,444 | +186% | 0 | 0 | — |
case-21 | pass→pass | 11,619 | 10,836 | -7% | 1 | 1 | 0% | 1,527 | 5,466 | +258% | 0 | 0 | — |
case-22 | pass→pass | 12,130 | 11,650 | -4% | 1 | 1 | 0% | 1,602 | 5,545 | +246% | 0 | 0 | — |
case-23 | pass→pass | 6,881 | 9,682 | +41% | 1 | 1 | 0% | 415 | 5,009 | +1107% | 0 | 0 | — |
DecimalAI ran this skill against gemini-3.6-flash twice over the same eval suite — once with the skill loaded and once without — and compared the two runs case by case. 23 cases were attempted. The headline lift of +13 percentage points is the difference between those two pass rates over the 23 comparable cases. 1 case got worse with the skill loaded, and it is included in that figure.
Without the skill loaded, the model failed this case. With it loaded, the same prompt on the same model passed. This is one improved case from the latest verified run; every case, including any that regressed, is in the table above.
Other measured skills in the registry, with their headline benchmark lift.