MesaFS reads and writes are realtime by default.
The realtime “room” is a change. Any active MesaFS mount on the same change can see edits made by another active mount on that change, even when those mounts are running on different hosts.
Realtime works across both CLI and application mounts. When using the application mount, you also have the option to subscribe to file-change events with fs.subscribe(...).
Use cases
With Mesa, realtime collaboration is usually treated as a complement, not a replacement, for branch-based collaboration.
In most cases, you should still create a new change + bookmark per session (see best practices).
However, realtime within the context of a change enables enables a couple of use cases:
Human-to-agent collaboration
The most common use case for realtime is a human watching the work of a cloud agent:
- An agent running in a sandbox edits files through a FUSE-based MesaFS mount.
- A human looks at the same files using an editor in the browser. The human’s reads and writes go a MesaFS application mount running in a multi-tenant backend.
- The backend is notified of file change events via
fs.subscribe(...) and tells the browser to reload the changed files.
The Realtime Next.js example shows this pattern with an in-browser editor, an SSE event stream, and Claude Code running in a Daytona sandbox.
Agent-to-agent collaboration
Another case is when you have multiple agents that want to know about each other’s changes and don’t need isolated timelines.
For example, you might have one agent that updates memories & skills while another one works on core artifacts (ex. application code, documents).
Conflict semantics
Realtime is smarter than a simple last-write-wins layer. When racing edits (i.e. edits within the same second) conflict, MesaFS keeps both sides.
The conflicted file reads back with JJ-style conflict markers instead of silently choosing one writer’s content:
<<<<<<< conflict 1 of 1
++++++ side #1
content from one writer
------- base
previous content
++++++ side #2
content from another writer
>>>>>>> conflict 1 of 1 ends
Resolve the conflict by simply editing the file again.
Subscribing to events
The subscription API, fs.subscribe(...), is only needed when your application wants an event stream that says which files changed.
The callback provided to subscribe runs after the changed state is visible through that filesystem handle.
For example, a web app might subscribe so it knows when to rerender the frontend with fresh data.
Basic Flow
- Mount MesaFS
- Use
fs.change.edit to specify the change you want to make edits at
- Call
fs.subscribe(...) with a callback to start being notified of modifications from other writers
- Call
unsubscribe() on the subscription handle to stop being notified
import { Mesa } from "@mesadev/sdk";
const mesa = new Mesa({ apiKey: process.env.MESA_API_KEY, org: "acme" });
const fs = await mesa.fs.mount({
repos: [{ name: "app", bookmark: "main" }],
mode: "rw",
});
await fs.change.edit({ repo: "app", bookmark: "main" });
// Reads see remote edits on this change within seconds.
console.log(await fs.readFile("/acme/app/README.md", "utf8"));
// Subscribe only if your app needs an event stream for refresh/rerender logic.
const subscription = fs.subscribe(async (event) => {
console.log("modified: ", event.path, event.recursive);
});
// Later, when the session ends:
subscription.unsubscribe();
The boundary for realtime reads and writes is the active change, not the repository as a whole.
To collaborate on main, explicitly switch to the change with
fs.change.edit({ repo: "app", bookmark: "main" }) before modifying files or subscribing to events.
Event shape
Each event contains the changed path and whether the invalidation applies recursively.
| Field | Type | Description |
|---|
path | string | Absolute MesaFS path, such as /acme/app/src/index.ts. |
recursive | boolean | true when descendants of path may have changed. Refresh the directory or subtree instead of only one file. |