---
title: "Sandbox"
description: "Compare mikan's supported host, container, image, microVM, Firecracker, and Cloudflare sandbox modes."
url: "https://geminixiang.github.io/sandbox/"
---

# Sandbox

`host` has the least setup and does not inject vault env. It cannot provide an isolated
    conversation office, so it also needs an explicit trusted door policy.
    `image:<image>` lets mikan manage lifecycle, workspace mounts, vault env, and resource limits.
    `gondolin:default` runs a local Gondolin/QEMU microVM in mikan's own process and is the planned
    successor to managed `image:*` sandboxes.

  `docker:*` is not a supported mode; use `container:*` or `image:*` instead.

## Supported modes

| Mode                                                        | Execution location        | Vault env injection | Vault key                       | Notes                                                                                            |
| ----------------------------------------------------------- | ------------------------- | ------------------- | ------------------------------- | ------------------------------------------------------------------------------------------------ |
| `host`                                                      | host machine              | not injected        | derived from the platform user  | Local development only; needs an explicit trusted door policy                                    |
| `container:<name>`                                          | existing Docker container | injected            | derived from the container name | one container one vault; multiple people sharing one container also share its vault              |
| `image:<image>`                                             | Docker managed by mikan   | injected            | the office key                  | Current recommended isolation mode; `1 conversation = 1 vault = 1 container`                     |
| `gondolin:default`                                          | local Gondolin/QEMU VM    | injected            | the office key                  | Preview; single-host, in mikan's own process; requires Node.js >=23.6 and QEMU                   |
| `firecracker:<vm-id>:<host-path>[:<ssh-user>[:<ssh-port>]]` | Firecracker VM            | injected            | the office key                  | Very early alpha; you must start the VM and mount workspace at `/workspace`; not recommended yet |
| `cloudflare:<sandbox-id>`                                   | Cloudflare Worker         | injected            | the office key                  | Under construction; requires your own `@cloudflare/sandbox` bridge; host workspace is not synced |

The office key is the versioned `v1-<platform>-<readable-id>-<hash>` segment that also names the
conversation's directory under the workspace. See [Conversation offices](#conversation-offices).

## Conversation offices

Each conversation owns one directory under the workspace root — its _office_ — named by office key
rather than by the platform's raw conversation id. Sandbox mounts follow that directory, so inside
a runtime the office is at `/workspace/<office-key>`.

Which parts of the workspace a runtime sees is the **door policy**, a `sandbox.workspace` setting
the admin portal can set globally or per conversation (the `/pi-sandbox door` chat command does the
same for one conversation, but only under `image:*` and `gondolin:*`):

| Door policy / layout         | Mounted under `/workspace`                                            |
| ---------------------------- | --------------------------------------------------------------------- |
| `isolated` (default)         | only `<office-key>/`                                                  |
| `trusted` / `shared-support` | `<office-key>/` plus the shared `MEMORY.md`, `skills/`, and `events/` |
| `trusted` / `full`           | the entire workspace root                                             |

Only `image:*` and `gondolin:default` can enforce the isolated projection. The other modes report
`managedProjection: false`, and because `isolated` is the default, they refuse to start a run until
someone explicitly chooses a trusted policy for that office. Field semantics and the legacy
`sandbox.image.workspaceMount` translation are documented in [Configuration](/configuration/).

  Door policy decides which host directories are projected into the runtime. It is not an execution
  boundary: `host` mode runs tools directly on the host with no filesystem or process isolation
  whatever policy is chosen, and a `full` layout gives the runtime every conversation's office.

### Upgrading from the raw-id layout

Workspaces created before the office layout hold directories named by raw conversation id. Every
boot migrates them — workspace directories, conversation vault keys, and per-conversation host state
— journaling each move so an interrupted run resumes instead of losing a conversation.

Two situations stop boot deliberately rather than guessing:

- **Unowned directories.** With several platforms enabled, mikan cannot tell which one owns a raw
  directory. Name the owner with `mikan office claim <conversationId> <platform>` (daemon stopped);
  the next start performs the move.
- **Conflicts**, where both the legacy and the office-key directory already exist. These are
  reported for manual merge and never clobbered.

Managed containers survive the rename: their binds are translated onto a snapshot of the running
container, so the writable layer is preserved rather than rebuilt from the base image.

## Per-mode docs

<LinkCard
  title="Host sandbox"
  description="Run tools directly on the host; best for local development."
  href="host/"
/>
<LinkCard
  title="Container sandbox"
  description="Connect to an existing Docker container and reuse your own lifecycle management."
  href="container/"
/>
<LinkCard
  title="Image sandbox"
  description="Let mikan manage per-conversation containers and resource limits."
  href="image/"
/>
<LinkCard
  title="Gondolin sandbox"
  description="Try the local Gondolin/QEMU preview intended to replace image sandboxes."
  href="gondolin/"
/>
<LinkCard
  title="Firecracker sandbox"
  description="Connect to a Firecracker VM that you start yourself."
  href="firecracker/"
/>
<LinkCard
  title="Cloudflare sandbox"
  description="Run tools through a Cloudflare Worker bridge; under construction."
  href="cloudflare/"
/>

## Capability differences

`image:<image>` <Badge text="recommended" variant="success" /> is the primary developed and recommended sandbox mode today; the other modes are kept for local development, compatibility, or experiments, and some capabilities will not be filled in.

| Capability                                   | `host`         | `container:<name>`     | `image:<image>` | `gondolin:default` | `firecracker:*` | `cloudflare:*`     |
| -------------------------------------------- | -------------- | ---------------------- | --------------- | ------------------ | --------------- | ------------------ |
| command execution                            | ✅             | ✅                     | ✅              | ✅                 | ✅              | ✅                 |
| mikan-managed runtime lifecycle              | not applicable | ❌                     | ✅              | ✅ process-owned   | ❌              | ❌                 |
| per-conversation container / runtime         | ❌             | ❌                     | ✅              | ✅                 | self-managed    | bridge-derived id  |
| per-conversation vault env                   | ❌             | ❌                     | ✅              | ✅                 | ✅              | ✅                 |
| automatic vault file projection / bind mount | ❌             | ❌                     | ✅              | ✅                 | ❌              | ❌                 |
| automatic workspace mount                    | host           | self-managed           | ✅              | ✅                 | self-managed    | ❌                 |
| isolated conversation office                 | ❌             | ❌                     | ✅              | ✅                 | ❌              | ❌                 |
| idle auto-stop / recreate                    | not applicable | ❌                     | ✅              | ✅                 | ❌              | ❌                 |
| default CPU / memory limits                  | ❌             | ❌                     | ✅              | ✅                 | ❌              | ❌                 |
| `/pi-sandbox boost`                          | ❌             | ❌                     | ✅              | ✅                 | ❌              | ❌                 |
| agent `sandbox` tool sets limits             | ❌             | ❌                     | ✅              | ✅                 | ❌              | ❌                 |
| recommendation level                         | local dev      | legacy / compatibility | mainline        | preview            | alpha           | under construction |

Both ❌ rows above are refusals rather than silent downgrades. A mode that cannot enforce the
isolated projection raises `Sandbox '<type>' cannot provide an isolated conversation office` instead
of mounting more than the policy asked for, and a mode that cannot mount vault files raises
`Sandbox type "<type>" does not support vault file mounts` instead of running without the
credential. On the modes that cannot project files, keep vault credentials in `env` only.
