What it is#
sdkgen is the second half of the toolchain. It does not read your OpenAPI spec: apidef does that, and hands sdkgen a model of entities, operations, fields and flows. sdkgen turns that model into code.
The unit of output is a target, and 23 of them are language SDKs. Twenty-two are bundled with the generator: TypeScript, JavaScript, Go, Python, PHP, Ruby, Lua, C#, Java, Kotlin, Scala, Swift, Dart, Rust, C, C++, Zig, Perl, Clojure, Elixir, OCaml and Lean. The twenty-third, Haskell, arrives as a package, @voxgig/sdkgen-haskell, which is how further targets arrive rather than as changes to the generator.
Four further bundled targets are consumer targets: they wrap a language SDK rather than call the API themselves. go-cli and go-mcp wrap the Go SDK to produce a command-line tool and an MCP server. py-data wraps the Python SDK for analysts. seneca-provider wraps the TypeScript SDK as a Seneca plugin. This is why one spec yields a CLI and an agent-callable server without anyone writing either.
Every target is generated from the same model through the same pipeline, so behaviour does not fork by language. A retry policy means the same thing in Rust as in Ruby because both were generated from one description of it, not written twice.
The generated code is yours, and regeneration is not a bulldozer: when a generated file already exists, the new content is three-way diff-merged into it, so the generator's updates and local reality usually converge without anyone resolving anything. A project that prefers a clean slate switches to plain overwrite with one line of config, which is what both demo repositories do. Either way a bug is fixed in the model, a template or a component rather than in the output, because a resync of a vendored target reverts hand edits and the merge is a convenience rather than a guarantee. The one file the toolchain will not touch is .sdk/model/project.aon, which is created once and is yours to edit.