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

sizevCPURAM (billed)OpenStack flavorHetzner typeRate
small (default)22 GBb2i.2c-2gcx23€0.03 / h
medium44 GBb2i.4c-4gcx33€0.06 / h
large88 GBb2i.8c-8gcx43€0.12 / h

Rate = vCPU × €0.01/h + GB RAM × €0.005/h, stored on the environment at creation (hourlyRateMicroEur: 30 000 / 60 000 / 120 000 micro-EUR). Disk is whatever the flavor or server type ships with. GPU environments are coming soon.

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.

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.

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.

Coming soon

Prebuilds (a warm pool per project), GPU environments and choosing the region in the hub are not available yet.

On this page