DedalusDedalusDedalus Labs
PricingBlogDocs
YBacked by Y CombinatorNewFrom Today to A2A: Crossing the Imagination ChasmFrom Today to A2A
⣁⡀
DedalusDedalusDedalus Labs

Dedalus Machines are the fastest persistent sandboxes for AI agents. Host long-running, stateful agents that never sleep in <50ms.

Product
  • Pricing
  • Marketplace
  • API
  • Docs
Company
  • About
  • Blog
  • Careers
  • Contact
Community
  • Startups
  • Creators
  • Ambassadors
  • Merch
Legal
  • Privacy Policy
  • Terms of Service

© 2026 Dedalus Labs. All rights reserved.

San Francisco, CA

Command Palette

Search for a command to run...

DedalusDedalusDedalus Labs
PricingBlogDocs
YBacked by Y CombinatorNewFrom Today to A2A: Crossing the Imagination ChasmFrom Today to A2A
⣁⡀
DedalusDedalusDedalus Labs

Dedalus Machines are the fastest persistent sandboxes for AI agents. Host long-running, stateful agents that never sleep in <50ms.

Product
  • Pricing
  • Marketplace
  • API
  • Docs
Company
  • About
  • Blog
  • Careers
  • Contact
Community
  • Startups
  • Creators
  • Ambassadors
  • Merch
Legal
  • Privacy Policy
  • Terms of Service

© 2026 Dedalus Labs. All rights reserved.

San Francisco, CA

Command Palette

Search for a command to run...

Dedalus Machines

Stateful Linux VMs with durable storage, SSH, and a headless execution API. Copy this page into any agent context and start building.

Quickstart

Dedalus Machines are isolated Linux microVMs with durable storage, SSH, and a headless execution API. Copy, paste, run.

Setup

bash
brew install dedalus-labs/tap/dedalus
bash
export DEDALUS_BASE_URL=https://dev.dcs.dedaluslabs.ai
export DEDALUS_API_KEY=<YOUR_DEDALUS_API_KEY>

SDKs

bash
pip install dedalus-sdk          # Python
npm install dedalus              # TypeScript
go get github.com/dedalus-labs/dedalus-go  # Go

Create a machine and run a command

CLI

bash
dedalus machines create --vcpu 1 --memory-mib 1024 --storage-gib 10
# Note the machine_id (dm-...)

dedalus machines exec --machine-id dm-<id> -- whoami

Python

python
from 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)

TypeScript

typescript
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);

Go

go
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)
}

Watch machine status (SSE)

Instead of polling, stream status changes via Server-Sent Events (SSE):

bash
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:

text
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.

python
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":
                break

Exec patterns

Machines 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.

python
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"])

Machine lifecycle

bash
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>

Examples

  • openclaw-ddls: Host OpenClaw on a Dedalus Machine!

Dedalus Machines

Stateful Linux VMs with durable storage, SSH, and a headless execution API. Copy this page into any agent context and start building.

Quickstart

Dedalus Machines are isolated Linux microVMs with durable storage, SSH, and a headless execution API. Copy, paste, run.

Setup

bash
brew install dedalus-labs/tap/dedalus
bash
export DEDALUS_BASE_URL=https://dev.dcs.dedaluslabs.ai
export DEDALUS_API_KEY=<YOUR_DEDALUS_API_KEY>

SDKs

bash
pip install dedalus-sdk          # Python
npm install dedalus              # TypeScript
go get github.com/dedalus-labs/dedalus-go  # Go

Create a machine and run a command

CLI

bash
dedalus machines create --vcpu 1 --memory-mib 1024 --storage-gib 10
# Note the machine_id (dm-...)

dedalus machines exec --machine-id dm-<id> -- whoami

Python

python
from 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)

TypeScript

typescript
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);

Go

go
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)
}

Watch machine status (SSE)

Instead of polling, stream status changes via Server-Sent Events (SSE):

bash
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:

text
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.

python
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":
                break

Exec patterns

Machines 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.

python
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"])

Machine lifecycle

bash
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>

Examples

  • openclaw-ddls: Host OpenClaw on a Dedalus Machine!