close
Skip to main content
In this quickstart, you will create a repo, read and write files with MesaFS, and experiment with versioning. The goal is to show the primitives Mesa provides that can be used for any of your agent workflows.
1

Sign up and create an API key

  1. Create an account at app.mesa.dev.
  2. Create an organization for your product (example: acme).
  3. Generate an API key with admin scope.
Store the key as an environment variable:
export MESA_API_KEY="mesa_..."
API keys are only shown once. Save them in your secrets manager before leaving the dashboard.
See Authentication for key management and scope details.
2

Install the SDK or CLI

npm install @mesadev/sdk
Using MesaFS through the CLI requires FUSE which is not a straightforward process on macOS (yet). If testing with the CLI we recommend using a FUSE-enabled sandbox. See Sandboxes for more.
3

Create a repo

In Mesa, you start by creating a special kind of folder called a repository. Each repository has its own version history and permissions.Repositories are free to create. Use them liberally to isolate resources that belong to different customers or projects.
import { Mesa } from "@mesadev/sdk";

const mesa = new Mesa({ apiKey: process.env.MESA_API_KEY, org: "acme" });

const repo = await mesa.repos.create({ name: "my-project" });
To retrieve an existing repo later:
const repo = await mesa.repos.get({ repo: "my-project" });
4

Read and write your first files

Once created, the easiest way to read and write to a repository is by mounting MesaFS, either through our SDKs or through a FUSE mount with our CLI.
import { Mesa } from "@mesadev/sdk";

const mesa = new Mesa({ apiKey: process.env.MESA_API_KEY, org: "acme" });
const repo = await mesa.repos.create({ name: "my-project" });

// Open the repository locally as a virtual filesystem
const fs = await mesa.fs.mount({
  repos: [{ name: repo.name, bookmark: "main" }],
});

// Use explicit filesystem operations
await fs.mkdir("/acme/my-project/memories", { recursive: true });
await fs.writeFile("/acme/my-project/memories/run-1.md", "Hello, world!");
const content = await fs.readFile("/acme/my-project/memories/run-1.md", "utf8");

// Or use the emulated bash environment
const { stdout } = await fs.bash({ cwd: "/acme/my-project" }).exec("echo memories/run-1.md");
5

Experiment with versioning

A repository is a directed acyclic graph of Changes: snapshots of the repository at that point in time. See more in Versioning.Every file write is part of specific change. Your first change is created automatically when you mount an empty repo in MesaFS. All subsequent changes must be explicitly created.
// The first Change that holds our previous writes
const firstChange = await fs.change.current({ repo: "my-project" });

// Create a new Change on top of the first
await fs.change.new({ repo: "my-project", changeId: firstChange.changeId });

// All writes go to the new change
await fs.bash({ cwd: "/acme/my-project" }).exec('echo "Hello, Mesa!" > memories/run-1.md');
const secondChange = await fs.change.current({ repo: "my-project" });
You can easily roll back to a previous version by switching to an old Change.
// Roll back to the first change
await fs.change.edit({ repo: "my-project", changeId: firstChange.changeId });
const original = await fs.readFile("/acme/my-project/memories/run-1.md", "utf8");
console.log("Content:", original); // "Hello, world!"

// Continue with the new change
await fs.change.edit({ repo: "my-project", changeId: secondChange.changeId });
const updated = await fs.readFile("/acme/my-project/memories/run-1.md", "utf8");
console.log("Content:", updated); // "Hello, Mesa!"
6

Diff two changes

Now you have two changes in your repo.You can imagine having many different changes, each representing the concurrent work of a different agent. Once an agent is done working, you may want to show a UI for users to review the changes and approve or reject them.
const diffResult = await mesa.diffs.get({
  repo: repo.name,
  base_change_id: firstChange.changeId,
  head_change_id: secondChange.changeId,
});

diffResult.entries.forEach((entry) => {
  // render file diff
});
7

Bookmark changes

By default, changes have random, alphanumeric identifiers. However, you will often want to assign a human-readable name to a change. You can do this with bookmarks. By default, the first change on a repo is bookmarked main.
await mesa.bookmarks.create({
  repo: repo.name,
  name: "my-feature",
  change_id: secondChange.changeId,
});
8

Merge two changes

You will eventually have lots of different changes and bookmarks and you’ll want to merge the changes from one bookmark into another.Merge your source bookmark (my-feature) into your target bookmark (main). This process creates a new Change on top of main that contains the merged changes and moves the main bookmark to the new Change.
const mergedChange = await mesa.bookmarks.merge({
  repo: repo.name,
  target: "main",
  source: "my-feature",
});

console.log("Merged Change:", mergedChange.change_id);
Now you have 3 changes in your repo.Conventionally, the main bookmark points to the canonical version of your documents, and other bookmarks represent “draft” work. A typical pattern is rendering diff UI for human-in-the-loop approvals, then merging approved changes into your main line of Change history.
You’re now ready to start building complex agent workflows with Mesa.

Next steps