Create

Each example below is an equivalent alternative; clients do not share the same in-memory handle. The TypeScript SDK supports internetAccess and typed egress policy on create. Use the Python SDK, CLI, or HTTP API when you need raw network fields that the TypeScript SDK has not wrapped yet, such as mask_request_host.
from nullspace import Machine

machine = Machine.create(
    template="base",
    vcpus=2,
    memory_mb=512,
    disk_mb=8192,
    timeout=300,
    cwd="/workspace",
    envs={"APP_ENV": "dev"},
    metadata={"project": "docs"},
    network={"mask_request_host": "localhost:${PORT}"},
)
print(machine.id)
machine.kill()
import { Machine } from "@nullspace/sdk";

const machine = await Machine.create({
  template: "base",
  vcpus: 2,
  memoryMb: 512,
  diskMb: 8192,
  timeout: 300,
  cwd: "/workspace",
  envs: { APP_ENV: "dev" },
  metadata: { project: "docs" },
});
console.log(machine.info.id);
await machine.destroy();
nullspace machine create --template base --vcpus 2 --memory 512 --disk 8192 --timeout 300
curl -X POST "${NULLSPACE_API_URL}/v1/machines" \
  -H "Authorization: Bearer ${NULLSPACE_API_KEY}" \
  -H "Content-Type: application/json" \
  -d '{
    "template": "base",
    "vcpus": 2,
    "memory_mb": 512,
    "disk_mb": 8192,
    "timeout_ms": 300000,
    "cwd": "/workspace",
    "envs": { "APP_ENV": "dev" },
    "metadata": { "project": "docs" },
    "network": { "mask_request_host": "localhost:${PORT}" }
  }'
disk_mb sets the minimum rootfs size (MB). On cold create the disk is grown to this size before boot, up to the current create limit of 163840 MiB (160 GiB). Snapshot-backed templates fix their disk size at build time, so for those set the size with Template.build(..., disk_mb=...) rather than per-create — passing a larger disk_mb than the template’s built-in size is rejected.

Create From A Template Warm Pool

Use a template warm pool when many machines should start from the same ready custom template. Pass an explicit pool ID and checkout mode. The TypeScript SDK does not expose warm-pool checkout on create, so use the Python SDK, CLI, or HTTP API:
machine = Machine.create(
    template="team/review-api:stable",
    warm_pool="twp_review_api_small",
    warm_pool_mode="prefer",
    warm_pool_wait_ms=1500,
)
print(machine.get_info().warm_pool_checkout)
nullspace machine create \
  --template team/review-api:stable \
  --warm-pool twp_review_api_small \
  --warm-pool-mode prefer \
  --warm-pool-wait 1500 \
  --json
curl -X POST "${NULLSPACE_API_URL}/v1/machines" \
  -H "Authorization: Bearer ${NULLSPACE_API_KEY}" \
  -H "Content-Type: application/json" \
  -d '{
    "template": "team/review-api:stable",
    "warm_pool": { "id": "twp_review_api_small", "mode": "prefer", "wait_ms": 1500 }
  }'
prefer may cold-fallback, require fails with warm_pool_unavailable, and bypass forces cold create. Snapshot restore, resume, fork, hibernate, and pause do not use template warm-pool checkout.

Connect

Use connect when another process created the machine or when a previous script handed you a machine ID.
machine = Machine.connect("mch_123")
print(machine.get_info().status)
import { Machine } from "@nullspace/sdk";

const machine = await Machine.connect("mch_123");
console.log(machine.info.status);
If the ID points at a paused machine alias, connect() resumes the snapshot and returns a running machine handle. For a read-only lookup that does not wake paused work, use Machine.get_info_by_id("mch_123"), nullspace machine get mch_123, or GET /v1/machines/mch_123 (see Inspect).

List

page = Machine.list(limit=20)
for item in page.items:
    print(item.id, item.status, item.template)

while page.has_next:
    for item in page.next_items():
        print(item.id)
import { NullspaceClient } from "@nullspace/sdk";

const client = new NullspaceClient();
const page = await client.machines.list({ limit: 20 });
for (const item of page.items) {
  console.log(item.id, item.status, item.template);
}
nullspace machine list --limit 20
nullspace machine list --state running --json
curl "${NULLSPACE_API_URL}/v1/machines?limit=20" \
  -H "Authorization: Bearer ${NULLSPACE_API_KEY}"
Filter lists by state, template, or metadata:
from nullspace import MachineQuery

page = Machine.list(
    query=MachineQuery(template="base", metadata={"project": "docs"}),
    limit=20,
)
Use fields when you only need a compact response:
rows = Machine.list(fields=["id", "status", "template"])
for row in rows:
    print(row["id"], row["status"])
When fields is set, the SDK returns raw dictionaries instead of a MachinePaginator.

Inspect

info = machine.get_info()
print(info.id, info.status, info.template)
print(info.metadata)
print(machine.is_running())
const info = await machine.refresh();
console.log(info.id, info.status, info.template);
console.log(info.metadata);
console.log(await machine.isRunning());
nullspace machine get mch_123 --json
curl "${NULLSPACE_API_URL}/v1/machines/mch_123" \
  -H "Authorization: Bearer ${NULLSPACE_API_KEY}"
For read-only inspection without resuming a paused machine, call Machine.get_info_by_id("mch_123"). For metrics without a handle, use Machine.get_metrics_by_id("mch_123").

Cleanup

Use a context manager for short-lived tasks:
with Machine.create(template="base") as machine:
    print(machine.commands.run("echo ready", shell=True).stdout)
For long-lived sessions, call machine.kill() or Machine.kill_by_id("mch_...") when the work is complete.