docs/fuse-compat.md

FUSE Compatibility

Sandbox and container runtime matrix for Linux FUSE support.

Markdown

agent-fs mount exposes drives as a Linux FUSE filesystem. FUSE requires /dev/fuse and the SYS_ADMIN capability inside the container. Not every agent sandbox grants those, so this page documents what works, what doesn't, and the exact incantation per runtime.

Universal fallback: the CLI / MCP / HTTP API paths are always available. If FUSE is blocked in your sandbox, fall back to agent-fs write, agent-fs cat, agent-fs grep, etc.

TL;DR matrix

RuntimeFUSE works?Minimal incantationFallback
Docker rootfulYesdocker run --cap-add SYS_ADMIN --device /dev/fuse --security-opt apparmor=unconfined ...n/a
Podman rootfulYesSame as Docker rootful (--cap-add SYS_ADMIN --device /dev/fuse)n/a
Podman rootlessConditionalRun as UID-0 inside the userns; --privileged alone is insufficient (podman#13449)CLI / MCP
Kubernetes — privileged PSSYessecurityContext: { privileged: true } or capabilities.add: [SYS_ADMIN] + /dev/fuse devicen/a
Kubernetes — baseline PSSConditionalExplicitly capabilities.add: [SYS_ADMIN] + device-plugin / hostPath for /dev/fuseCLI / MCP
Kubernetes — restricted PSSNo (use CSI sidecar)See GCS FUSE CSI driver pattern — privileged init opens /dev/fuse, hands FD to unprivileged sidecarCLI / MCP via init container
GKE AutopilotNo (managed only)Cluster-managed FUSE only via Google's CSI driver — users can't mount arbitrary FUSE FSesCLI / MCP
Cloudflare ContainersYes (since 2025-11)Install FUSE binary in image, mount at startup; platform exposes /dev/fusen/a
Apple Container (macOS)YesEach container is a full Linux VM — FUSE behaves like any in-guest Linux mountn/a
E2B sandboxesYesFirecracker with CONFIG_FUSE_FS=y. e2b connect-bucket auto-installs FUSE helpersn/a
Kata ContainersYesvirtio-fs default + in-guest FUSE works when SYS_ADMIN grantedn/a
gVisor (runsc)NoSentry has stub FUSE only (#2752, #2753) — affects GKE Sandbox, Cloud Run gen1CLI / MCP
GitHub Codespaces (hosted)NoHosted env ignores --device in devcontainer config (community#163129)CLI / MCP
Modal sandboxesNoModal uses FUSE internally; user code has no /dev/fuse accessCLI / MCP
Fly.io Machines (Firecracker)NoDefault Fly kernel does not have CONFIG_FUSE_FS=y (community#649)CLI / MCP

Last checked: 2026-05. Sandboxes change quickly — file an issue if you hit a fresh blocker.

---

Per-runtime incantations

Docker rootful (the canonical case)

bash
docker run -d \
--name agent-fs-runner \
--cap-add SYS_ADMIN \
--device /dev/fuse \
--security-opt apparmor=unconfined \
-v "$PWD":/work \
-w /work \
ubuntu:24.04 \
tail -f /dev/null
# Inside the container:
docker exec -it agent-fs-runner bash
apt-get update && apt-get install -y fuse3
# install agent-fs (Linux x64): bun install -g @desplega.ai/agent-fs
agent-fs daemon start
agent-fs mount /mnt/agent-fs

Gotchas

  • --security-opt apparmor=unconfined is required on Ubuntu hosts because the default AppArmor profile blocks /dev/fuse access for containerised processes. On Docker Desktop (Darwin) it's harmless.
  • --cap-add MKNOD is sometimes also recommended; in practice SYS_ADMIN covers it.

Podman rootful

Identical to Docker. Use --security-opt label=disable instead of AppArmor when SELinux is the host MAC system.

Podman rootless

You must be root *inside the userns* for SYS_ADMIN to actually grant FUSE. --privileged is not enough (podman#13449). If you're using Podman rootless, prefer the CLI / MCP fallback.

Kubernetes — privileged

yaml
apiVersion: v1
kind: Pod
metadata:
name: agent-fs
spec:
containers:
- name: agent
image: my-agent-image:latest
securityContext:
privileged: true # OR capabilities: { add: [SYS_ADMIN] }
volumeMounts:
- name: fuse-device
mountPath: /dev/fuse
volumes:
- name: fuse-device
hostPath:
path: /dev/fuse
type: CharDevice

Kubernetes — baseline PSS

yaml
securityContext:
capabilities:
add: [SYS_ADMIN]

Plus a device plugin or hostPath for /dev/fuse. The pod will be admitted under the baseline Pod Security Standard but rejected under restricted.

Kubernetes — restricted PSS

Direct FUSE mounts are not possible. The supported pattern is the GCS FUSE CSI driver / meta-fuse-csi-plugin shape:

  1. A privileged CSI node-driver opens /dev/fuse and hands the FD to an unprivileged sidecar.
  2. The sidecar runs the FUSE daemon (our Rust helper, in a future v1.x adapter).
  3. The workload pod mounts the FUSE FS as a volume — no caps needed.

Status for agent-fs: v1 does not ship a CSI adapter. Tracked as a v1.x deliverable in the plan appendix.

Cloudflare Containers

Native FUSE support since 2025-11-21. Install the FUSE helper in your Dockerfile and mount at startup; the platform handles the device. See the r2-fuse-mount example.

Apple Container (macOS)

Each container is a full Linux VM (WWDC 2025 announcement). FUSE works in-guest like any Linux VM. macFUSE 5.1.0 / fuse-t are host-side concerns and do not affect in-guest behavior.

E2B

First-class FUSE — Firecracker kernel ships CONFIG_FUSE_FS=y. Use e2b.dev directly, or install agent-fs and run agent-fs mount like any Linux host. The E2B connect-bucket API auto-installs s3fs/gcsfuse/R2 helpers; ours is direct.

Kata Containers

virtio-fs is the default sharing mechanism since Kata 2.0; in-guest FUSE also works when SYS_ADMIN is granted. See kata-containers virtio-fs guide.

---

Where FUSE is blocked

gVisor (runsc)

Practical status: broken for our use case. The gVisor sentry has a stub FUSE client only — #2752 and #2753 have been open since 2020. The "Setting up FUSE" boot message is internal scaffolding, not user-mountable. Affects:

  • GKE Sandbox (workloads with runtimeClassName: gvisor)
  • Cloud Run gen1
  • Several agent platforms that use gVisor for tenant isolation

Use the CLI / MCP path instead.

GitHub Codespaces (hosted)

Codespaces ignores devcontainer mounts / runArgs for --device in the hosted environment. See community#163129. Local VS Code Dev Containers can pass --device /dev/fuse fine.

Modal uses FUSE internally for its lazy-loading image filesystem, but user code has no privileges to interact with /dev/fuse. No public path to mount user FUSE FSes.

Fly.io Machines

Default Fly kernel does not have CONFIG_FUSE_FS=y. LiteFS works because Fly ships LiteFS-specific kernel support. See community#649. Practical conclusion: agent-fs FUSE won't run on Fly Machines without Fly-side changes.

---

See also