> ## Documentation Index
> Fetch the complete documentation index at: https://docs.dedaluslabs.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Executions

> Run arbitrary shell commands on Dedalus Machines

export const Pop = ({content, children}) => {
  const [open, setOpen] = useState(false);
  const [hoverOpen, setHoverOpen] = useState(false);
  const [isDark, setIsDark] = useState(false);
  const triggerRef = useRef(null);
  const portalRef = useRef(null);
  const closeTimer = useRef(null);
  const isOpen = open || hoverOpen;
  useEffect(() => {
    const probe = () => setIsDark(document.documentElement.classList.contains("dark"));
    probe();
    const obs = new MutationObserver(probe);
    obs.observe(document.documentElement, {
      attributes: true,
      attributeFilter: ["class"]
    });
    return () => obs.disconnect();
  }, []);
  const onEnter = () => {
    clearTimeout(closeTimer.current);
    setHoverOpen(true);
  };
  const onLeave = () => {
    closeTimer.current = setTimeout(() => setHoverOpen(false), 150);
  };
  useEffect(() => {
    if (!isOpen) return;
    const node = document.createElement("div");
    node.setAttribute("role", "dialog");
    node.textContent = content;
    document.body.appendChild(node);
    portalRef.current = node;
    const dark = document.documentElement.classList.contains("dark");
    Object.assign(node.style, {
      position: "fixed",
      zIndex: "9999",
      maxWidth: "20rem",
      width: "max-content",
      padding: "0.5rem 0.75rem",
      fontSize: "0.875rem",
      lineHeight: "1.55",
      color: dark ? "rgb(244, 244, 245)" : "rgb(39, 39, 42)",
      backgroundColor: dark ? "rgba(24, 24, 27, 0.4)" : "rgba(255, 255, 255, 0.4)",
      backdropFilter: "blur(4px) saturate(160%)",
      WebkitBackdropFilter: "blur(4px) saturate(160%)",
      border: dark ? "1px solid rgba(255, 255, 255, 0.18)" : "1px solid rgba(0, 0, 0, 0.16)",
      boxShadow: "0 8px 32px rgba(0, 0, 0, 0.12)",
      opacity: "0",
      transform: "translateY(-4px)",
      transition: "opacity 180ms cubic-bezier(0.16, 1, 0.3, 1), transform 180ms cubic-bezier(0.16, 1, 0.3, 1)"
    });
    const place = () => {
      const r = triggerRef.current?.getBoundingClientRect();
      if (!r || !portalRef.current) return;
      portalRef.current.style.left = `${r.left}px`;
      portalRef.current.style.top = `${r.bottom + 8}px`;
    };
    place();
    requestAnimationFrame(() => {
      node.style.opacity = "1";
      node.style.transform = "translateY(0)";
    });
    node.addEventListener("mouseenter", onEnter);
    node.addEventListener("mouseleave", onLeave);
    window.addEventListener("scroll", place, true);
    window.addEventListener("resize", place);
    return () => {
      window.removeEventListener("scroll", place, true);
      window.removeEventListener("resize", place);
      node.remove();
      portalRef.current = null;
    };
  }, [isOpen, content]);
  useEffect(() => {
    if (!open) return;
    const dismiss = e => {
      const inside = triggerRef.current?.contains(e.target) || portalRef.current?.contains(e.target);
      if (!inside) {
        setOpen(false);
        setHoverOpen(false);
      }
    };
    const onKey = e => e.key === "Escape" && (setOpen(false), setHoverOpen(false));
    document.addEventListener("mousedown", dismiss);
    document.addEventListener("keydown", onKey);
    return () => {
      document.removeEventListener("mousedown", dismiss);
      document.removeEventListener("keydown", onKey);
    };
  }, [open]);
  return <button ref={triggerRef} type="button" onClick={() => setOpen(v => !v)} onMouseEnter={onEnter} onMouseLeave={onLeave} aria-expanded={isOpen} className="cursor-pointer bg-transparent border-0 p-0 text-inherit underline decoration-dotted underline-offset-[3px] transition-colors" style={{
    textDecorationColor: isDark ? "rgb(113, 113, 122)" : "rgb(161, 161, 170)"
  }}>
			{children}
		</button>;
};

## Run a command

Execute is asynchronous: create returns immediately, you poll until <Pop content="A finished status: succeeded, failed, cancelled, or expired.">terminal</Pop>, then fetch output.

