A Worker declares which environment classes it needs. Before anything starts, control resolves whether this deployment and this workspace can supply them, and refuses with a typed reason if not.

The classes

Desktop, Android and iOS have no backend in this build. They are surfaced with their status, their allocation fails closed with a reason, and nothing about them is presented as working. The fleet did not change that: it stands behind code and browser and may not be named for the other three.
This page describes how an environment is resolved and what it enforces. It is not a statement that a run completes: as of 2026-09-10 one does not, for the reasons in Overview.

Read runnable, not the label

Each class carries six facts that together answer one question:
string
required
available, beta, waitlist or unavailable. What Obol offers as a product.
string
required
configured or not_configured. Whether this deployment has a backend for it.
boolean
required
Whether the workspace’s plan includes the class.
boolean
required
The conjunction of the three above. This is the answer. A class can be available and not runnable because no backend is configured, and a surface that reads availability alone will offer a start button that fails.
string
required
e2b, docker_dev, demo or none. none is the absence of an implementation, and it can never report itself ready.
string
required
none, development_only or vendor_attested_microvm, ordered weakest first. The order is part of the contract, so two claims can be compared. There is deliberately no production member: no value here names an isolation boundary Obol has verified.
string
required
allocates or fails_closed.
reason, backend_readiness_reason and entitlement_reason carry the sentence to show a person.

What the backends are

Code and browser can be stood behind one of four backends. Which one you get is a fact about your deployment, not about your plan, and control asserts none of them by default: a deployment that has configured nothing reports backend: "none", backend_readiness: "not_configured" and runnable: false for every class.

The Obol-operated E2B fleet — e2b

Linux microVMs for code, and browser through Playwright baked into a reviewed template. Obol operates the fleet on its own infrastructure account, and that account’s credential buys compute and nothing else: it is never placed inside an environment, it never carries e2b.* connector traffic, and it appears in no receipt, snapshot or log. It is not a pooled vendor account, and it is a different object from the customer-facing e2b connector pack, which uses your own key. Two operating rules are worth knowing because they are visible in behaviour. A guest is never publicly addressable — the vendor’s default is the opposite, and for a class that can hold a login that default would put a logged-in browser on the open internet. And a sandbox is killed rather than paused, so checkpoint is unsupported on this backend: a paused guest at this vendor has no time to live and is never reaped, and a snapshot would leave run state there after the run that produced it ended, under no retention promise.
This backend’s isolation_claim is vendor_attested_microvm: more than a development backend, and not production isolation, which nothing on this page claims. Your work — files, page contents and screenshots — sits inside a third party’s infrastructure under Obol’s account, and four things stay open about that:
  • The microVM boundary and the compliance posture are the vendor’s assertions. Obol has not verified either one.
  • Domain-level egress is a routing control at that vendor, not a security boundary. Obol restricts outbound traffic with address rules and its own proxy instead, and never relies on domain matching.
  • Separation between tenants sharing one fleet account is undocumented by the vendor.
  • Some sandbox state can outlive the run that produced it, and no vendor retention promise currently covers it.
The fleet is decided in ADR-0104 (Accepted). Two contract details follow from what the vendor can express: region reports the deployment’s configured region or null and never asserts a placement Obol did not choose, and image_digest carries an immutable build pin (e2b:build:<uuid>) rather than a content digest. A mutable tag stays unrepresentable, which was the point of the original rule.

The Obol-operated Browserbase browser fleet — browserbase

browser only, and it is the backend a deployment with both fleets runs browser work on: a vendor-built Chromium with a real input transport, driven over CDP from Obol’s own process, where every classification, destination check and mask happens before any byte reaches the vendor. Obol operates it on its own infrastructure account under the same rules as the E2B fleet — the credential buys browser compute and nothing else, never carries browserbase.* connector traffic, and appears in no receipt or log. It is not a pooled vendor account, and it is a different object from the customer-facing browserbase connector pack, which uses your own key.Two operating rules are worth knowing because they are visible in behaviour. Nothing persists at the vendor. This backend never mounts the vendor’s persistent browser profiles (Contexts), so no login state outlives a session and a session profile cannot be attached to a browser step here — a step that needs a retained login runs on the E2B fleet instead. And browser egress is vendor-side: pages reach the web on the vendor’s network, which Obol cannot restrict beyond main-frame navigations, so a deny_all browser step is refused rather than accepted under a policy nothing enforces.
This backend’s isolation_claim is also vendor_attested_microvm: more than a development backend, and not production isolation. A dedicated VM per session is the vendor’s assertion, browser traffic egresses on the vendor’s network, and separation between tenants sharing one fleet account is undocumented by the vendor and enforced by Obol. The decision, and the refusal to mount Contexts that makes it defensible, is ADR-0106.

