Code Generation
AsyncAPI, Orval, and oapi-codegen client generation workflows.
Code Generation
The platform uses code generation pipelines to keep API contracts in sync across all services.
Event types (AsyncAPI)
The AsyncAPI specification in services/wordloop-core/asyncapi.yaml is the single source of truth for all event-driven types (WebSocket events and Pub/Sub messages).
This produces:
| Target | Tool | Output |
|---|---|---|
| Go | asyncapi-codegen | services/wordloop-core/internal/provider/generated/asyncapi.gen.go |
| TypeScript | @asyncapi/cli (Modelina) | services/wordloop-app/lib/generated/asyncapi.ts |
| Python | @asyncapi/cli (Modelina) | services/wordloop-ml/src/wordloop/providers/generated/asyncapi_models.py |
Consumer scripts (App, ML) try to fetch the spec from a running Core instance at http://localhost:4002/asyncapi.yaml first, and fall back to the local monorepo path for offline generation.
:::info Core owns the spec and generates its own types locally. App and ML are consumers that pull the spec from Core — following the same pattern as OpenAPI client generation. :::
Core → ML client (oapi-codegen)
wordloop-core generates a Go HTTP client for calling wordloop-ml's API.
Under the hood:
Adding a new external API client in Core:
- Create
internal/provider/<name>/ - Add an
oapi-codegen.yamlconfig in that directory - Set
<NAME>_BASE_URLwhen running the script
ML → Core client (openapi-python-client)
wordloop-ml generates a Python client for calling wordloop-core's API.
Under the hood:
The generated client is written to src/wordloop/providers/wordloop_core/client/ and must not be edited manually.
App TypeScript client (Orval)
wordloop-app generates TypeScript types, SWR hooks, and API functions from Core's OpenAPI spec.
Under the hood:
The generated file is lib/api/generated.ts — never edit it manually. Use the wrapper hooks in hooks/use-data.ts.
Regenerate everything
This runs: events → clients → docs.