arvalez
Modern OpenAPI client generator with a compiler-style core, typed IR, and WASM plugins.
Current Scope
This first implementation slice focuses on the plugin architecture and the first target backends:
- shared IR types in Rust
- a plugin SDK that reads and writes IR over a serde boundary
- a WASM runtime that executes plugins as WASI programs
- a sample
moneyplugin that rewrites decimal money fields to a domain type - a first Python backend that emits Pydantic models plus sync and async
httpxclients - a first TypeScript backend that emits typed models plus a
fetch-based client - a first Go backend that emits typed models plus a
net/httpclient
The OpenAPI importer is in place, and the generator can now emit Python and TypeScript packages from openapi.json. Go is still to come.
Workspace Layout
crates/arvalez-ir: shared IR and validationcrates/arvalez-openapi: OpenAPI document loader and Core IR mappercrates/arvalez-plugin-sdk: plugin-side protocol helperscrates/arvalez-plugin-runtime: host-side WASM executioncrates/arvalez-target-python: Python SDK generatorcrates/arvalez-target-typescript: TypeScript SDK generatorcrates/arvalez-cli: local CLI for inspecting IR and running pluginsplugins/money-plugin: example WASM plugin
Build
Install the WASI target if needed:
Build the example plugin:
Run the plugin against the fixture IR:
Build Core IR from the local OpenAPI document:
Run the plugin against a real OpenAPI document:
Generate a Python SDK package:
Generate a TypeScript SDK package:
Generate a Go SDK package:
The generators also read optional settings from arvalez.toml:
[]
= "generated"
= true
= "1.0.0"
[]
= "github.com/acme/client"
= "client"
= "1.0.0"
[]
= "arvalez_client"
= "1.0.1"
= "./templates/python"
[]
= "@arvalez/client"
= "1.0.2"
= "./templates/typescript"
Override the configured output version from the CLI:
Generate all enabled backends into one output root:
Disable a backend from the CLI:
Disable a backend from config:
[]
= true
= "@arvalez/client"
The Go backend also supports bundled default Tera templates with selective overrides:
Supported override names are:
package/go.mod.terapackage/README.md.terapackage/models.go.terapackage/client.go.terapartials/model_struct.go.terapartials/service.go.terapartials/client_method.go.tera
When group_by_tag = true, tagged operations are grouped under subclients. For example, Python becomes client.ingredients.create_ingredient(...) and TypeScript becomes client.ingredients.createIngredient(...). Operations without tags stay on the root client, and multi-tag operations use the first tag.
Shared settings in [output] act as defaults, and [output.python] / [output.typescript] / [output.go] can override them per target. That includes group_by_tag, version, and similar cross-target options. CLI flags like --output-version override both.
Override only selected Python templates:
The Python backend ships with bundled default Tera templates inside the binary. Override files are optional and can be provided selectively. Supported override names are:
package/pyproject.toml.terapackage/README.md.terapackage/__init__.py.terapackage/models.py.terapackage/client.py.terapartials/model_class.py.terapartials/client_class.py.terapartials/client_method.py.tera
Override only selected TypeScript templates:
The TypeScript backend also ships with bundled default Tera templates inside the binary. Supported override names are:
package/package.json.terapackage/tsconfig.json.terapackage/README.md.terapackage/models.ts.terapackage/client.ts.terapackage/index.ts.terapartials/model_interface.ts.terapartials/client_method.ts.terapartials/tag_group.ts.tera
Inspect the raw fixture IR:
Docker
Build a container image with the precompiled CLI:
Run the bundled tool against files mounted from the current workspace:
Generate a Python SDK from inside the container:
Releases
Publishing a GitHub release triggers .github/workflows/release.yml, which:
- checks that the release tag matches the workspace version in
Cargo.toml - builds and pushes the multi-arch
arvalez/cliimage to Docker Hub - publishes the Rust crates to crates.io in dependency order
The workflow expects these GitHub repository secrets:
DOCKERHUB_USERNAMEDOCKERHUB_TOKENCARGO_REGISTRY_TOKEN
Set up pre-commit once after cloning:
The pre-commit config keeps internal workspace dependency versions aligned with the workspace version and regenerates Cargo.lock whenever Cargo manifests are part of the commit.