--- title: FUSE icon: hard-drive description: Set up FUSE support for MIRAGE in Python. --- ## Prerequisites - Python 3.11+ - [uv](https://docs.astral.sh/uv/) package manager (optional) ## System FUSE Install the OS-level FUSE kernel extension first: - [macOS FUSE Setup](/home/setup/macos), macFUSE + kernel extension + Apple Silicon recovery mode steps. - [Linux FUSE Setup](/home/setup/linux), `fuse3` install and `/etc/fuse.conf`. ## Install Mirage with the FUSE Extra ```bash pip install "mirage-ai[fuse]" ``` Or with uv: ```bash uv add "mirage-ai[fuse]" ``` ## Verify ```python from mirage import Mount, MountMode, Workspace from mirage.resource.ram import RAMResource with Workspace( {"/data": Mount(RAMResource(), mode=MountMode.WRITE, fuse=True)}) as ws: print("mountpoints:", ws.fuse_mountpoints) ``` If the printed path exists under `/tmp/mirage-*`, FUSE is wired up correctly. The `Workspace` constructor blocks until every `fuse` mount is live, so the mountpoint is ready to read as soon as the `with` block is entered, no sleep needed. (In TypeScript, where mounts are async, you `await ws.fuseReady()` instead.) ## Per-mount FUSE FUSE is configured **per mount**. Each mount whose `fuse` is set is exposed at its own mountpoint, showing only that mount's subtree. The value is either `true` (mount at a fresh temp directory) or a path string (mount there, creating the directory if missing): ```yaml mode: WRITE mounts: /data: resource: ram fuse: /tmp/data-repo # explicit path /s3: resource: s3 fuse: true # temp directory /logs: resource: disk # no fuse key, not FUSE-exposed ``` `ws.fuse_mountpoints` returns a `{prefix: path}` map of the live mountpoints. ## Size semantics for API-backed files Some resources (Linear, Trello, Slack, ...) cannot report a file's size without fetching its content, so `stat` returns an unknown size. Over the FUSE mount these files behave like Linux `/proc` files: they stat as **0 bytes until first open**, and become fully readable the moment anything opens them. Mirage mounts with `direct_io` (the kernel reads to EOF regardless of the reported size) and `attr_timeout=0` (post-open `fstat` returns the real size of the now-fetched content, kept warm in a 30-second cache). What that means per tool: | Tools | Behavior | | --- | --- | | `cat`, `grep`, `head`, `cp`, `md5sum`, `sed`, `sort` | correct content, always | | `wc -c`, `tail -c` | correct (they fstat after open, which serves the real size) | | `ls -l`, `du`, `find -size`, `test -s` | report 0 until the file has been opened recently | | `tar`, `rsync`, `scp` | see 0 at stat time and copy empty content, exactly like `tar` over `/proc`; read the file first or use `cat`/`cp` based flows | Mirage never reports a fake size and never fetches content during `stat`: returning real sizes eagerly would fire one API call per file on every `ls -l`. **macOS allows only one in-process FUSE mount.** macFUSE registers a process-global signal source, so a second simultaneous mount in the same process fails with `fuse: cannot register signal source`. Multiple per-mount FUSE mounts work on Linux; on macOS, enable `fuse` on a single mount per workspace (or run additional mounts in separate processes).