cloud: cmux-cloud-client, NEXT Cloud's one Rust client generated from cmux-platform's openapi.json; acpmux join moves onto it
Merged
TE
2d ago+12565+12565+01234567890123456789012345678901234567890123456789-112-112-012345678901234567890123456789
Leo, 2026-11-04: "and moving off swift into rust for next's cloud" / "you guys should be willing to remove code rewrite do large scale refactors".
Step M11 of cmuxterm-hq plans/cloud/ARCHITECTURE-2026-11.md (T2, one Rust client): NEXT Cloud gets one Rust client, generated from cmux-platform's openapi.json, and acpmux's join is its first caller.
What changes
- New crate
cmux-tui/crates/cmux-cloud-client.src/generated.rsis progenitor output from a vendored selection of cmux-platform's spec (openapi.json, pinned inPLATFORM_REF).tags.txtlists the groups it keeps: machines, placement, reservations, join credentials and redemption, workspace machines, environments, auth, client config and machine vault. That comes to 56 routes and 81 schemas, out of 154 routes in the full spec. The crate also has:client/anonymous_client/client_for: bearer marked sensitive,x-cmux-team, no redirects.ApiError: one reading of the{_tag, code, message}refusal, the wire{error:{code}}shape and proxy HTML, with aretryableflag.ops::call::<O>: thecmux.wire/1ops (/v1/ops,/v1/read), typed bycmux-cloud-wire. It checks the idempotency rule before sending.backend::Backend: the platform origin and owner API for each environment, fromcmux-cloud-environment's deployment rows.cmux-cloud-config'sPRODUCTION_PLATFORM(cmux-platform.debussy.workers.dev) 404s even on/v1/health, so it isn't used; the live Worker iscmux-platform-production.client_key(): the idempotency key.
- The generator is shared, not forked.
cmux-vm-codegengets--tags,--selected-outand--script, and--raw-outbecomes optional. It now reads a property whose only type isnullas an any-value schema; before, progenitor panicked on those (invalid type: null; platform's placement accounting fields). The cmux-vm client comes out byte for byte the same. - CI.
cmux-vm-clients.ymlalso runscmux-tui/crates/cmux-cloud-client/scripts/regenerate.shand fails when the result is stale.scripts/update-spec.sh [REF]pulls a newer platform spec. - acpmux join (C12) moves onto the client.
credentials/self(probe, replacement proof, status) andjoin-tokens/redeemnow use the generated methods and types. Before, they used hand-built reqwest calls that read the answer field by field. The redeem body is checked against the spec's limits before it is sent. Exit codes, messages and the 10 s deadline are unchanged.DEFAULT_HUBnow reads its origin fromBackend. It stays on development for now: production serves no join yet (/v1/machines/join.shand/credentials/selfanswer 404 oncmux-platform-production, andMACHINES_ENABLEDis on only in development). The production flip goes in its own PR once the backend helper turns join on there (manaflow-ai/cmux-platform#830 thread).
What it does not do
- Routes cmux-platform serves by hand and does not describe are not in the spec:
/v1/opsand/v1/read,/v1/cloud/machines/{id}/exec|fs/*|client-session|acpmux*, bind and keyset, and the agent-key mint. They are listed in manaflow-ai/cmux-platform#825; no type for them is written here. The vault pull keeps its own raw read, because it zeroizes the secret body, which typed decoding would not do. - The CLI's
cmux machineverbs, the Cloud app server and Swift move in later PRs (M11 continued, then M12).
Checks (fleet, cmux-ci test)
cargo test -p cmux-cloud-client: 10 passed.cargo test -p acpmux --test machine_join: 3 passed, 10 ignored, the same as base.cargo test -p acpmux --lib cloud_join: 6 passed.cargo test -p cmux-vm-codegen: passed.cargo clippy -p cmux-cloud-client -p acpmux --all-targets -- -D warnings: clean.cargo fmt --check: clean.- Regenerating gives the same output twice; the cmux-vm client is unchanged.
Agent session: agent session
🤖 Generated with Claude Code
![Autofix with [code]smith](https://pr-comments-assets.blacksmith.sh/codesmith/autofix-with-codesmith-dark-3x.png)
Open in [code]smith · Need help on this PR? Tag @codesmith-bot with what you need.
Summary by cubic
Introduces cmux-cloud-client, NEXT Cloud's single Rust client generated from cmux-platform's OpenAPI spec, and moves acpmux's join flow onto it in place of hand-built reqwest calls.
Changes
- The crate generates 56 of 154 spec routes across 13 tags and adds
cmux.wire/1ops, unified error decoding, per-environment backends, and idempotency keys. The client is generated at build time viabuild.rs(which includescmux-vm-codegen'snormalize.rsby path), so no generated file is committed. cmux-vm-codegenis shared rather than forked: new--tags,--selected-out, and--scriptflags, optional--raw-out, and null-only schemas become any-value instead of panicking.scripts/update-spec.shpulls newer platform specs and validates that a new selection still generates;ops::callrefuses an idempotency key for a mutation whose catalog row refuses keys.- acpmux join now calls the generated
credentials/selfandjoin-tokens/redeem; exit codes, messages, and the 10 s deadline are unchanged, andDEFAULT_HUBcomes fromBackend(development, since production serves no join yet).
Not in this PR
- No types for hand-served routes the spec omits (
/v1/ops, read, exec, bind, keyset, agent-key mint); the vault pull keeps its raw read to zeroize secrets. - The CLI's
cmux machineverbs, the Cloud app server, and the Swift migration land later.