HOLD: paid Cloud plan entitlements on in production (CLOUD_PLAN_ENTITLEMENTS=on)
HOLD: outward step, flips paid Cloud entitlements in production; p0-machines' coordinator decides when
What
This PR turns paid NEXT Cloud entitlements on in production (cmux-api):
backend/apps/api/wrangler.jsoncenv.production vars:"CLOUD_PLAN_ENTITLEMENTS": "on".scripts/cmux-next/release/production-approvals.jsonguarded_vars:"CLOUD_PLAN_ENTITLEMENTS=on". The production promote's G7 needs this entry (#26727, merged).
Once this lands and the promote runs, a team with a paid cmuxPlan gets Cloud machines at its PAID_PLAN_LIMITS:
- Pro, Founders and Team: 5 active, 20 saved, up to 8 vCPU / 16 GB / 128 GB;
- Max: 20 active, 50 saved, up to 32 vCPU / 64 GB / 512 GB;
- Go: 1 active, 2 vCPU / 4 GB.
Every other team keeps getting cloud.plan.required, which the Mac app answers with the cmux Pro offer (Upgrade opens cmux.com/pricing). The plan comes from web billing's Stripe-written cmuxPlan, read through TeamDO.inferencePlan, the same read the model router already uses in production.
Not ready yet: what must land before this one can
- A production Cloud image and provider. Production has no
CLOUD_FREESTYLE_SNAPSHOT(nocmuxnp-prod-vmimg-image; the image promote workflow only has a dev channel) and no vm-api transport. Until it has one, every paid create would answercloud.no_snapshot_configured.test/cloud-plan-production.test.ts(#26727) fails on this PR for that reason, by design. The snapshot var (or the vm-api vars) goes into this PR, or lands before it. - The provider key secret on
cmux-api:CLOUD_FREESTYLE_API_KEYfor the direct transport, orCLOUD_VM_API_SERVICE_KEYfor vm-api. Without it the promote holds at G5 (#26727). - Whoever removes the HOLD line also owns the guarded_vars entry text above. G7 lets the production promote carry this value only while the entry exists.
Known gaps that ship with this flip (none of them blocks entitlements; each is a money or product call)
- No VM-hours meter. NEXT limits machine shape and count, not hours.
vm_hours_usedis always 0, and Go'svm_hours_included: 40is shown but not enforced. The only time bound is the idle pause (30 min default, plus the 24 h no-report backstop). - Team is 5 machines flat. Classic web gives 5 per paid seat (
cmuxSeats); NEXT does not read seats. - A lapsed plan does not pause running machines. Create, start, resize and snapshot are refused at the next request. A busy machine keeps running until it goes idle.
- The CLI and Chief cannot open live checkouts.
cmux billing checkoutrefuses a live Stripe session whileBillingLivePolicy.shipped.liveCheckoutis false (a separate app-side flip). The GUI offer is not affected.
Why
Leo, 2026-10-28: "whatever's convenient for cloud, like that can be productionized, operationalized, we ought to just put out there"
Leo, 2026-10-28: "'pay money to us'"
Risk
Outward and money-moving. This flip starts Freestyle spend for paying teams in production, and it makes NEXT Cloud part of what Pro, Max, Team, Founders and Go sell. Rollback: unset the var (G7 needs CLOUD_PLAN_ENTITLEMENTS=<unset> approved), or run the one-command production rollback. Machines that already exist keep running until they pause or are deleted. Deletes always run.
Tested
The production behaviour with the flag on is covered by cloud-plan-production.test.ts, the Durable Object cases by cloud-plan-entitlements.test.ts, and the promote gates by prod-promote.test.ts (#26727). The production-provider invariant in that test is red on this PR until item 1 above lands.
Agent session: agent session
🤖 Generated with Claude Code
![View with [code]smith](https://pr-comments-assets.blacksmith.sh/codesmith/view-with-codesmith-dark-v3-3x.png)
![Autofix with [code]smith](https://pr-comments-assets.blacksmith.sh/codesmith/autofix-with-codesmith-dark-3x.png)
Need help on this PR? Tag @codesmith-bot with what you need.
Summary by cubic
HOLD: turns paid Cloud plan entitlements on in production (CLOUD_PLAN_ENTITLEMENTS=on). Teams with a paid cmuxPlan now get Cloud machines at their PAID_PLAN_LIMITS; all other teams keep getting cloud.plan.required. This PR is held until the coordinator decides when it lands.
Rollout
- Sets the var in the production worker config and approves it in the production promote gates.
- Until a production Cloud image and provider key secret exist, every paid create fails with
cloud.no_snapshot_configured.
Known gaps
- Limits apply to machine shape and count, not hours; Go's 40 included hours are shown but not enforced.
- A lapsed plan doesn't pause running machines; only the next create, start, resize, or snapshot is refused.
- The CLI and Chief can't open live checkouts while
BillingLivePolicy.shipped.liveCheckoutis off.