CLI
Control machines from a terminal, script, or agent.1
Install the CLI
curl -fsSL https://raw.githubusercontent.com/dedalus-labs/dedalus-cli/main/scripts/install.sh | bash
brew install dedalus-labs/tap/dedalus
irm https://raw.githubusercontent.com/dedalus-labs/dedalus-cli/main/scripts/install.ps1 | iex
git clone https://github.com/dedalus-labs/dedalus-cli.git
cd dedalus-cli
go install ./cmd/dedalus
2
Set your API key
Get a Dedalus API key from the Dashboard and set it in your shell.
export DEDALUS_API_KEY=<your-key>
3
Create a machine
The CLI calls the Machines API.Save the
dedalus machines create --vcpu 1 \
--memory-mib 1024 \
--storage-gib 5 \
--autosleep never
machine_id. Later commands use it.{
"machine_id": "dm-0197f2a9-4d1c-7b8f-9f9b-3b7c1a5e0a12",
"vcpu": 1,
"memory_mib": 1024,
"storage_gib": 5,
"autosleep_seconds": 0,
"desired_state": "running",
"status": {
"phase": "accepted",
"reason": "Accepted",
"retryable": true,
"revision": "1",
"last_transition_at": "2026-06-18T00:00:00Z",
"last_progress_at": "2026-06-18T00:00:00Z"
}
}
4
Run a command
The CLI runs commands directly, without opening a shell.Save the
Machine IDs start with
dm-.dedalus machines executions create \
--machine-id <machine_id> \
--command '["/bin/bash", "-c", "whoami && uname -a"]'
execution_id. Use it to retrieve the result.{
"execution_id": "wexec-7e2f9d4b8c1a4f0d9e6c2b1a5d8f3c0e4a9b6d7c",
"machine_id": "dm-0197f2a9-4d1c-7b8f-9f9b-3b7c1a5e0a12",
"status": "queued",
"command": ["/bin/bash", "-c", "whoami && uname -a"],
"created_at": "2026-06-18T00:00:02Z"
}
5
Get the result
Poll the execution until its status is
succeeded, then fetch the captured output.dedalus machines executions retrieve \
--machine-id <machine_id> \
--execution-id <execution_id>
dedalus machines executions output \
--machine-id <machine_id> \
--execution-id <execution_id>
SSH
Use executions for agents. Use SSH for human shells and debugging. Install packages and run normal Linux commands.dedalus ssh <machine_id>
# Inside the machine:
whoami && uname -a
SDK
These examples create a machine, run a command, and print output.import time
from dedalus_sdk import Dedalus
client = Dedalus()
DONE = {"succeeded", "failed", "cancelled", "expired"}
dm = client.machines.create(vcpu=1, memory_mib=1024, storage_gib=10)
stream = client.machines.watch(machine_id=dm.machine_id)
for _ in stream:
pass
exc = client.machines.executions.create(
machine_id=dm.machine_id,
command=["/bin/bash", "-c", "whoami && uname -a"],
)
while exc.status not in DONE:
time.sleep(0.5)
exc = client.machines.executions.retrieve(
machine_id=dm.machine_id,
execution_id=exc.execution_id,
)
if exc.status != "succeeded":
raise RuntimeError(f"{exc.status}: {exc.error_code}: {exc.error_message}")
out = client.machines.executions.output(
machine_id=dm.machine_id,
execution_id=exc.execution_id,
)
print(out.stdout)
import Dedalus from "dedalus";
const client = new Dedalus();
const DONE = new Set(["succeeded", "failed", "cancelled", "expired"]);
const sleep = (ms: number) => new Promise<void>((resolve) => setTimeout(resolve, ms));
const dm = await client.machines.create({
vcpu: 1,
memory_mib: 1024,
storage_gib: 10,
});
const stream = await client.machines.watch({ machine_id: dm.machine_id });
for await (const _ of stream) {}
let exc = await client.machines.executions.create({
machine_id: dm.machine_id,
command: ["/bin/bash", "-c", "whoami && uname -a"],
});
while (!DONE.has(exc.status)) {
await sleep(500);
exc = await client.machines.executions.retrieve({
machine_id: dm.machine_id,
execution_id: exc.execution_id,
});
}
if (exc.status !== "succeeded") {
throw new Error(`${exc.status}: ${exc.error_code}: ${exc.error_message}`);
}
const out = await client.machines.executions.output({
machine_id: dm.machine_id,
execution_id: exc.execution_id,
});
console.log(out.stdout);
package main
import (
"context"
"fmt"
"time"
dedalus "github.com/dedalus-labs/dedalus-go"
)
func main() {
client := dedalus.NewClient()
ctx := context.Background()
done := map[dedalus.ExecutionStatus]bool{
dedalus.ExecutionStatusSucceeded: true,
dedalus.ExecutionStatusFailed: true,
dedalus.ExecutionStatusCancelled: true,
dedalus.ExecutionStatusExpired: true,
}
dm, err := client.Machines.New(ctx, dedalus.MachineNewParams{
CreateParams: dedalus.CreateParams{
VCPU: 1, MemoryMiB: 1024, StorageGiB: 10,
},
})
check(err)
stream := client.Machines.WatchStreaming(ctx, dedalus.MachineWatchParams{
MachineID: dm.MachineID,
})
for stream.Next() {
}
check(stream.Err())
exc, err := client.Machines.Executions.New(ctx, dedalus.MachineExecutionNewParams{
MachineID: dm.MachineID,
ExecutionCreateParams: dedalus.ExecutionCreateParams{
Command: []string{"/bin/bash", "-c", "whoami && uname -a"},
},
})
check(err)
for !done[exc.Status] {
time.Sleep(500 * time.Millisecond)
exc, err = client.Machines.Executions.Get(ctx, dedalus.MachineExecutionGetParams{
MachineID: dm.MachineID, ExecutionID: exc.ExecutionID,
})
check(err)
}
if exc.Status != dedalus.ExecutionStatusSucceeded {
panic(fmt.Sprintf("%s: %s", exc.ErrorCode, exc.ErrorMessage))
}
out, err := client.Machines.Executions.Output(ctx, dedalus.MachineExecutionOutputParams{
MachineID: dm.MachineID, ExecutionID: exc.ExecutionID,
})
check(err)
fmt.Println(out.Stdout)
}
func check(err error) {
if err != nil {
panic(err)
}
}