The local Docker development backend — docker_dev

A development backend on a trusted host: shared kernel, no hypervisor boundary, no hardened host baseline, no attested image supply chain, no proven tenant reset. It is fit for development and demonstration. It is not production isolation, and its isolation_claim reads development_only rather than naming a stronger boundary.

The demo backend — demo

Deterministic and Obol-owned. A demo run touches no customer credential and no real vendor, its estimate is a known zero rather than an unavailable one, and it never bills. Its claim is development_only too.

When a class cannot run

Allocation is checked before anything chargeable starts, and the refusal is typed:
409
set_by: "control" is on every one of these. A failure reason is control’s fact, never model prose.
The same environment_class_unavailable reason is currently returned when an unsupported capability is the real problem, because the closed failure taxonomy has no capability_unsupported variant yet. The what and why still describe what happened; the machine-readable reason is broader than the cause. This is recorded in docs/workers/2026-09-09-self-serve-follow-ups.md.

Sandboxed commands on code

A code Worker can run commands in its isolated sandbox: env_code_exec, env_code_file_read, env_code_file_write. No credential is placed in the guest. Each command is a fresh bash -c, at most 240 seconds, with no background processes. Network scope for those commands is derived from the lease (deny_all → none; dependency provisioning or an allowlist → declared; anything else fails closed as undeclared). Control re-derives the same value and evaluates the stricter of the claimed and derived scope. In safe mode, and in test mode, a sandboxed command whose network is none or declared is admitted without an approval hold. Other non-read environment commands still wait or are refused. The Read only preset permits no sandbox commands. GitHub’s API is not reachable from the sandbox. Clone public repositories over https://github.com/… and publish through gateway Git Data tools (github.get_ref, github.create_tree, github.create_commit, github.create_ref, then github.create_pull). Private repositories are not supported. A Worker acts in one environment class per run; code and browser together cannot run yet. Browser environments on Browserbase are unchanged. Command output is an observation, not evidence of a vendor-side effect.

Networking

A code environment denies egress by default except for dependency provisioning; a browser environment uses an allowlist. Widening it is a reviewed change to the Worker’s limits, and a run that reaches a destination outside the list fails with network_destination_denied carrying a widen_network_policy fix. Where the environment runs on the fleet, that policy is enforced in two places rather than one. deny_all is no internet access at the fabric, outside the guest. An allowlist is address rules whose only permitted destination is a SOCKS5 proxy Obol operates, and every name-based decision is taken there, where Obol can also enforce the scheme rule, refuse private addresses, pin the address it resolved and re-evaluate a redirect. The proxy fails closed when it is unreachable, which means its availability is your run’s availability. The vendor’s own domain rules are not used at all, and that is deliberate rather than an omission: using any domain entry there permanently allows a public nameserver that cannot be removed, which would be a DNS channel to a third party inside an environment you have been told is restricted. With no domain entry the guest has no name resolution of its own, and the name it wanted arrives at the proxy for Obol to resolve and check. The per-command destination check still runs as well, because the vendor cannot express scheme restriction, private-address refusal, address pinning or redirect re-evaluation.

Evidence from an environment

An environment produces observations: a screenshot, a command’s output, a file. Those are recorded with their provenance, and provenance keeps two questions apart — who observed this, and what the observation is worth. Hosted compute raises no evidence ceiling: a screenshot of a confirmation page is an observation of a screen, and it is not proof that a vendor-side effect occurred. What a receipt may claim is decided by the route the call took, and the receipt names the class — see Evidence.