SDK
Install
bun add @indexable/sdk Each package reads IX_TOKEN, then the file that ix login writes.
Example
import { Client, Machine } from "@indexable/sdk"
// A machine for this agent, removed
// when this scope ends.
await using machine = await Machine.create({
image: "ix/debian:12",
name: "agent-7",
lifetime: "ephemeral",
})
await machine.writeFile("/task.md", prompt)
const run = await machine.exec(["./agent", "/task.md"], { check: true })
console.log(run.stdout)
// Every restore is a new machine.
const snap = await machine.snapshot()
const snapshots = new Client().snapshots
const forks = await Promise.all(
["a", "b", "c"].map((n) =>
snapshots.restore(snap.snapshotId, `agent-7-${n}`),
),
)Ephemeral and persistent
A machine is persistent by default. lifetime: "ephemeral" removes it when the scope ends. A ttl makes the platform remove it at the deadline. Leaving the scope of a persistent machine never removes it.
const ix = new Client()
// Ephemeral: removed when the scope ends.
await using scratch = await ix.machines.create({ lifetime: "ephemeral" })
// A deadline: the platform removes it after 20 minutes,
// even if this process dies first.
const ci = await ix.machines.create({
ttl: "20m",
name: "ci-run-418",
})
// Persistent, the default: scope exit only releases the handle.
await using dev = await ix.machines.create({ name: "dev" })
const again = await ix.machines.connect("dev")Live output
machine.exec starts the command and returns a Process at once. Await it for the result, or read stdout and stderr while it runs. Dropping the Process stops the command. The SDK reference lists every member.
// exec returns at once. Read the output while it runs.
const proc = machine.exec(["npm", "test"])
for await (const chunk of proc.stdout) process.stdout.write(chunk)
const { exitCode } = await proc
// Write to stdin.
const sort = machine.exec(["sort"], { stdin: true })
await sort.stdin.write("b\na\n")
await sort.stdin.close()
console.log((await sort).stdout)
// Stop a command.
const slow = machine.exec(["sleep", "600"])
setTimeout(() => slow.kill(), 5000)
await slowReach a machine
In TypeScript, Machine has static functions that need no client. Each one uses your ix login or IX_TOKEN.
| Function | What it does |
|---|---|
Machine.create(options) | Boot a machine. image picks the OCI image it boots and lifetime how long it lives. The machine answers when the call returns. |
Machine.attach(nameOrId) | Adopt a machine that exists. Releasing the handle does not remove it. |
Machine.list() | List the machines in your account. |
Every method on a machine
| Method | What it does |
|---|---|
exec, shell | Run a command given as an argument list, or a script. Both return a Process at once. Await it for the result. A non-zero exit is a result unless you pass check: true. |
spawn | Start a command that outlives the call. It returns the guest pid. |
readFile, writeFile, listDir | Move files in and out. |
snapshot, waitSnapshotReady, fork | Capture the disk, wait until the snapshot can be restored, or do both and restore into a new machine. |
start, stop, restart, rename, delete | Lifecycle. |
logs, tailLogs, watch | Recorded output, live output, and status changes. |
forwardPort, connectPort | A local port that forwards into the machine, or a byte stream to a port inside it. |
Account namespaces
Everything that belongs to the account and not to one machine hangs off new Client() in TypeScript or ix_sdk.Client() in Python, as properties. Rust calls them as methods, for example ix.machines(). Python calls are asynchronous.
| Call | What it does |
|---|---|
client.machines.create(options) | Boot a machine from an image or from a snapshot. |
client.snapshots.restore(id, name) | Restore a snapshot into a new machine. |
client.keys.create(name, limitUsd) | Create an API key with a spending ceiling. |
client.secrets.set(name, value) | Store a secret. |
client.groups.create(slug), addMember | Create a private network group and add machines to it. |
Python uses the same names in snake case. Rust names follow the crate's conventions.