Generate an SDK
A practical path from authoritative API input to an Effect-native package.
Before you begin
Choose the source strategy before writing generator code. The authority and shape of the upstream input determines whether you need a spec repository at all.
Pin the authoritative input
Mirror a maintained OpenAPI document or add the official typed SDK as a submodule. Pin an exact commit.
Document semantic patches
Keep unavoidable RFC 6902 transformations small, named, and reviewable. Never silently mutate the source.
Generate operations
Emit Effect schemas, HTTP traits, categories, and yieldable operations through the shared generator.
Add provider behavior
Implement credentials, client wiring, error mapping, retry policy, and any pagination conventions in the provider repository.
Prove determinism
Regenerate and fail when committed operations or coverage.json drift. Review method totals and unsupported operations, and test generator adaptations with focused request-shape fixtures.
Publish independently
Release the provider package from its own trusted GitHub workflow.
OpenAPI generator
import { generateFromOpenAPI } from "@kevinmichaelchen/distilled/openapi/generate";
generateFromOpenAPI({
specPath: "specs/provider/specs/openapi.json",
patchDir: "patches",
outputDir: "src/operations",
});
The exact provider configuration is documented by the source type:
specPathstring
Path to the OpenAPI spec file
stringpatchDirstring
Directory containing *.patch.json files (can be same as spec dir or separate)
stringoutputDirstring
Output directory for generated files
stringimportPrefixstring
Import prefix for relative imports (e.g., ".." for operations/ -> src/)
stringclientImport?string
Client import path (e.g., "../client")
stringtraitsImport?string
Traits import path (e.g., "../traits" or "@distilled.cloud/core/traits")
stringsensitiveImport?string
Sensitive import path
stringerrorsImport?string
Errors import path (for operation-specific error imports)
stringincludeOperationErrors?boolean
Whether to include operation-specific error imports (default: true for Swagger, false for OAS 3.x)
booleanstatusToErrorClass?Record<string, string>
Status codes to error class name mapping (only used when includeOperationErrors=true)
Record<string, string>defaultErrorStatuses?Set<string>
Default error status codes to exclude from operation-specific errors
Set<string>skipDeprecated?boolean
Whether to skip deprecated operations (default: true)
booleanapiVersion?string
Default `api-version` for versioned APIs (e.g. Azure ARM). When set, the generator bakes `apiVersion` into each operation's `T.Http` trait (so the client injects `?api-version=<value>` automatically) and omits the `api-version` query parameter from the generated input schema.
stringAgent handoff
Ask a coding agent to evaluate a new provider source.
Study the Distilled source decision rule. For this API, identify the authoritative maintained source, decide whether a separate distilled-spec repository is justified, document any unavoidable patches, and propose the smallest deterministic generator path. Do not scrape prose into a pseudo-spec when an official typed source exists.
Why are generated files committed?
Because source and generator changes should produce reviewable diffs. Consumers also receive a complete source package without needing generation at install time.
Why not one monorepo?
Independent repositories keep source history, provider cadence, package ownership, and release permissions explicit.
When should I create distilled-spec-*?
When a compact, authoritative artifact benefits from immutable mirroring or extraction. Skip it when the official source repository is already the right-sized authoritative input.