Skip to main content
Mesa uses FUSE to expose Mesa repositories as a POSIX-compliant filesystem. Any tool that works with files — editors, language servers, build systems, agents — can read and write repository contents through normal filesystem operations.
MesaFS can be run as either a POSIX mount or app mount. If you aren’t sure which to use, see Filesystem for an overview and comparison.

Installation

Install the mesa CLI on macOS or Linux:
Re-run the same command at any time to update to the latest version.

General flow

  1. Install Mesa — install the mesa CLI and any platform-specific FUSE dependencies.
  2. Configure and mount — set MESA_API_KEY and MESA_ORG, then run mesa mount or mesa mount --daemonize for background operation.
  3. Work with your reposcd into the mount path (default: ~/.local/share/mesa/mnt/<org>/<repo>) and use any tool — editors, shell commands, agents. File changes are automatically persisted back to Mesa.
Running inside a sandbox (Docker, Daytona, E2B, etc.)? The same flow applies for installing the CLI, setting MESA_API_KEY and MESA_ORG, and mounting. See the Daytona guide or other provider-specific guides.
POSIX mounts can see reads and writes from other mounts on the same change in realtime. See realtime docs for more details.

Platform requirements

macOS

On macOS, the Mesa install script uses Homebrew to install required dependencies. If you don’t have Homebrew yet, install it from brew.sh.

Linux

Mesa uses FUSE3 via libfuse3. Most full Linux distributions include this by default and mesa’s installer installs it for you otherwise.

allow_other and user_allow_other

Mesa mounts with the FUSE allow_other option so that other processes — like your agent, editors, and language servers — can access the mounted filesystem. Without this, only the process that ran mesa mount would be able to read the files. On Linux, this requires user_allow_other to be enabled in /etc/fuse.conf. Uncomment or add the following line:
If this is not set, mesa mount will fail with a permission error.
If your environment runs as root (common in some CI and container setups), allow_other works without this setting. But if you’re running as a non-root user — which is the default in most sandbox providers like Daytona — you’ll need to ensure this is configured.

Docker

Slim and minimal base images strip out system libraries that Mesa needs at runtime. Install them explicitly:
For Debian-based images like node:22-slim or debian:bookworm-slim:
  • ca-certificates — TLS certificate store, required for connections to Mesa’s API.
  • fuse3 — Userspace FUSE library.
  • openssl (and libssl3 on Debian) — OpenSSL shared library, used for TLS.
If you skip these packages on a slim image, connections to Mesa’s API will fail with errors like gRPC TLS configuration failed: transport error.
The same dependencies apply to sandbox environments (Daytona, E2B, etc.) — see provider-specific guides like the Daytona guide for more on setup.

Usage

Browsing your repos

Mesa exposes standard filesystem semantics. You can use regular shell commands — ls, cat, cp, grep, and more — directly against your mounted repos.
You can also open a mounted repo in your IDE. For example, with Cursor:
Mesa mounts every repo your API key can access. To restrict which repos are available, scope the API key.

Editing files in repos

Writes edit the you have checked out — by default, the change the mounted points at — in place, advancing any bookmark pointing at it. See Writing to a Mount for the model and how to work in isolation instead. Every write you perform in mesa that affects your source code will create a new automatically in the background. Mesa respects your .gitignore and will not create commits for files which you have configured as ignored.

Extended attributes

Mesa supports POSIX extended attributes (xattrs) on files and directories inside a mounted repo. Use them to attach lightweight metadata (provenance markers, build labels, agent annotations) without rewriting commits or maintaining a sidecar database. Mesa scopes the writable xattr surface to the user.mesa.* namespace. Names outside that prefix — including the broader user.* (e.g. user.origin) and the kernel-managed security.* / system.* / trusted.* namespaces — are short-circuited at the FUSE layer: writes return EPERM and reads return ENODATA without crossing into mesa’s gRPC backend. This keeps file-heavy workloads (npm install, cp -a, tar --xattrs) from paying a round-trip on every kernel-issued xattr query they trigger. Symlinks cannot carry user.* xattrs — Linux’s kernel restricts that namespace to regular files and directories at the VFS layer, so attempts to lsetxattr a user.* attribute on a symlink return EPERM. Standard POSIX tooling works against the mount:
On macOS, use the xattr CLI (xattr -w user.mesa.origin notion:foo docs/notes.md, xattr -p user.mesa.origin docs/notes.md, etc.). Library callers go through the standard setxattr / getxattr / listxattr / removexattr syscalls and the l*xattr variants for symlinks. Xattrs are sticky: once set, they stay on the path across content edits, and they travel with the path when Mesa records a move_path op. Deleting the path through the mount removes its xattrs. Renames detected only via Git’s content similarity heuristic (no move_path op recorded) drop their xattrs — re-tag the new path if needed.

Limits

The per-attribute cap is exact. The per-path total is bounded by storage rather than by a strict raw-byte count: values are base64-encoded in the backing store, and the storage cap (96 KiB JSONB) translates to roughly 64-72 KiB raw per path depending on how many attributes you set and how long their names are. Linux’s kernel itself doesn’t enforce a strict per-path raw total either — that’s per-filesystem, and Mesa follows suit. Violations surface as standard POSIX errnos: E2BIG (value exceeds 64 KiB — the kernel intercepts oversized syscalls itself; or storage cap reached when adding more attributes to a path), EPERM (name outside the user.mesa.* namespace, or any user.* name on a symlink), ENAMETOOLONG (name length), ENODATA (removing a missing attribute, or any read for a name outside user.mesa.*).

Synthetic xattrs

Mesa exposes a few read-only synthetic attributes on every mounted path: If you set a stored value with the same name, the synthetic wins on read — the stored value is invisible until you remove the synthetic source (which you can’t). The mesa CLI uses user.mesa.org to infer --org from the current working directory, so it’s the load-bearing case.

Reading xattrs through REST or the SDK

The Content API and the TypeScript SDK return xattrs read-only on file and symlink responses — directory listings are unchanged. There is no REST or SDK write surface in v1; all writes go through the mount. Reads at a historical change_id return today’s xattrs for the resolved path, not the values as of that change (xattrs are stored separately from Git history).

Commands

mesa new

Create a new detached from a or ID:
Omitting -m creates the change with no description. Pass -m or --message to set one:
You can also create a new based on an existing one by passing its ID:
New changes are always detached — writes still snapshot the change but do not advance any bookmark. To work on a bookmark where writes advance it, use mesa edit instead.

mesa edit

Switch to a different bookmark:
The filesystem immediately updates to reflect the selected bookmark. Writes will automatically advance the bookmark as you work. You can also resume a previous by ID:
Resuming a change by ID enters detached mode. Any bookmarks that were tracking this change will still advance automatically as you write.
checkout is an alias for edit: mesa checkout main works identically.

mesa bookmark create

Creates a new pointing at the current :
You can also specify which revision the bookmark should point to with -r:
This only creates the bookmark — it does not switch to it. To start working on the new bookmark, follow up with mesa edit:

mesa bookmark list

List all bookmarks for a repository:

mesa log

To look at the log of all your , you can run mesa log. Mesa will display a list of changes, as well as a helpful diagram.

Workflow examples

Making changes on a feature bookmark

Create a feature bookmark and write some files.
Every write through the mount snapshots the change automatically. Because you switched to the bookmark with mesa edit, the bookmark also advances automatically. There is no manual save step, changes are persisted to Mesa as you write.

Browsing and switching between bookmarks

Browse a repo, start a feature bookmark, switch between bookmarks, and resume work.
For the full list of CLI flags and options, see the CLI reference.