Amy
SDKs

SDKs

One contract, one spec, many languages. The TypeScript SDK ships today. Python and Swift land when the first user asks. Until then, the OpenAPI spec at /openapi.json lets anyone generate a client in…

One contract, one spec, many languages. The TypeScript SDK ships today. Python and Swift land when the first user asks. Until then, the OpenAPI spec at /openapi.json lets anyone generate a client in any language in minutes.

Which SDK exists today

LanguageStatusPackageReference
TypeScriptStable@amy/sdkReference
PythonPlannedamy-sdk (PyPI)When the first Python user asks
SwiftPlannedamy-sdk (SPM)When the native iOS app starts

The CLI you run today is itself a TypeScript SDK client, every amy ... command is a thin wrapper around an SDK method. If the SDK can't do it, the CLI can't either.


Why TypeScript first

Three reasons, in order:

  1. It's the canonical client. The Worker is written in TypeScript with Hono. Hono's hc() produces a typed fetch client from the route definitions, free end-to-end types with no extra build step. Every other language SDK is downstream of this one.
  2. Mobile uses it too. The React Native app talks to Amy with the same package, no JS / TS split, no second implementation to keep in sync.
  3. It's the SDK the team uses. The CLI, the e2e tests, the internal tooling all consume @amy/sdk. If the TS SDK is broken we notice immediately; the contract for every other language is downstream.

When someone asks for a Python SDK we'll ship one. Until then we'd rather spend that build effort on the contract that drives all of them.


How SDKs are generated

The pipeline has one source of truth: the Zod schemas in packages/contracts/.

  Zod schemas              the source of truth

       ▼  @hono/zod-openapi
  /openapi.json            served live by the Worker

       ├──── hc()        → TypeScript SDK   (free with Hono, zero codegen)
       ├──── Fern        → Python SDK       (when asked)
       └──── Fern        → Swift SDK        (when the iOS app starts)

The same /openapi.json your Worker serves is what we'd feed into any code generator. We use Fern's free tier for non-TS languages because it produces idiomatic, well-typed clients without us writing a generator from scratch.

You don't have to wait for us. The spec is always live at /openapi.json on any deployed Amy Worker, point your favorite generator at it and ship.

# Generate your own client in any language Fern supports
fern generate --openapi https://amy.heyamy.xyz/openapi.json

# Or with the OpenAPI generator
openapi-generator-cli generate \
  -i https://amy.heyamy.xyz/openapi.json \
  -g <lang> -o ./my-amy-sdk

Common targets that work out of the box: Python, Go, Rust, Java, Kotlin, Swift, C#, Ruby, PHP. The spec is OpenAPI 3.1, which most modern generators handle natively.


What every SDK ships with

Whatever language we generate next, these are non-negotiable:

FeatureWhy
Fully typed methods (matching the Zod contract)The whole point of the schema-first design
Automatic retries with exponential backoff for 429 / 5xxNetwork is unreliable; clients shouldn't have to handle it
Auto-generated Idempotency-Key (UUIDv4) on writesSafe to retry without duplicating side effects
Async iterator / stream interface for SSE endpoints"Watch Amy think" UX works the same everywhere
Typed error classes with stable code fieldsif err is NotFoundError works in every language
Cursor-based pagination helpersOne for loop walks every page

See TypeScript reference for the concrete shapes; other SDKs will mirror them.


Stability

We follow semver. The TypeScript SDK is at 0.x, breaking changes can happen between minor versions during the beta. Once we hit 1.0, the rules tighten:

ChangeCounts as breaking?
Removing or renaming an endpointYes
Removing a field from a responseYes
Changing a field's type or making it nullableYes
Removing or renaming an SDK methodYes
Changing a method's positional argument orderYes
Adding a new endpointNo
Adding an optional request fieldNo
Adding a new response fieldNo
Adding a new SDK methodNo
Adding a new event type to a streamNo

Clients should always ignore unknown fields in responses and unknown event types in streams. Both are how we ship non-breaking additions.

For API versioning specifically: every endpoint lives under /v1/. When we ship /v2/, both run side by side and /v1/ stays available for at least 6 months with deprecation headers. The TypeScript SDK pins to a single API version per release; bumping your SDK is how you opt in to a new API version.


Where to next

On this page