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

# Apple Container

> Run captured programs in containers under Apple's container tool on macOS.

`apple_container` runs captured programs in a running container under
Apple's `container` tool. It can map each session to its own container, so
every agent gets one. You start the containers; Mirage only runs programs
in them. Needs Apple silicon and macOS 26 or later. Python SDK and Node.

## Installation

Install and start Apple's `container`. From the Mirage repository root,
build [the sandbox image](/home/setup/runtime/sandbox.md#the-sandbox-image), which
carries Mirage and `fuse3`, and start a container from it:

```bash theme={null}
brew install container
container system start
container build -f docker/sandbox/Dockerfile --target fuse \
  -t mirage-python-fuse .
container run -d --cap-add SYS_ADMIN \
  --name my-sandbox mirage-python-fuse sleep infinity
```

## Usage

`captures` defaults to [`@external`](/home/setup/runtime/overview#captures):
every program Mirage does not have itself. Name `python3` to run it in the
container too. Use `containers`, a
map from session ID to container, for one container per agent.

**Python**

```python theme={null}
from mirage import RAMVFS, MountMode, Workspace
from mirage.runtime.sandbox.apple_container import AppleContainerRuntime

runtime = AppleContainerRuntime(
    captures=["python3", "@external"],
    config={"container": "my-sandbox"},
)
ws = Workspace({"/data": RAMVFS()}, mode=MountMode.EXEC, runtimes=[runtime])
await ws.shell("python3 -c 'print(1 + 1)'")
```

**TypeScript**

```typescript theme={null}
import { AppleContainerRuntime, MountMode, RAMVFS, Workspace } from '@struktoai/mirage-node'

const runtime = new AppleContainerRuntime({
  captures: ['python3', '@external'],
  config: { container: 'my-sandbox' },
})
const ws = new Workspace({ '/data': new RAMVFS() }, { mode: MountMode.EXEC, runtimes: [runtime] })
await ws.shell("python3 -c 'print(1 + 1)'")
```

**YAML**

```yaml theme={null}
mode: exec
runtimes:
  - name: apple_container
    captures: ["python3", "@external"]
    config:
      container: my-sandbox
      containers:
        agent-1: agent-1-box
mounts:
  /data:
    vfs: ram
```

## Connecting the workspace

A program in the container opens workspace files at the same paths as in
Mirage, so the container must see the mounts there. `mount_type` picks how, as
for [Docker](/home/setup/runtime/sandbox/docker.md#connecting-the-workspace):
`ssh` serves every mount over `container exec` (the image needs `sshfs`),
`fuse` leaves them to a Mirage inside, and `both` mixes the two. `mount_type`
serves one session, so it cannot be combined with `containers`.

For `fuse`, write the same mounts at the same paths into `sandbox.yaml`, and
start Mirage with it in the container:

```yaml theme={null}
mounts:
  /data:
    vfs: s3
    config:
      bucket: my-bucket
    backend: fuse
    mountpoint: /data
```

```bash theme={null}
container cp sandbox.yaml my-sandbox:/tmp/sandbox.yaml
container exec my-sandbox mirage workspace create /tmp/sandbox.yaml
```

* This workspace's mount modes and permissions do not reach those files;
  `sandbox.yaml` decides.
* Keep the container's paths in step with the host's mounts yourself.

## Runtime behavior

| Capability | In the container |
| - | - |
| Command | The captured program and its words, as typed |
| Piped input | stdin |
| Environment | The session's, over the config `env` |
| Working directory | The shell's, unchanged |
| Workspace files | By `mount_type`; see [above](#connecting-the-workspace) |
| Disk and network | The container's own |

## Notes

* Set `container` to the name of a running container.
* The image needs a POSIX-compatible `/bin/sh`. The session's environment wins
  over the image's. The working directory must already exist in the container.
* Host directories reach the container only through `--volume`. A service on
  your Mac is not at `127.0.0.1` inside; Apple's
  [host integration guide](https://github.com/apple/container/blob/main/docs/host-integration.md)
  sets up `host.container.internal`.
* `containers` maps session IDs to containers, one per agent; a session not
  listed runs in `container`, and fails if there is none. Each container is
  its own VM, so agents share no files, processes, CPU or memory. Give each
  one that agent's rules: the `default` profile in its `sandbox.yaml`.
* A [timeout](/home/setup/runtime/sandbox.md#timeouts) does not kill the program: `container` 1.4.1 does
  not deliver signals into the guest
  ([apple/container#1941](https://github.com/apple/container/issues/1941)).


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