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

# Overview

> Run captured programs on a container, VM, cloud sandbox or remote machine you already have.

A machine is somewhere you already have: a container, a microVM, a cloud
sandbox or a host over SSH. Declare each one under `machines:` with the
`provider` that reaches it, and run captured programs there with the
`machine` runtime, whose `machine` names it. You create and stop the machine;
Mirage only runs programs on it. `captures` defaults to
[`@external`](https://docs.mirage.strukto.ai/home/setup/runtime/overview#captures), every program Mirage
does not have itself.

```yaml theme={null}
machines:
  box:
    provider: docker
    container: my-sandbox
runtimes:
  - name: machine
    machine: box
```

A line or a command can also name its machine: `execute(machine=)`, a
`machine` on the shell request, or a policy's `Route(machine=)`.

A program there opens workspace files at the same paths, so the machine
must see the mounts. `docker`, `e2b`, `ssh`, `smolvm`, `microsandbox`, and
`apple_container` pick how with `mount_type`: `ssh` serves them from the
workspace, `fuse` from a Mirage inside the machine, and `both` mixes the two.
Daytona uses a Mirage inside.

| Provider | Runs programs in | Workspace files through |
| - | - | - |
| [Docker](https://docs.mirage.strukto.ai/home/setup/machine/docker.md) | A Docker container | `mount_type`: `ssh`, `fuse` or `both` |
| [E2B](https://docs.mirage.strukto.ai/home/setup/machine/e2b.md) | An E2B cloud sandbox | `mount_type`: `ssh`, `fuse` or `both` |
| [Daytona](https://docs.mirage.strukto.ai/home/setup/machine/daytona.md) | A Daytona cloud sandbox | FUSE, from a Mirage inside |
| [smolvm](https://docs.mirage.strukto.ai/home/setup/machine/smolvm.md) | A microVM with its own kernel | `mount_type`: `ssh`, `fuse` or `both` |
| [Microsandbox](https://docs.mirage.strukto.ai/home/setup/machine/microsandbox.md) | A microVM with its own kernel | `mount_type`: `ssh`, `fuse` or `both` |
| [Apple Container](https://docs.mirage.strukto.ai/home/setup/machine/apple_container.md) | A container on macOS, a VM of its own | `mount_type`: `ssh`, `fuse` or `both` |
| [SSH](https://docs.mirage.strukto.ai/home/setup/machine/ssh.md) | Any machine running `sshd` | `mount_type`: `ssh`, `fuse` or `both` |

[Sandlock](https://docs.mirage.strukto.ai/home/setup/runtime/sandlock.md) is a runtime, not a machine:
it runs programs on this Linux host, confined, with a
[FUSE folder](https://docs.mirage.strukto.ai/home/setup/fuse.md) you grant.

After following a provider page's **Connecting the workspace** steps, run the
shared [workspace file check](https://docs.mirage.strukto.ai/home/setup/runtime/overview.md#verify-workspace-file-access)
to confirm reads and writes cross the runtime boundary.

## Language compatibility

Python modules, file modes and other language APIs come from the interpreter
installed on the machine. Mirage forwards the captured program's
arguments, input, environment and working directory; a working directory
the machine lacks fails the program with exit 126. Each run also gets
`MIRAGE_PROCESS`, the id of its Mirage process (`w1:9`), which every process
it starts inherits. Each provider's **Runtime behavior** table describes
that boundary.

File operations reach workspace mounts through the connection configured
for that provider. They also remain subject to the machine's own
permissions and confinement.

## Processes and signals

`ps` lists a program on a machine with the machine and its pid there, and
everything the program started as processes of their own, found by a scan
of the machine's `/proc` for its `MIRAGE_PROCESS`:

```text theme={null}
    PID MACHINE                            MPID CMD
4194305 -                                     - ps
4194306 docker:box                           13 python3 train.py
4194307 docker:box                           19 sleep 300
```

`ps -o machine,mpid` selects those columns, and `ps f` or `ps --forest`
draws each command under its parent's. A process a scan found leaves the
list once a scan no longer sees it.

`kill` sends a signal to a program on a machine as you sent it: a program
that traps `USR1` gets it and runs on, and one that `TERM` ends exits with
its own status, which `wait` reports. KILL is sent only when you ask for it
(`kill -9`, `timeout -k`) or when Mirage shuts the workspace down. Mirage's
own stops, a `head` that has read enough, a line's timeout, a cancelled
line, send TERM, then KILL a second later, to every process on the machine
that carries the run's `MIRAGE_PROCESS`.

In a Mirage shell a pid is Mirage's: they start at 4194305, past any
machine's own. A smaller number given to `kill`, `kill -0`, `wait` or
`ps -p` is a machine pid, the process whose program has that pid on its
machine; one that two machines both have is refused as an ambiguous job
spec. Inside a program on a machine a pid is that machine's, and a line
sent whole to a machine (`@line`) runs in that machine's shell, with its
pids. Every one of these follows the session's `processes` grants.

## Machine states

Each check finds a machine in one of three states:

| State | Means |
| - | - |
| `managed` | Mirage reached it and sees and stops every process its programs start there: it has `/proc` and the `sh`, `tr` and `grep` the scan runs. The workspace's own host is always `managed`. |
| `reachable` | Mirage reached it, but sees and stops only what it started itself. |
| `unreachable` | The last check failed. |

`GET /v1/workspaces/{id}/machines` checks every machine and lists the host
first; `GET /v1/workspaces/{id}/machines/{machine}` checks one and lists its
processes. `mirage workspace list-machines` prints the same table.

## The machine image

Every machine needs a POSIX shell at `/bin/sh`, which starts each command,
and `grep`, which finds what a run cut short left running. With
[libfaketime](https://github.com/wolfcw/libfaketime) in the image, programs
see the workspace's [`system_time`](https://docs.mirage.strukto.ai/home/configuration#system-time);
without it they see the machine's clock.
With `mount_type: ssh` the machine also needs `sshfs`.
A machine that serves the mounts with its own Mirage needs `fuse3` and
Mirage. The repository's Dockerfile builds that image from the current
checkout, with every mountable backend:

```bash theme={null}
docker build -f docker/sandbox/Dockerfile --target fuse -t mirage-python-fuse .
```

Narrow it to the backends you use with `MIRAGE_EXTRAS`:

```bash theme={null}
docker build -f docker/sandbox/Dockerfile --target fuse \
  --build-arg MIRAGE_EXTRAS=s3,postgres -t mirage-fuse-lean .
```

The same image serves every provider: run it under Docker, Apple's
`container`, Microsandbox or smolvm, or use it as a Daytona image or an E2B template base.
Add the programs your captures need, such as Node.js for `node`. The Mirage
inside is the Python build, whichever SDK the host uses.

## Timeouts

`command_limits` apply to a program on a machine as to any command: a line past
its `@line` entry's `timeout_seconds` exits 124, and `max_bytes` and
`max_lines` cap the program's output.

> [!WARNING]
>
> A timeout stops the program: Mirage sends TERM, then KILL a second later, to every process there that carries the
> run's `MIRAGE_PROCESS`; that needs `/bin/sh`, `tr`, `grep` and `/proc` on
> the machine, and Mirage gives up after 5 seconds if it stops answering. In TypeScript, a Daytona command keeps
> running after a timeout. A Daytona sandbox has no timeout of its own, so
> it keeps running and billing. Use the provider's own limits.

## Serving session files

With `mount_type: ssh`, workspace file access follows the session's permissions
and policies. You do not need to expose a public file server or copy service
credentials into the machine. Each machine is assigned to one session.

Mirage refuses to run a program when it cannot enforce the session's file
restrictions. Unsupported cases include:

* Restrictions on `/` or `/dev`.
* Hiding a mount when doing so would expose the machine's own files underneath.
* Restrictions on mounts served by a separate Mirage inside the machine.
* File rules that depend on which program opens a file.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.