/<org>/<repo> paths are not present.
Layouts work with both the app mount and the POSIX mount (mesa mount --layout).
Mounting a layout from the SDK
Declare each repository withrepo(...) and map absolute paths to declarations. This example mounts an application repository at /workspace with two read-only skills repositories nested inside its tree:
mode is required on every declaration and has no default: "rw" allows writes, "ro" rejects them with EROFS. The mount mints a least-privilege access token scoped by name to exactly the layout’s repositories — read-only when every declaration is "ro".
The layout file
A layout serializes to JSON — the formatmesa mount --layout reads. The document is a pure path map: every top-level key is an absolute mount path, and each value is one repository declaration or an array of them. The file never names an organization; the mount that consumes it supplies one (see Organization resolution).
layout.json
layout.toString() in TypeScript, str(layout) in Python.
A path’s value is one declaration or an array, and the two mean different things:
- Single declaration — the repository’s contents appear directly at the path (
/workspace/README.mdismy-app’sREADME.md). - Array — each repository appears in its own child directory under the path, named after the repository;
aliasoverrides the directory name.
Declaration fields
When neither
bookmark nor changeId is set, the mount checks out the repository’s default bookmark.
Structural rules:
- Top-level keys must be absolute (
/-prefixed);subPathskeys must be relative. /itself cannot be a mount path.- Path components cannot be
.or... - A repository can appear only once per layout.
- Two declarations cannot expand to the same path.
Mounting a layout with the CLI
Pass the file tomesa mount:
~/.local/share/mesa/mnt/workspace.
The file is validated while arguments are parsed — a missing file, invalid JSON, or a rule violation fails immediately, before any mount work.
Organization resolution
The layout file never names an organization, so the mount needs exactly one from its context:- The SDK resolves every repository name within the client’s organization.
- The CLI uses the organization
MESA_ORGselects; withoutMESA_ORG, its single configured organization.
MESA_ORGS) and MESA_ORG does not select one, the mount fails with an error pointing at MESA_ORG. Every repository in the layout must belong to that one organization; cross-org layouts are not supported.
Running the mount elsewhere
A common shape: your backend composes the layout and holds the API key, while the mount runs in a sandbox that should only ever see a scoped, short-lived credential.mesa.fs.define bundles a layout with the operations that flow needs — the layout itself serializes to layout.json, and getToken() / get_token() mints the layout’s least-privilege access token.
await definition.mount() in TypeScript, async with definition.mount() as fs: in Python. To mint a token without a definition, call mesa.fs.createToken(layout, { ttl }) / mesa.fs.create_token(layout, ttl=...) directly. The token helpers validate the layout against the structural rules above before minting, so a structurally invalid layout fails at token time with the same error the mount would report. Repository names are not resolved until mount time — a layout naming a nonexistent repository still mints a token and fails when the mount resolves it.
ttl is the token lifetime in seconds. API-key clients default to one hour and allow up to 24 hours; TypeScript private-key clients default to 15 minutes and allow up to four hours. There is no refresh — once the token expires, the mount stops authenticating.
Repository boundaries
Nesting changes where repositories appear, not how they behave. Each declaration stays its own repository with its own history, and the deepest mount owns each subtree:- Writes route to the repository that owns the path: a write under a nested mount lands in the nested repository, never in the repository it sits inside.
- Renames cannot cross repositories —
renameacross a boundary returnsEXDEV. Tools likemvfall back to copy-and-delete, which writes to both repositories. - The directory at a nested mount’s path cannot itself be renamed or removed.
modeis enforced per repository: a read-write repository can nest read-only ones, and only the read-only subtrees reject writes withEROFS.- Intermediate directories a layout introduces (for example
/tools/internalon the way to/tools/internal/cli) are read-only scaffolding.
mesa mount flags, see the CLI reference.