<CodeGroup>
  ```bash CLI theme={"theme":{"light":"github-light","dark":"github-dark"}}
  dedalus machines executions create \
    --machine-id "$MACHINE_ID" \
    --command '["echo 'hello world'"]'
  ```

  ```python Python theme={"theme":{"light":"github-light","dark":"github-dark"}}
  import time
  from dedalus_sdk import Dedalus

  TERMINAL = {"succeeded", "failed", "cancelled", "expired"}

  def run(client: Dedalus, machine_id: str, command: list[str], **kwargs) -> str:
      """Block until the execution finishes; return stdout. Raises on failure."""
      exc = client.machines.executions.create(machine_id=machine_id, command=command, **kwargs)
      delay = 0.1
      while exc.status not in TERMINAL:
          wait = (exc.retry_after_ms or 0) / 1000 if exc.status == "wake_in_progress" else delay
          time.sleep(wait)
          delay = min(delay * 2, 2.0)
          exc = client.machines.executions.retrieve(machine_id=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=machine_id, execution_id=exc.execution_id)
      return out.stdout or ""

  print(run(client, machine_id, ["/bin/bash", "-c", "uname -a"]))
  ```

  ```typescript TypeScript theme={"theme":{"light":"github-light","dark":"github-dark"}}
  import Dedalus from "dedalus";

  const TERMINAL = new Set(["succeeded", "failed", "cancelled", "expired"]);
  const sleep = (ms: number) => new Promise((r) => setTimeout(r, ms));

  async function run(
    client: Dedalus, machineId: string, command: string[],
    opts: { stdin?: string; env?: Record<string, string>; cwd?: string; timeout_ms?: number } = {},
  ): Promise<string> {
    let exc = await client.machines.executions.create({
      machine_id: machineId,
      command,
      ...opts,
    });
    let delay = 100;
    while (!TERMINAL.has(exc.status)) {
      const wait = exc.status === "wake_in_progress" ? (exc.retry_after_ms ?? 0) : delay;
      await sleep(wait);
      delay = Math.min(delay * 2, 2000);
      exc = await client.machines.executions.retrieve({
        machine_id: machineId,
        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: machineId,
      execution_id: exc.execution_id,
    });
    return out.stdout ?? "";
  }

  console.log(await run(client, machineId, ["/bin/bash", "-c", "uname -a"]));
  ```

  ```go Go theme={"theme":{"light":"github-light","dark":"github-dark"}}
  func run(ctx context.Context, client dedalus.Client, machineID string, command []string) (string, error) {
      done := map[dedalus.ExecutionStatus]bool{
          dedalus.ExecutionStatusSucceeded: true,
          dedalus.ExecutionStatusFailed: true,
          dedalus.ExecutionStatusCancelled: true,
          dedalus.ExecutionStatusExpired: true,
      }

      exc, err := client.Machines.Executions.New(ctx, dedalus.MachineExecutionNewParams{
          MachineID: machineID,
          ExecutionCreateParams: dedalus.ExecutionCreateParams{
              Command: command,
          },
      })
      if err != nil {
          return "", err
      }

      for !done[exc.Status] {
          time.Sleep(500 * time.Millisecond)
          exc, err = client.Machines.Executions.Get(ctx, dedalus.MachineExecutionGetParams{
              MachineID: machineID, ExecutionID: exc.ExecutionID,
          })
          if err != nil {
              return "", err
          }
      }
      if exc.Status != dedalus.ExecutionStatusSucceeded {
          return "", fmt.Errorf("%s: %s", exc.ErrorCode, exc.ErrorMessage)
      }

      out, err := client.Machines.Executions.Output(ctx, dedalus.MachineExecutionOutputParams{
          MachineID: machineID, ExecutionID: exc.ExecutionID,
      })
      if err != nil {
          return "", err
      }
      return out.Stdout, nil
  }

  stdout, _ := run(ctx, client, machineID, []string{"/bin/bash", "-c", "uname -a"})
  fmt.Println(stdout)
  ```
</CodeGroup>

## Create

Start an execution. Returns immediately.

