# Mount syntax

Mounts control which host directories are available inside the container. By default, Moat mounts the workspace directory at `/workspace`. Additional mounts are configured with the `--mount` CLI flag or the `mounts` field in `moat.yaml`.

To persist data across runs, use [volumes](./02-moat-yaml.md#volumes) instead. Volumes are managed by moat and survive container destruction.

## Mount string format

Each mount is a colon-separated string:

```text
<source>:<target>[:<mode>]
```

| Field | Description |
|-------|-------------|
| `source` | Path on the host. Absolute or relative to the workspace directory. |
| `target` | Path inside the container. Must be absolute. |
| `mode` | `ro` (read-only) or `rw` (read-write). Default: `rw`. |

The mode field is optional. When omitted, the mount is read-write.

### Examples

| Mount string | Source | Target | Mode |
|--------------|--------|--------|------|
| `./data:/data` | `./data` (relative) | `/data` | read-write |
| `./data:/data:ro` | `./data` (relative) | `/data` | read-only |
| `/host/path:/container/path` | `/host/path` (absolute) | `/container/path` | read-write |
| `./cache:/cache:rw` | `./cache` (relative) | `/cache` | read-write |

## Object form

For advanced configuration like directory exclusion, use the object form:

| Field | Type | Required | Default | Description |
|-------|------|----------|---------|-------------|
| `source` | `string` | yes | | Host path. Absolute or relative to the workspace directory. |
| `target` | `string` | yes | | Container path. Must be absolute. |
| `mode` | `string` | no | `rw` | `ro` (read-only) or `rw` (read-write). |
| `exclude` | `[]string` | no | `[]` | Paths relative to `target` to overlay with tmpfs. |

String and object forms can be mixed in the same `mounts` array.

## CLI usage

The `--mount` flag adds mounts from the command line. It is repeatable. CLI mounts are combined with any mounts defined in `moat.yaml`. Duplicate targets are rejected.

```bash
# Mount a directory read-only
moat run --mount ./data:/data:ro ./my-project

# Mount multiple directories
moat run --mount ./configs:/app/configs:ro --mount /tmp/output:/output:rw ./my-project

# Combine with other flags
moat run --grant github --mount ./data:/data:ro ./my-project
```

If a `--mount` targets `/workspace`, it replaces the automatic workspace mount. The workspace directory will not be available unless you mount it explicitly.

## moat.yaml usage

The `mounts` field accepts a list of mount strings, objects, or both.

```yaml
mounts:
  - ./data:/data:ro
  - /host/path:/container/path:rw
  - source: .
    target: /workspace
    exclude:
      - node_modules
```

CLI `--mount` flags are additive with `moat.yaml` `mounts`. Both sources are combined at runtime.

## Default workspace mount

Moat always mounts the workspace directory at `/workspace` as read-write. This mount is added automatically and does not need to be specified.

```bash
$ moat run ./my-project -- pwd
/workspace

$ moat run ./my-project -- ls
moat.yaml
src/
package.json
```

The workspace path is resolved to an absolute path on the host before mounting. Changes the agent makes in `/workspace` are written directly to the host filesystem and persist after the run completes.

To add excludes to the workspace mount, declare it explicitly with the object form. This replaces the automatic mount:

```yaml
mounts:
  - source: .
    target: /workspace
    exclude:
      - node_modules
```

## Path resolution

Relative `source` paths are resolved against the workspace directory. The `target` path must be absolute.

| Source in mount string | Resolved host path (workspace: `/home/user/my-project`) |
|------------------------|-------------------|
| `./data` | `/home/user/my-project/data` |
| `../shared` | `/home/user/shared` |
| `/opt/datasets` | `/opt/datasets` |

## Access modes

| Mode | Behavior |
|------|----------|
| `rw` | Container reads and writes to the mounted directory. Changes are reflected on the host. |
| `ro` | Container reads from the mounted directory. Write attempts fail. |

`rw` is the default when no mode is specified.

## Excluding directories

Excluded directories are overlaid with tmpfs (in-memory) mounts inside the container. The host files at those paths are hidden, and the container sees an empty directory. Files written to excluded paths live in memory and do not touch the host filesystem. Each tmpfs mount defaults to 50% of system RAM (Docker's default). On machines with many excludes or large dependency trees, monitor memory usage.

This is useful for large dependency trees (`node_modules`, `.venv`, `vendor/`) that cause performance problems with shared filesystem mounts -- particularly VirtioFS on Apple Containers, where open file handles accumulate over time.

```yaml
mounts:
  - source: .
    target: /workspace
    exclude:
      - node_modules
      - .venv
```

Since excluded directories start empty, install dependencies inside the container. Use a `pre_run` hook:

```yaml
hooks:
  pre_run: npm install

mounts:
  - source: .
    target: /workspace
    exclude:
      - node_modules
```

On Docker, tmpfs overlays are always writable, even when the parent mount is read-only. This allows installing dependencies on tmpfs while keeping source files read-only. On Apple Containers, this behavior has not been verified -- test with your setup if combining read-only mounts with excludes.

Excludes are only available in `moat.yaml` (object form). The `--mount` CLI flag uses the string format and does not support excludes.

## Runtime differences

Both Docker and Apple containers support directory mounts with read-only and read-write modes. The mount syntax is identical across runtimes.

One difference: Apple containers only support directory mounts, not individual file mounts. Moat handles this internally (for example, mounting a directory containing a CA certificate rather than the certificate file directly). If a mount source is a file, Moat mounts the containing directory instead.

## Global mounts

Global mounts are personal mounts that apply to every run. Configure them in `~/.moat/config.yaml`:

```yaml
mounts:
  - source: ~/.moat/scripts/statusline.sh
    target: /home/user/.claude/moat/statusline.sh
```

Global mounts use the same syntax as `moat.yaml` mounts (both string and object forms) with these constraints:

- **Source paths must be absolute** (or use `~` for home directory). There is no workspace to resolve relative paths against.
- **Always read-only.** Moat enforces read-only mode on global mounts regardless of the `mode` field.
- **Excludes are not supported.**

Global mounts are appended after project mounts and before volumes.

## Related pages

- [CLI reference](/moat/reference/cli) -- `moat run` flags including `--mount`
- [moat.yaml reference](/moat/reference/moat-yaml) -- `mounts` field, `volumes` field, and all configuration options
- [Recipes](/moat/guides/recipes) -- Complete project examples using volumes and excludes for dependency caching
- [Sandboxing](/moat/concepts/sandboxing) -- Workspace mounting and filesystem isolation
- [Security model](/moat/concepts/security) -- Trust boundaries and defense in depth

---
[← Moat documentation index](https://majorcontext.com/moat/llms.txt)
