> ## Documentation Index
> Fetch the complete documentation index at: https://docs.mesa.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Realtime

> Realtime collaboration in MesaFS

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 POSIX mounts and app mounts. When using an app 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 [usage patterns](/content/usage-patterns/overview)).
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 POSIX mount.
* A human looks at the same files using an editor in the browser. The human's reads and writes go through a MesaFS app 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](https://github.com/mesa-dot-dev/examples/tree/main/realtime-nextjs) 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:

```text theme={null}
<<<<<<< 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

1. Mount MesaFS
2. Call `fs.subscribe(...)` with a callback to start being notified of modifications from other writers
3. Call `unsubscribe()` on the subscription handle to stop being notified

<CodeGroup>
  ```typescript TypeScript theme={null}
  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",
  });

  // 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();
  ```

  ```python Python theme={null}
  import os
  from mesa_sdk import Mesa, RepoConfig

  mesa = Mesa(api_key=os.environ["MESA_API_KEY"], org="acme")

  async with mesa.fs.mount(
      repos=[RepoConfig(name="app", bookmark="main")],
      mode="rw",
  ) as fs:
      # Reads see remote edits on this change within seconds.
      print((await fs.read("/acme/app/README.md")).decode())

      # Subscribe only if your app needs an event stream for refresh/rerender logic.
      async def on_change(event):
          print("changed:", event.path)

          if not event.recursive and event.path.endswith(".md"):
              content = await fs.read(event.path)
              print(content.decode())

      subscription = fs.subscribe(on_change)

      # Keep your application running here.

      await subscription.unsubscribe()
  ```
</CodeGroup>

<Tip>
  The boundary for realtime reads and writes is the active change, not the repository as a whole.
  Mounts of the same bookmark are already on the same change, so they collaborate by default;
  use `fs.change.edit(...)` or `fs.change.new(...)` to move a mount into a different room.
</Tip>

### 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. |
