Search for a command to run...
Search for a command to run...
Stateful Linux VMs with durable storage, SSH, and a headless execution API. Copy this page into any agent context and start building.
Dedalus Machines are isolated Linux microVMs with durable storage, SSH, and a headless execution API. Copy, paste, run.
brew install dedalus-labs/tap/dedalusexport DEDALUS_BASE_URL=https://dev.dcs.dedaluslabs.ai
export DEDALUS_API_KEY=<YOUR_DEDALUS_API_KEY>pip install dedalus-sdk # Python
npm install dedalus # TypeScript
go get github.com/dedalus-labs/dedalus-go # Godedalus machines create --vcpu 1 --memory-mib 1024 --storage-gib 10
# Note the machine_id (dm-...)
dedalus machines exec --machine-id dm-<id> -- whoamifrom dedalus_sdk import Dedalus
import os, time
client = Dedalus(
api_key=os.environ["DEDALUS_API_KEY"],
base_url="https://dev.dcs.dedaluslabs.ai",
)
dm = client.machines.create(vcpu=1, memory_mib=1024, storage_gib=10)
while dm.status.phase != "running":
time.sleep(1)
dm = client.machines.retrieve(machine_id=dm.machine_id)
exc = client.machines.executions.create(
machine_id=dm.machine_id,
command=["/bin/bash", "-c", "whoami && uname -a"],
)
while exc.status not in ("succeeded", "failed"):
time.sleep(0.5)
exc = client.machines.executions.retrieve(
machine_id=dm.machine_id, execution_id=exc.execution_id,
)
output = client.machines.executions.output(
machine_id=dm.machine_id, execution_id=exc.execution_id,
)
print(output.stdout)import Dedalus from "dedalus";
const client = new Dedalus({
apiKey: process.env.DEDALUS_API_KEY,
baseURL: "https://dev.dcs.dedaluslabs.ai",
});
let dm = await client.machines.create({
vcpu: 1,
memory_mib: 1024,
storage_gib: 10,
});
while (dm.status.phase !== "running") {
await new Promise((r) => setTimeout(r, 1000));
dm = await client.machines.retrieve({ machine_id: dm.machine_id });
}
const exec = await client.machines.executions.create({
machine_id: dm.machine_id,
command: ["/bin/bash", "-c", "whoami && uname -a"],
});
let result = exec;
while (result.status !== "succeeded" && result.status !== "failed") {
await new Promise((r) => setTimeout(r, 500));
result = await client.machines.executions.retrieve({
machine_id: dm.machine_id,
execution_id: exec.execution_id,
});
}
const output = await client.machines.executions.output({
machine_id: dm.machine_id,
execution_id: exec.execution_id,
});
console.log(output.stdout);package main
import (
"context"
"fmt"
"time"
"github.com/dedalus-labs/dedalus-go"
"github.com/dedalus-labs/dedalus-go/option"
)
func main() {
client := dedalus.NewClient(
option.WithAPIKey("your-api-key"),
option.WithBaseURL("https://dev.dcs.dedaluslabs.ai"),
)
ctx := context.Background()
dm, _ := client.Machines.New(ctx, dedalus.MachineNewParams{
CreateParams: dedalus.CreateParams{
VCPU: 1, MemoryMiB: 1024, StorageGiB: 10,
},
})
for dm.Status.Phase != "running" {
time.Sleep(time.Second)
dm, _ = client.Machines.Get(ctx, dedalus.MachineGetParams{
MachineID: dm.MachineID,
})
}
exc, _ := client.Machines.Executions.New(ctx, dedalus.MachineExecutionNewParams{
MachineID: dm.MachineID,
ExecutionCreateParams: dedalus.ExecutionCreateParams{
Command: []string{"/bin/bash", "-c", "whoami && uname -a"},
},
})
for exc.Status != "succeeded" && exc.Status != "failed" {
time.Sleep(500 * time.Millisecond)
exc, _ = client.Machines.Executions.Get(ctx, dedalus.MachineExecutionGetParams{
MachineID: dm.MachineID, ExecutionID: exc.ExecutionID,
})
}
output, _ := client.Machines.Executions.Output(ctx, dedalus.MachineExecutionOutputParams{
MachineID: dm.MachineID, ExecutionID: exc.ExecutionID,
})
fmt.Println(output.Stdout)
}Instead of polling, stream status changes via Server-Sent Events (SSE):
curl -N https://dev.dcs.dedaluslabs.ai/v1/machines/dm-<id>/status/stream \
-H "Authorization: Bearer $DEDALUS_API_KEY" \
-H "Accept: text/event-stream"Each event is a JSON object with the full machine state:
event: status
data: {"machine_id":"dm-...","status":{"phase":"running",...}}In code, use any SSE client. The stream stays open until the machine is destroyed or you disconnect.
import os, json, urllib.request
machine_id = "dm-..." # from create output
url = f"https://dev.dcs.dedaluslabs.ai/v1/machines/{machine_id}/status/stream"
req = urllib.request.Request(url, headers={
"Authorization": f"Bearer {os.environ['DEDALUS_API_KEY']}",
"Accept": "text/event-stream",
})
with urllib.request.urlopen(req) as resp:
for line in resp:
line = line.decode().strip()
if line.startswith("data: "):
status = json.loads(line[6:])
print(status["status"]["phase"])
if status["status"]["phase"] == "running":
breakMachines are stateful Linux VMs with persistent /home/machine storage. Files
written in one exec are visible in the next. The machine stays running until you
sleep or delete it.
def exec_cmd(client, machine_id, command):
"""Run a command and return stdout."""
exc = client.machines.executions.create(
machine_id=machine_id, command=command,
)
while exc.status not in ("succeeded", "failed"):
time.sleep(0.5)
exc = client.machines.executions.retrieve(
machine_id=machine_id, execution_id=exc.execution_id,
)
output = client.machines.executions.output(
machine_id=machine_id, execution_id=exc.execution_id,
)
return output.stdout
machine_id = dm.machine_id # from create output above
exec_cmd(client, machine_id, ["apt-get", "install", "-y", "python3-pip"])
exec_cmd(client, machine_id, ["/bin/bash", "-c",
"cd /home/machine && git clone https://github.com/org/repo"])
exec_cmd(client, machine_id, ["/bin/bash", "-c",
"cd /home/machine/repo && python -m pytest -v 2>&1"])
exec_cmd(client, machine_id, ["/bin/bash", "-c",
"nohup python server.py > /tmp/server.log 2>&1 &"])
exec_cmd(client, machine_id, ["cat", "/home/machine/repo/output.json"])
exec_cmd(client, machine_id, ["/bin/bash", "-c",
"echo 'hello' > /home/machine/test.txt"])
exec_cmd(client, machine_id, ["/bin/bash", "-c",
"free -h && df -h /home/machine"])dedalus machines list
dedalus machines retrieve --machine-id dm-<id>
# Sleep (zero compute cost, storage persists)
dedalus machines update --machine-id dm-<id> --desired-state sleeping
# Wake
dedalus machines update --machine-id dm-<id> --desired-state running
# Resize (live, no restart)
dedalus machines update --machine-id dm-<id> --vcpu 2 --memory-mib 2048
# Delete (grab revision from retrieve output)
dedalus machines delete --machine-id dm-<id> --if-match <revision>Stateful Linux VMs with durable storage, SSH, and a headless execution API. Copy this page into any agent context and start building.
Dedalus Machines are isolated Linux microVMs with durable storage, SSH, and a headless execution API. Copy, paste, run.
brew install dedalus-labs/tap/dedalusexport DEDALUS_BASE_URL=https://dev.dcs.dedaluslabs.ai
export DEDALUS_API_KEY=<YOUR_DEDALUS_API_KEY>pip install dedalus-sdk # Python
npm install dedalus # TypeScript
go get github.com/dedalus-labs/dedalus-go # Godedalus machines create --vcpu 1 --memory-mib 1024 --storage-gib 10
# Note the machine_id (dm-...)
dedalus machines exec --machine-id dm-<id> -- whoamifrom dedalus_sdk import Dedalus
import os, time
client = Dedalus(
api_key=os.environ["DEDALUS_API_KEY"],
base_url="https://dev.dcs.dedaluslabs.ai",
)
dm = client.machines.create(vcpu=1, memory_mib=1024, storage_gib=10)
while dm.status.phase != "running":
time.sleep(1)
dm = client.machines.retrieve(machine_id=dm.machine_id)
exc = client.machines.executions.create(
machine_id=dm.machine_id,
command=["/bin/bash", "-c", "whoami && uname -a"],
)
while exc.status not in ("succeeded", "failed"):
time.sleep(0.5)
exc = client.machines.executions.retrieve(
machine_id=dm.machine_id, execution_id=exc.execution_id,
)
output = client.machines.executions.output(
machine_id=dm.machine_id, execution_id=exc.execution_id,
)
print(output.stdout)import Dedalus from "dedalus";
const client = new Dedalus({
apiKey: process.env.DEDALUS_API_KEY,
baseURL: "https://dev.dcs.dedaluslabs.ai",
});
let dm = await client.machines.create({
vcpu: 1,
memory_mib: 1024,
storage_gib: 10,
});
while (dm.status.phase !== "running") {
await new Promise((r) => setTimeout(r, 1000));
dm = await client.machines.retrieve({ machine_id: dm.machine_id });
}
const exec = await client.machines.executions.create({
machine_id: dm.machine_id,
command: ["/bin/bash", "-c", "whoami && uname -a"],
});
let result = exec;
while (result.status !== "succeeded" && result.status !== "failed") {
await new Promise((r) => setTimeout(r, 500));
result = await client.machines.executions.retrieve({
machine_id: dm.machine_id,
execution_id: exec.execution_id,
});
}
const output = await client.machines.executions.output({
machine_id: dm.machine_id,
execution_id: exec.execution_id,
});
console.log(output.stdout);package main
import (
"context"
"fmt"
"time"
"github.com/dedalus-labs/dedalus-go"
"github.com/dedalus-labs/dedalus-go/option"
)
func main() {
client := dedalus.NewClient(
option.WithAPIKey("your-api-key"),
option.WithBaseURL("https://dev.dcs.dedaluslabs.ai"),
)
ctx := context.Background()
dm, _ := client.Machines.New(ctx, dedalus.MachineNewParams{
CreateParams: dedalus.CreateParams{
VCPU: 1, MemoryMiB: 1024, StorageGiB: 10,
},
})
for dm.Status.Phase != "running" {
time.Sleep(time.Second)
dm, _ = client.Machines.Get(ctx, dedalus.MachineGetParams{
MachineID: dm.MachineID,
})
}
exc, _ := client.Machines.Executions.New(ctx, dedalus.MachineExecutionNewParams{
MachineID: dm.MachineID,
ExecutionCreateParams: dedalus.ExecutionCreateParams{
Command: []string{"/bin/bash", "-c", "whoami && uname -a"},
},
})
for exc.Status != "succeeded" && exc.Status != "failed" {
time.Sleep(500 * time.Millisecond)
exc, _ = client.Machines.Executions.Get(ctx, dedalus.MachineExecutionGetParams{
MachineID: dm.MachineID, ExecutionID: exc.ExecutionID,
})
}
output, _ := client.Machines.Executions.Output(ctx, dedalus.MachineExecutionOutputParams{
MachineID: dm.MachineID, ExecutionID: exc.ExecutionID,
})
fmt.Println(output.Stdout)
}Instead of polling, stream status changes via Server-Sent Events (SSE):
curl -N https://dev.dcs.dedaluslabs.ai/v1/machines/dm-<id>/status/stream \
-H "Authorization: Bearer $DEDALUS_API_KEY" \
-H "Accept: text/event-stream"Each event is a JSON object with the full machine state:
event: status
data: {"machine_id":"dm-...","status":{"phase":"running",...}}In code, use any SSE client. The stream stays open until the machine is destroyed or you disconnect.
import os, json, urllib.request
machine_id = "dm-..." # from create output
url = f"https://dev.dcs.dedaluslabs.ai/v1/machines/{machine_id}/status/stream"
req = urllib.request.Request(url, headers={
"Authorization": f"Bearer {os.environ['DEDALUS_API_KEY']}",
"Accept": "text/event-stream",
})
with urllib.request.urlopen(req) as resp:
for line in resp:
line = line.decode().strip()
if line.startswith("data: "):
status = json.loads(line[6:])
print(status["status"]["phase"])
if status["status"]["phase"] == "running":
breakMachines are stateful Linux VMs with persistent /home/machine storage. Files
written in one exec are visible in the next. The machine stays running until you
sleep or delete it.
def exec_cmd(client, machine_id, command):
"""Run a command and return stdout."""
exc = client.machines.executions.create(
machine_id=machine_id, command=command,
)
while exc.status not in ("succeeded", "failed"):
time.sleep(0.5)
exc = client.machines.executions.retrieve(
machine_id=machine_id, execution_id=exc.execution_id,
)
output = client.machines.executions.output(
machine_id=machine_id, execution_id=exc.execution_id,
)
return output.stdout
machine_id = dm.machine_id # from create output above
exec_cmd(client, machine_id, ["apt-get", "install", "-y", "python3-pip"])
exec_cmd(client, machine_id, ["/bin/bash", "-c",
"cd /home/machine && git clone https://github.com/org/repo"])
exec_cmd(client, machine_id, ["/bin/bash", "-c",
"cd /home/machine/repo && python -m pytest -v 2>&1"])
exec_cmd(client, machine_id, ["/bin/bash", "-c",
"nohup python server.py > /tmp/server.log 2>&1 &"])
exec_cmd(client, machine_id, ["cat", "/home/machine/repo/output.json"])
exec_cmd(client, machine_id, ["/bin/bash", "-c",
"echo 'hello' > /home/machine/test.txt"])
exec_cmd(client, machine_id, ["/bin/bash", "-c",
"free -h && df -h /home/machine"])dedalus machines list
dedalus machines retrieve --machine-id dm-<id>
# Sleep (zero compute cost, storage persists)
dedalus machines update --machine-id dm-<id> --desired-state sleeping
# Wake
dedalus machines update --machine-id dm-<id> --desired-state running
# Resize (live, no restart)
dedalus machines update --machine-id dm-<id> --vcpu 2 --memory-mib 2048
# Delete (grab revision from retrieve output)
dedalus machines delete --machine-id dm-<id> --if-match <revision>