# CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

## Project

`cloud-hypervisor-client` is an unofficial Rust crate wrapping the
[cloud-hypervisor REST API](https://github.com/cloud-hypervisor/cloud-hypervisor/blob/main/docs/api.md).
Cloud-hypervisor exposes its API over a local Unix domain socket, and this crate provides a typed async client
for it.

## Layout

There are two Cargo packages, not configured as a workspace:

- Repo root: the published library crate (`cloud-hypervisor-client`, edition 2024, MSRV 1.86.0).
- `generator/`: a separate, unpublished binary crate (edition 2024) that regenerates the library's API/model code
  from the upstream OpenAPI spec. It is not a path-dependency of the library.

Inside `src/`:

- `src/lib.rs` is **hand-written** and is the only source file in `src/` that survives regeneration. It
  re-exports `apis` and `models` and provides `socket_based_api_client(path) -> SocketBasedApiClient`, which
  wires `hyperlocal::UnixConnector` into a `DefaultApiClient` so callers can target the cloud-hypervisor VMM
  socket without assembling the `Configuration` themselves.
- `src/apis/` and `src/models/` are **auto-generated** by `generator/` from the OpenAPI spec. Do not hand-edit
  these files - they are deleted and rewritten on every regeneration. Persistent changes belong in the generator
  templates instead (see below).

## Common commands

Library (run from repo root):

- `cargo build` / `cargo build --release`
- `cargo test`
- `cargo test --test <name>` / `cargo test <substring>` for a single test or filtered subset.
- `cargo fmt` / `cargo fmt --check`
- `cargo clippy --all-targets`
- `cargo run --example get_info` (the example expects a real VMM socket at `cloud_hypervisor_vm_socket.sock`
  in CWD and will fail without one).

Code generator:

- `just gen` (from the repo root) is the canonical entry point. It runs the generator binary, which downloads
  the OpenAPI spec and the OpenAPI Generator jar (caches them under `generator/workdir/downloads/`), runs
  codegen, replaces `src/apis` and `src/models`, and runs `cargo fmt` on the library. Requires Java on `PATH`
  (or `JAVA_HOME` set); the jar is fetched from Maven Central and verified against its `.sha1`. Run `just`
  with no arguments to list recipes.
- `cargo run --manifest-path generator/Cargo.toml` works equivalently from any working directory.
  `Dirs::init` anchors `workdir` to the generator crate's `CARGO_MANIFEST_DIR`, so CWD is not significant.

Maintenance:

- `just ci` runs everything the GitHub Actions `ci.yml` workflow runs (fmt check, cargo check / test /
  build / doc on the library, plus check / clippy / test on the `generator/` crate), with
  `RUSTFLAGS=-D warnings` and `--locked` to match CI behaviour. The MSRV job is intentionally skipped;
  use `just msrv` separately when touching dependency versions.
- `just install-tools` installs `cargo-minimal-versions` and `cargo-msrv` (one-time, via stable toolchain).
- `just msrv` runs `cargo msrv find` to (re)derive the minimum supported Rust version. The result must
  match the `rust-version` field in `Cargo.toml` (currently `1.86.0`) and the MSRV badge in `README.md`.
- `just minimal-versions` runs `cargo minimal-versions check --workspace --direct` to verify that the
  declared dependency lower bounds in `Cargo.toml` actually compile. Run this after touching versions in
  `[dependencies]`.

## Code generation pipeline

The generator is `generator/src/main.rs`. The flow:

1. Downloads the upstream spec from the cloud-hypervisor `master` branch and asserts its `info.version` equals
   `cloud_hypervisor_openapi_expected_version` (currently `"0.3.0"` in code). Bumping the upstream spec means
   updating that constant in `main.rs` and verifying the generated diff is sane. Note: the upstream spec has
   been observed to remain pinned at `0.3.0` even after substantive changes (see commit b1c3cb0), so the
   version assertion alone is not sufficient to detect drift. The downloaded spec is written to
   `generator/workdir/downloads/cloud-hypervisor_<version>.yaml` and is **committed** to the repo (the
   generator overwrites it in place on every run via `truncate(true)`); an unexpected diff there after
   `just gen` is the signal that upstream has drifted and the regenerated `src/` should be reviewed against
   it. The OpenAPI Generator jars in the same directory remain gitignored (they are reproducibly fetched
   from Maven Central and SHA1-verified).
2. Runs `openapi-generator-cli` (version `7.22.0`, pinned in `main.rs`) twice:
    - `author template -g rust` into `generator/workdir/templates_original/` to capture the upstream baseline
      templates.
    - `generate` with `--template-dir generator/workdir/templates/` to produce the actual output. The local
      templates are the customized versions that ship in this repo.
3. Deletes `src/apis/` and `src/models/`, moves the generated equivalents in from `generator/workdir/output/`,
   and runs `cargo fmt` on the library.
4. Writes a `git diff -w` between `templates_original/` and `templates/` to `generator/workdir/templates.diff`,
   so reviewers can see what the local template overrides actually change vs. upstream.

`generator/workdir/openapi-generator.yaml` holds the generator config. Key choices:

- `library: hyper` (the generated client uses hyper directly, not reqwest).
- `bestFitInt: true` plus explicit `typeMappings` for `uint8/16/32/64 -> u8/16/32/64`. The `uint*` mapping
  exists because OpenAPI Generator otherwise widens unsigned integers to signed types; commit f05472c added
  this fix and is the kind of change that lives in this YAML.
- `useSingleRequestParameter: true` - operations with multiple parameters take a single struct.
- `avoidBoxedModels: true`.

## Editing rules of thumb

- Library bug fix or hand-written feature -> edit `src/lib.rs` (or non-generated test/example files).
- Output of generated code is wrong (type, naming, structure, derive, etc.) -> edit
  `generator/workdir/templates/` or `generator/workdir/openapi-generator.yaml`, then re-run the generator.
  Do not touch `templates_original/` (it is wiped on every run).
- Spec or generator version bump -> edit the constants near the top of `generator/src/main.rs`.
- After any generator change, run `just gen` and inspect the resulting diff under `src/` before committing.
  Commit the regenerated `src/` together with the template/config change in the same commit (see commit
  b1c3cb0 for the established pattern).

## Versioning and release metadata

The crate version in `Cargo.toml` carries upstream-spec provenance in its build metadata:
`<semver>+api-spec-<upstream-version>-<regenerated-at-date>` (currently
`0.5.0+api-spec-0.3.0-2026-05-11`). The same two values are mirrored as machine-readable fields under
`[package.metadata.api-spec]` (`upstream-version`, `regenerated-at`). Keep all three in sync, and update
the MSRV badge / version snippet in `README.md` plus the entry in `CHANGELOG.md` whenever the version
changes. Cargo treats the `+...` build metadata as opaque, so it does not affect semver resolution; do
not "simplify" it away.