<CodeGroup>
  ```bash CLI theme={"theme":{"light":"github-light","dark":"github-dark"}}
  dedalus machines executions create --machine-id "$MACHINE_ID" --command '["whoami"]'
  ```

  ```python Python theme={"theme":{"light":"github-light","dark":"github-dark"}}
  exc = client.machines.executions.create(
      machine_id=machine_id,
      command=["/bin/bash", "-c", "whoami"],
  )
  ```

  ```typescript TypeScript theme={"theme":{"light":"github-light","dark":"github-dark"}}
  const exc = await client.machines.executions.create({
    machine_id: machineId,
    command: ["/bin/bash", "-c", "whoami"],
  });
  ```

  ```go Go theme={"theme":{"light":"github-light","dark":"github-dark"}}
  exc, _ := client.Machines.Executions.New(ctx, dedalus.MachineExecutionNewParams{
      MachineID: machineID,
      ExecutionCreateParams: dedalus.ExecutionCreateParams{
          Command: []string{"/bin/bash", "-c", "whoami"},
      },
  })
  fmt.Println(exc.ExecutionID)
  ```
</CodeGroup>

<Accordion title="Parameters">
  <ParamField path="machine_id" type="string" required>
    The machine to run the command on.
  </ParamField>

  <ParamField body="command" type="string[]" required>
    `argv` array. The first element is the executable; the rest are arguments.
  </ParamField>

  <ParamField body="stdin" type="string">
    Bytes to pipe to the process's stdin.
  </ParamField>

  <ParamField body="env" type="object">
    Extra environment variables for this process.
  </ParamField>

  <ParamField body="cwd" default="/root" type="string">
    Working directory.
  </ParamField>

  <ParamField body="timeout_ms" type="integer">
    Hard kill after this many milliseconds.
  </ParamField>
</Accordion>

## Retrieve

Get the current state of an execution. Use this to poll until terminal.

<CodeGroup>
  ```bash CLI theme={"theme":{"light":"github-light","dark":"github-dark"}}
  dedalus machines executions retrieve --machine-id "$MACHINE_ID" --execution-id "$EXEC_ID"
  ```

  ```python Python theme={"theme":{"light":"github-light","dark":"github-dark"}}
  exc = client.machines.executions.retrieve(machine_id=machine_id, execution_id="<execution_id>")
  ```

  ```typescript TypeScript theme={"theme":{"light":"github-light","dark":"github-dark"}}
  const exc = await client.machines.executions.retrieve({
    machine_id: machineId,
    execution_id: "<execution_id>",
  });
  ```

  ```go Go theme={"theme":{"light":"github-light","dark":"github-dark"}}
  exc, _ := client.Machines.Executions.Get(ctx, dedalus.MachineExecutionGetParams{
      MachineID:    machineID,
      ExecutionID: "<execution_id>",
  })
  fmt.Println(exc.Status)
  ```
</CodeGroup>

<Accordion title="Parameters">
  <ParamField path="machine_id" type="string" required>
    The machine that owns the execution.
  </ParamField>

  <ParamField path="execution_id" type="string" required>
    The execution to retrieve.
  </ParamField>
</Accordion>

## List

List executions on a machine, newest first.

<CodeGroup>
  ```bash CLI theme={"theme":{"light":"github-light","dark":"github-dark"}}
  dedalus machines executions list --machine-id "$MACHINE_ID"
  ```

  ```python Python theme={"theme":{"light":"github-light","dark":"github-dark"}}
  page = client.machines.executions.list(machine_id=machine_id)
  for exc in page.items or []:
      print(exc.execution_id, exc.status)
  ```

  ```typescript TypeScript theme={"theme":{"light":"github-light","dark":"github-dark"}}
  const page = await client.machines.executions.list({ machine_id: machineId });
  for (const exc of page.items ?? []) console.log(exc.execution_id, exc.status);
  ```

  ```go Go theme={"theme":{"light":"github-light","dark":"github-dark"}}
  page, _ := client.Machines.Executions.List(ctx, dedalus.MachineExecutionListParams{
      MachineID: machineID,
  })
  for _, exc := range page.Items {
      fmt.Println(exc.ExecutionID, exc.Status)
  }
  ```
</CodeGroup>

<Accordion title="Parameters">
  <ParamField path="machine_id" type="string" required>
    The machine whose executions you want to list.
  </ParamField>

  <ParamField query="cursor" type="string">
    Pagination cursor from a prior page's `next_cursor`.
  </ParamField>

  <ParamField query="limit" type="integer">
    Max items per page.
  </ParamField>
</Accordion>

## Delete

