SDKs: generate, prove and publish them

Fern generates typed clients, and a CLI if the project has one, from the specs your contract writes. It runs in Docker. Method names, paging and streaming come from the contract.

Generate

charter sdk        # the TypeScript SDK -> sdk/out/typescript-dist (not committed)
charter sdk go     # any group of fern/generators.yml -> sdk/out/<group>
import { NotesClient } from "./sdk/out/typescript-dist/esm/index.mjs";
const client = new NotesClient({ baseUrl: "http://localhost:<the project's port>" });
for await (const n of await client.notes.list({ limit: 50 })) console.log(n.id);   // pages by itself

Prove them, in every language

charter sdk -prove generates every group of fern/generators.yml at once, each in a Docker container of its own, and proves each in its language as soon as it is generated: Go built, vetted and tested against WireMock; TypeScript typechecked; Python checked by mypy and its own tests; the Rust CLI built. Each says how long it took. The toolchains come from mise, at versions charter pins. This repo’s CI proves the conformance projects’ clients, which carry every Fern feature.

Which SDKs a project has is [sdks] in charter.toml; charter spec writes Fern’s settings, fern/generators.yml, from it and the spec, with the generators charter pins:

[sdks]
name = "Notes"
more = ["python", "cli"]
Field Gives
name The TypeScript SDK’s namespace; in lower case, the Go package and the CLI’s command
(always) The groups go, typescript (sources) and typescript-dist (compiled); the Go SDK’s module is the project’s Go module, or in TypeScript the Worker’s name, with /sdk/go
more python, and cli: a command-line client in Rust (Fern’s early access), which charter sdk -prove cli builds
audiences For each, a TypeScript SDK of only what the contract tags for it (x-fern-audiences): the group typescript-<audience>

The credentials each SDK sends are the spec’s security schemes, restated there: bearer tokens, header keys (a Cloudflare Access service token) and OAuth client credentials, any of them.

Give the Go SDK to another repo

In a Go project with go = true in charter.toml’s [sdks]:

charter sdk -publish       # generates and proves the Go SDK, and copies it into sdk/go
git add sdk/go             # commit it with its contract change; never edit it

Then another repo runs go get <your module>/sdk/go@main, or @<tag>.

Fern features

The conformance (examples/conformance-go/, and examples/conformance-ts/ from oRPC) switches each on; copy the lines from its contract and api/spec.go.

Feature In the Go contract The caller gets
OAuth client credentials A security scheme in config(); a form-encoded token operation (humaworkers.WithForm); auth-schemes in generators.yml new ConformanceClient({ oauth: { clientId, clientSecret } })
Idempotency x-fern-idempotency-headers, "x-fern-idempotent": true, a hidden header field notes.create(body, { idempotencyKey })
Multipart upload RawBody multipart.Form and the form’s schema files.uploadFile({ file, note })
Webhooks, signed doc.Webhooks; x-fern-webhook-signature; crypto/hmac in the handler WebhooksHelper.verifySignature(...)
A WebSocket both ways asyncapi.Operation on the GET, asyncapi.SendOperation on a POST to the same path A typed sendSubscribe() (TypeScript)
Audiences x-fern-audiences; a group with audiences: [public] A public SDK without internal operations
Resumable SSE A text/event-stream response; x-fern-streaming with terminator and resumable; each event’s id its place in the log, and the handler resuming from the newer of after and Last-Event-ID notes.watch({ after, seconds }), which reconnects on a drop (because it is resumable) and stops at the terminator
MCP tools serve.API serves them; mcp.NotATool(op) for what is no tool Any MCP client: the operations as tools at /api/mcp

The spec only describes: the server must enforce auth, and idempotency is the handler’s job (the conformance projects keep the first note under each key, in D1).