codai docs
Projects & Environments

Managed environments

VMs that codai provisions for you on OpenStack or Hetzner — sizes, regions, start and stop, idle auto-stop and snapshots.

A managed environment is a VM that codai creates, enrols and looks after. You pick a provider and a size; a worker that runs every minute provisions the machine, installs codaid through cloud-init, stops it when idle and bills it per second of runtime.

Managed providers are rolling out and enabled per account. Until yours is enabled, POST /v1/environments with a managed provider answers 403 — Provider 'hetzner' is not available yet; use 'byo' (bring your own machine) — and the hub shows the managed options as coming soon. Bring your own server works for everyone.

Providers and regions

providerWhereDefault region
openstackcodai cloud on Cloudify (EU, Romania), Ubuntu 24.04eu-east-1
hetznerHetzner Cloudnbg1 (the machine types below exist in fsn1, hel1 and nbg1)

The local provider value exists in the schema but is reserved; it is not provisioned.

Sizes

Each provider bills the RAM it actually gives you.

sizevCPUOpenStack (Cloudify)RateHetznerRate
small (default)2b2i.2c-2g, 2 GB€0.03 / hcx23, 4 GB€0.04 / h
medium4b2i.4c-4g, 4 GB€0.06 / hcx33, 8 GB€0.08 / h
large8b2i.8c-8g, 8 GB€0.12 / hcx43, 16 GB€0.16 / h

Rate = vCPU × €0.01/h + GB RAM × €0.005/h, stored on the environment at creation (hourlyRateMicroEur). The server type is a preference: if a provider retires it, codai picks the cheapest live type with at least the same vCPU and RAM and still bills the size's rate. Disk is whatever the flavor or server type ships with (OpenStack 20 / 40 / 80 GB, Hetzner 40 / 80 / 160 GB); while the machine is stopped or archived, the kept disk costs €0.05 per GB-month — see storage. GPU environments are coming soon.

Creating or starting a managed environment needs a wallet balance of at least one hour at its rate, otherwise 402 insufficient_balance (details).

Compute reserve and grace

Set a compute reserve in Hub → Billing: LLM usage never spends the wallet below it, so a busy chat session cannot starve your VM. If a 10-minute bucket still cannot be paid, the environment enters a 30-minute grace period (shown in Hub and the desktop app with the stop time); a top-up during grace pays the missed bucket and clears it. After 30 minutes the environment is snapshot-stopped — nothing is lost.

Create one

In hub.codai.ro/projects, open a project → New environment, choose codai cloud (OpenStack) or Hetzner, a size, the idle timeout (5–1440 minutes) and an optional monthly budget cap in euro.

The environment starts in creating. The worker creates the server (creating → enrolling once it has a public IP), cloud-init installs codaid as a system service and enrols it with a token the worker mints, and the environment becomes running. On both providers this took about two to three minutes in production. At enrolment the daemon of a managed machine receives its own API key under the environment owner; destroying the environment revokes it.

That daemon key is scoped to its own environment: it may call inference, drive the shared session of a task it runs, read its own environment (and its project), and list its own environment's secret names — nothing else. Any other route answers 403 key_scope_forbidden, so a compromised machine cannot reach your other environments, keys or wallet.

StepTime limitOn timeout
Create the server10 minretried; after 3 consecutive provider failures the environment is parked in error
Daemon enrols15 minerror, reason enroll_timeout — a late enrolment still recovers it to running
Start from stopped10 minerror

The worker never destroys a machine on an error path; you decide.

An environment in error whose server still exists is billed like a running one; after 30 minutes in error the worker snapshot-stops it, so a broken machine does not keep charging.

Lifecycle

ActionAllowed fromGoes toRole
stoprunningstopping → stoppedmaintainer
startstoppedstarting → runningmaintainer
archivestoppedarchiving → archivedmaintainer
destroyany state except destroying/destroyeddestroying → destroyedowner

Anything else answers 409 invalid_transition. Hub buttons, codaid env start|stop|destroy and POST /v1/environments/{id}/{action} all go through the same transition table.

What stop and start do on each provider:

StopStart
OpenStackShelve, then shelve-offload: the server id and public IP are kept, compute is released.Unshelve the same server.
HetznerTake a snapshot, then delete the server.Create a new server from the snapshot. The previous snapshot is deleted after the next stop.

archive runs the same stop path and parks the machine in archived; the only way out of archived is destroy. destroy deletes the server (and on Hetzner its snapshot) and revokes the daemon key.

Idle auto-stop

Every environment has idle_timeout_minutes (default 30, 5–1440; change it with PATCH /v1/environments/{id} or in the hub). The worker stops a running managed environment when

now − max(last_activity_at, started_at) > idle_timeout_minutes

with reason idle. Activity is:

  • any exec, terminal or port-stream byte from an attached client, through the relay;
  • daemon heartbeats reporting human or agent activity — an idle heartbeat never counts;
  • requests the daemon itself makes to the gateway with its key (for example an agent loop running inside the machine);
  • your own start/stop/archive/destroy requests.

Open preview traffic from third parties counts only as port-stream bytes, so a public preview with visitors keeps the machine awake. Activity is recorded at most once a minute.

The machine can also be stopped for billing reasons — insufficient_funds, billing_error or budget_exceeded; see billing. The reason is shown on the environment page and returned as stateReason.

Prebuilds

A project can keep a pool of up to 5 ready machines so a new environment starts from a warmed snapshot instead of a fresh install:

curl -X PATCH https://ai.codai.ro/v1/projects/$PROJECT_ID \
  -H "Authorization: Bearer $CODAI_API_KEY" -H 'content-type: application/json' \
  -d '{"prebuild_pool_size": 2, "prebuild_provider": "openstack", "prebuild_size": "small"}'
  • Only the project owner or an org owner/admin can set it. The worker tops the pool up every minute, runs only the devcontainer's onCreateCommand and updateContentCommand, then stops each machine.
  • The project owner pays the warm-up compute and the storage of the stopped pool machines (the normal storage rate). The pool is not topped up while the owner's wallet holds less than one hour of a pool machine.
  • POST /v1/environments with the same provider and size (and no slug) claims a ready machine: ownership moves to you, it starts right away and the response carries prebuild_claimed: true. From then on you pay for it. The one-hour balance check still applies.
  • Unclaimed pool machines are visible only to the project owner. Lowering prebuild_pool_size, or changing the provider/size, destroys the extra unclaimed machines.

Coming soon

GPU environments and choosing the region in the hub are not available yet.

Last updated:

On this page