Cancel a running execution. No-op if already terminated.

<CodeGroup>
  ```bash CLI theme={"theme":{"light":"github-light","dark":"github-dark"}}
  dedalus machines executions delete --machine-id "$MACHINE_ID" --execution-id "$EXEC_ID"
  ```

  ```python Python theme={"theme":{"light":"github-light","dark":"github-dark"}}
  client.machines.executions.delete(machine_id=machine_id, execution_id="<execution_id>")
  ```

  ```typescript TypeScript theme={"theme":{"light":"github-light","dark":"github-dark"}}
  await client.machines.executions.delete({
    machine_id: machineId,
    execution_id: "<execution_id>",
  });
  ```

  ```go Go theme={"theme":{"light":"github-light","dark":"github-dark"}}
  client.Machines.Executions.Delete(ctx, dedalus.MachineExecutionDeleteParams{
      MachineID:    machineID,
      ExecutionID: "<execution_id>",
  })
  ```
</CodeGroup>

<Accordion title="Parameters">
  <ParamField path="machine_id" type="string" required>
    The machine that owns the execution.
  </ParamField>

  <ParamField path="execution_id" type="string" required>
    The execution to cancel.
  </ParamField>
</Accordion>

## Events

Per-execution event log: stdout/stderr chunks plus lifecycle transitions. Cursor-paginated.

<CodeGroup>
  ```bash CLI theme={"theme":{"light":"github-light","dark":"github-dark"}}
  dedalus machines executions events --machine-id "$MACHINE_ID" --execution-id "$EXEC_ID"
  ```

  ```python Python theme={"theme":{"light":"github-light","dark":"github-dark"}}
  page = client.machines.executions.events(machine_id=machine_id, execution_id="<execution_id>")
  for e in page.items or []:
      print(e.sequence, e.type, e.chunk)
  ```

  ```typescript TypeScript theme={"theme":{"light":"github-light","dark":"github-dark"}}
  const events = client.machines.executions.events({
    machine_id: machineId,
    execution_id: "<execution_id>",
  });
  for await (const e of events) console.log(e.sequence, e.type, e.chunk);
  ```

  ```go Go theme={"theme":{"light":"github-light","dark":"github-dark"}}
  page, _ := client.Machines.Executions.Events(ctx, dedalus.MachineExecutionEventsParams{
      MachineID:   machineID,
      ExecutionID: "<execution_id>",
  })
  for _, e := range page.Items {
      fmt.Println(e.Sequence, e.Type, e.Chunk)
  }
  ```
</CodeGroup>

<Accordion title="Parameters">
  <ParamField path="machine_id" type="string" required>
    The machine that owns the execution.
  </ParamField>

  <ParamField path="execution_id" type="string" required>
    The execution whose events you want to read.
  </ParamField>

  <ParamField query="cursor" type="string">
    Pagination cursor from a prior page's `next_cursor`.
  </ParamField>

  <ParamField query="limit" type="integer">
    Max events per page.
  </ParamField>
</Accordion>

## Output

Output returns the command's captured `stdout` and `stderr` after the execution finishes.

<CodeGroup>
  ```bash CLI theme={"theme":{"light":"github-light","dark":"github-dark"}}
  dedalus machines executions output --machine-id "$MACHINE_ID" --execution-id "$EXEC_ID"
  ```

  ```python Python theme={"theme":{"light":"github-light","dark":"github-dark"}}
  out = client.machines.executions.output(machine_id=machine_id, execution_id="<execution_id>")
  print(out.stdout)
  ```

  ```typescript TypeScript theme={"theme":{"light":"github-light","dark":"github-dark"}}
  const out = await client.machines.executions.output({
    machine_id: machineId,
    execution_id: "<execution_id>",
  });
  console.log(out.stdout);
  ```

  ```go Go theme={"theme":{"light":"github-light","dark":"github-dark"}}
  out, _ := client.Machines.Executions.Output(ctx, dedalus.MachineExecutionOutputParams{
      MachineID:    machineID,
      ExecutionID: "<execution_id>",
  })
  fmt.Println(out.Stdout)
  ```
</CodeGroup>

<Accordion title="Parameters">
  <ParamField path="machine_id" type="string" required>
    The machine that owns the execution.
  </ParamField>

  <ParamField path="execution_id" type="string" required>
    The finished execution whose output you want.
  </ParamField>
</Accordion>
