/v1/computers lets outside developers create Allternit computers and drive them with the computer and browser toolsets. The developer guide is Hosted computers. This page covers what Allternit runs.
How a call travels
- The developer’s key hits cloud-api
POST /v1/computers/{id}/toolset(cmd/allternit-cloud-api/src/routes/platform_v1/computers.rs). - cloud-api checks the project flag, the
computersscope, the spend cap and the per-key cap. - It relays the call, signed as the computer’s owner, to the computer’s own allternit-api executor at
/api/v1/computers/this-device/toolset. That is the same relay hosted agents use. - The executor runs contract validation, the control lease, policy, approval, the audit row and then the action. cloud-api never runs an action itself.
- A 409
approval_requiredgoes back to the developer. The project owner approves it in the console, or a key does when the project’sapproval_modeisapi_key.
platform-drv:<computer id>, never a person’s account. It sleeps when idle and wakes on the next call (POST /v1/computers/{id}/start wakes it too).
Where they run (Eoj, 2026-10-08)
Developer computers run on the Mail VPS (host_mail, Incus at https://127.0.0.1:8443 from cloud-api on the same host), not on allternit-standby. Customer cloud computers stay on standby. The split is ALLTERNIT_HOSTED_DRIVER_HOSTS=host_mail: that host takes only developer computers, and developer computers go only there.
The Mail VPS also runs the prod Postgres, prod allternit-api, MinIO, the trading services and three qemu VMs, so the developer pool is hard-capped:
Headless image
Developer computers bootallternit-computer-headless (ALLTERNIT_HOSTED_DRIVER_IMAGE), not the full allternit-cloud-computer desktop. It’s built from the cloud computer image by cmd/allternit-computer-cloud/guest/build-headless-computer-image.sh: the desktop session (XFCE, LightDM, VNC, the screen mux) and the services a developer computer doesn’t use (printing, Avahi, Tailscale, the subscription gateway) are masked. The Allternit app runs as allternit-headless.service in provisioned mode on a bare Xvfb :0 (allternit-xvfb.service, 1280×800, no window manager). It still redeems the bootstrap token, holds the relay and runs allternit-api, gizzi-code, the computer-use sidecars and Chrome.
The computer toolset drives that screen through the Allternit Driver that ships in the image (phase D1b): the driver runs as allternit-driver.service on a shared session bus (allternit-session-bus.service, so the app, the AT-SPI registry and the driver see the same accessibility world on the bare Xvfb), and serves read_ui/act/run_batch/verify plus the pixel members over /run/allternit/driver.sock. allternit-api reaches it through the guest exec channel and falls back to xdotool/scrot only when the driver doesn’t answer. The browser toolset uses headless Chrome.
The Xvfb still starts at boot because the current Linux app (1.1.x) segfaults on Chromium’s headless Ozone platform when it opens its window. When the app can run without a window, drop allternit-xvfb.service from the image; allternit-api already starts the screen on demand.
Rebuild it on the Mail VPS after a new cloud computer image or allternit-api:
bash cmd/allternit-computer-cloud/guest/validate-image.sh allternit-computer-headless then proves the driver service, its hello capability report and a populated read_ui on the new image (it launches a throw-away local container; never run it against the fleet).
Host setup (Mail VPS)
cmd/allternit-cloud-api/deploy/incus/dev-pool-mailvps.sh does the one-time setup, after backing up the Incus config, iptables rules and the cloud-api .env to /root/backups/dev-pool-<time>/: the btrfs pool cow, the egress script below, the host_mail ledger row, and the cloud-api env. It restarts nothing; the next cloud-api deploy (or systemctl restart allternit-cloud-api) picks up the env.
Launch flag
Nothing works untilplatform_projects.hosted_driver_enabled is true for the project. Every route answers 404 hosted_driver_disabled until then, except GET /v1/computer_settings. Developers can’t set the flag. Turn it on by hand:
Configuration (cloud-api env)
Egress rules
Hosted-driver computers must not reach private networks: RFC1918,100.64.0.0/10 (our mesh), link-local 169.254.0.0/16 (this includes the metadata address 169.254.169.254), loopback, IPv6 ULA and link-local ranges, and the host’s own addresses.
Incus enforces this with a network ACL on a dedicated managed bridge. Run the setup once per fleet host that takes hosted-driver computers:
allternit-hosted-driver-egress (which also rejects the host’s own global IPv4 addresses), an nft table inet allternit_drv_guard that lets the bridge send the host only DHCP and DNS (so Postgres 5432, MinIO 9000/9001, allternit-api, SMTP 25, the Incus API and the qemu VNC ports are closed to these computers on every host address), the unit allternit-drv-guard.service that restores it and the Docker DOCKER-USER accepts at boot, the bridge allternit-drv0 (default 10.231.0.1/24; override with HOSTED_DRIVER_SUBNET) and the profile allternit-hosted-driver. DNS to the bridge gateway stays allowed.
If a host doesn’t have the profile, Incus refuses to create the computer, so a hosted-driver computer can’t start without the filter.
Metering
There are two meters:computer_minute (running minutes, recorded on each call, stop and delete) and computer_action (one per executed toolset call). Both count toward usage at $0 until prices are set. They’re in the Stripe dry-run plan as pending meters, and --apply doesn’t create them.