Environments
Provisioning, running commands in, and tearing down microVMs
client.environments provisions, inspects, drives, and tears down microVMs.
Here’s a complete flow: create one, run a command inside it, then tear it
down.
const env = await client.environments.create({
task_id: "build-1",
spec: { cpus: 2, ram_mb: 2048, storage_gb: 10 },
});
const result = await client.environments.exec(env.id, { cmd: ["make", "test"] });
if (result.exit_code !== 0) {
throw new Error(`tests failed: ${result.stderr}`);
}
await client.environments.destroy(env.id);
createprovisions from aspec(CPUs, RAM, storage, and optionally GPU) and blocks server-side until the environment isrunningor provisioning fails, so the returnedEnvironmentInfoalready reflects the outcome. No separate poll-until-ready step is needed for the common case. Wire field names are snake_case throughout,task_id/ram_mb, nottaskId/ramMb.Speccarriesgpus,gpu_kind, andgpu_profile, so fractional MIG environments can be requested type-safely from this SDK.execruns one command inside the guest and returns its exit code with stdout/stderr kept apart. A non-zeroexit_codeis a resolved call, not a thrown error, the command ran and failed, which is the answer you asked for. Only a thrown error means the command couldn’t run at all (VM not found, VM not running, or the provider has no guest to exec into).execrequires the master token, see Errors.destroytears the environment down from any state and is idempotent, a second call on an already-gone environment throws aFuseApiErrorwithcode === "not_found"rather than hanging or throwing something unrelated.
Watching state instead of exec
If you need to react to lifecycle transitions rather than run a one-shot
command, events returns an async iterable instead of a single call:
for await (const event of await client.environments.events(env.id)) {
console.log(event.state);
}
The stream yields the current state immediately on connect, then one item
per transition, and ends on its own after a terminal-state event
(destroyed/failed). There is no built-in timeout, pass { signal } to
cancel early. See the full walkthrough in
Quickstart.
Everything else
| Method | Purpose |
|---|---|
list({ taskId, state, hostId }) |
List environments, all filters optional. |
get(vmId) |
Fetch one environment by ID. |
drain(vmId) |
Phase one of teardown: signal the guest to stop gracefully without destroying the VM. |
fork(vmId, { reuse_snapshot_id, comment }) |
Create a new environment seeded from a snapshot of this one. |
rotateToken(vmId) |
Re-issue the guest’s credentials without recreating the VM. |
The two option bags differ in case on purpose. list takes a client-side
filter object, so it is camelCase; fork sends its object straight through as
the JSON request body, so it uses the snake_case wire names.
Every method accepts a trailing { signal } for cancellation. Fork is
unavailable wherever snapshotting is, GPU/QEMU-backed environments can’t be
forked, see Providers. These mirror the
HTTP API one to one.
Lifecycle states
export const State = {
Provisioning: "provisioning",
Running: "running",
Draining: "draining",
Destroying: "destroying",
Destroyed: "destroyed",
Failed: "failed",
} as const;
function isTerminalState(state: string): boolean;
isTerminalState reports whether state is Destroyed or Failed, the two
states after which an event stream ends.