Skip to content

How it's built

Most of this package is generated. The models, resources, error classes and api.md come from OpenCode's own contract; the transport, retries, streaming, pagination and server launcher are written by hand.

@opencode/protocol (npm) ──bun codegen/extract──▶ spec/contract.json ──python -m codegen──▶ src/opencode

1. Extract the contract

codegen/extract/extract.ts loads ClientApi from the published @opencode/protocol package, the same Effect HttpApi definition the official TypeScript client is built from. It exports every endpoint with its inputs, outputs and declared errors, and every schema as JSON Schema, into spec/contract.json.

Because the contract comes from the server's source of truth rather than a hand-written OpenAPI file, method names and request shapes match the TypeScript client exactly.

2. Generate Python

python -m codegen reads the contract and writes:

Output What it contains
src/opencode/types/ pydantic models for every schema, discriminated unions with Unknown... fallbacks, open enums
src/opencode/resources/ A sync and an async class per API group, with typed arguments and docstrings
src/opencode/_errors.py An exception class for every declared server error
api.md The method table

3. Hand-written runtime

Module Responsibility
_base_client.py Request building, auth, retries with backoff, timeouts
_pagination.py Cursor pages and the async paginator
_streaming.py Server-sent event decoding
_server.py OpencodeServer
_models.py, _types.py Model base class, NOT_GIVEN, open enums

Keeping it current

Generated code is committed. CI regenerates it and fails if anything changed, so the committed code always matches spec/contract.json. A nightly workflow checks for new @opencode/protocol releases and opens a pull request with the regenerated client. See Contributing for running it locally.