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

# Python SDK Changelog

> Release history for the Python SDK.

All notable changes to this project will be documented in this file.

The format is based on [Common Changelog](https://common-changelog.org/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## \[0.47.1] - 2026-08-16

### Fixed

* Fix slow `mount()` initialization for layouts that specify a checked-out revision with `at`

## \[0.47.0] - 2026-08-14

### Changed

* **Breaking:** Change the app-mount Bash default working directory from `/home/user` to `/`

## \[0.46.0] - 2026-08-13

### Changed

* **Breaking:** Replace the `mesa.fs.mount(repos=...)` mount syntax with the new FS definition syntax: `mesa.fs(layout=...).mount(...)`
* **Breaking:** Change `repo()` to select a checkout revision with the `at` field instead of `bookmark` / `change_id`

### Added

* Add `branched_from` to `repo()` to fork a new change the first time the mount opens the repo

### Removed

* **Breaking:** Removed the async `mesa.resolve_org()` method. The organization slug is now available synchronously via `mesa.org.slug`.
* **Breaking:** Remove `org` from the Python SDK constructor and resource methods; the SDK derives the organization from the credential
* **Breaking:** Remove `vcs_url` option from the client configuration
* **Breaking:** Replace all singular `author` options with a plural `authors`

### Fixed

* Fix `repo()` `at` pins being overridden when the organization's configuration forks the repo on open
* Fix layout `repo()` silently dropping unrecognized keys in `at`, `branched_from`. The SDK now raises instead of pinning the wrong revision
* Fix layout `repo()` silently accepting an invalid fully-qualified `"org/repo"` name; a repo name containing `/` now raises

## \[0.45.0] - 2026-08-11

### Changed

* Point package source and issue links to the public SDK repository
* **Breaking:** Remove top-level `RepoConfig.bookmark`, `RepoConfig.change_id`, and `RepoConfig.read_only`. Use `at` and `mode` instead
* **Breaking:** `RepoConfig.mode` is now a `MountMode` enum (`MountMode.rw` / `MountMode.ro`); the strings `"rw"` / `"ro"` remain accepted. The public `MountMode` name is this enum (layout JSON still uses `"ro"` / `"rw"` string literals)
* **Breaking:** Resolve `fs.changes.new(..., bookmark=...)` (and `edit` / mount `at={"bookmark": ...}`) strictly against `refs/heads/<name>`. A string that is not a bookmark no longer falls through server-side revspec resolution to a change id; pass `change_id` to fork from a change

### Added

* Add mount `RepoConfig` fields `mode`, `at`, and `branched_from` to open an existing revision or fork a new revision at mount time (create change → optional `as.bookmark` → publish checkout; omit `as.bookmark` for an anonymous tip)

### Removed

* **Breaking:** Remove API-key authentication from the SDK, including `api_key`, `MESA_API_KEY`, legacy HS256 token minting, and `MissingApiKeyError`; use `private_key` or `auth["access_token"]` instead

## \[0.44.1] - 2026-08-09

### Changed

* Split native filesystem write batches to the server-advertised VCS operation and message-size limits

## \[0.44.0] - 2026-08-07

### Changed

* Resolve the organization for `auth["access_token"]` locally from its JWT issuer and reject opaque or malformed tokens instead of making an implicit `/whoami` request

### Added

* Add custom mount layouts, created by calling `mesa.fs(layout=..., ttl=...)`
* Add `token()` and `layout()` on the FS mount definition for serializing a token and layout file that can be passed into a sandbox
* Add `await fs.changes.checkpoint(repo, message=None)` to flush pending writes (serializing concurrent writes and tree mutations in the same repo), optionally describe the current change, create a new descendant change, and advance bookmarks onto that descendant (requires the checkout to already be on a bookmark). Concurrent bookmark-tip races raise a retryable conflict (distinct from not-on-a-bookmark and from a half-applied checkout failure). Omit `message` to preserve the existing description; pass `message=""` to clear it; any other string overwrites. Returns `CheckpointResult` with `saved_change_oid` (saved change) and `active_change_oid` (now-active empty descendant)
* Add private-key authentication and local Ed25519 token signing. Token minting, commit-producing REST operations, and MesaFS mounts require operation-level ordered authors; non-authoring REST credentials remain authorless

## \[0.43.0] - 2026-08-02

### Changed

* **Breaking:** Require REST bookmark moves to advance history unless `allow_backwards` is set
* **Breaking:** Require native filesystem bookmark moves to advance history by default and add an `allow_backwards` override

### Added

* Add repository ID restrictions to locally signed access tokens with `mesa.tokens.create(repo_ids=[...])`

## \[0.39.0] - 2026-07-08

### Added

* Add structured tag filter dictionaries to `mesa.repos.list()`, with `$`-prefixed case-insensitive operators (`$and`, `$or`, `$not`, `$eq`, `$in`, `$contains`, `$starts_with`, `$ends_with`, `$exists`) and case-insensitive tag matching

### Deprecated

* Deprecate legacy comma-separated repo tag filters in favor of structured tag filter dictionaries

## \[0.38.0] - 2026-06-22

### Fixed

* Fix files written through the SDK transiently disappearing during bursts of writes

## \[0.37.0] - 2026-06-17

### Fixed

* Repeated filesystem operations on the same repository are now dramatically faster

## \[0.36.0] - 2026-06-09

### Added

* Add `mesa.tokens.create(...)` to sign a self-expiring access token (JWT) locally from an API key, scoped to a subset of the key's scopes and to repositories by full `org/repo` name. Signing is local with no network call; a `ttl_seconds` outside 1 second to 24 hours raises `InvalidOptionsError`
* Add a `ttl` option to `mesa.fs.mount()` to set how long the mount lasts, in seconds (default 3600, max 86400). The mount signs one access token for that lifetime and expires with it
* Add `MissingCredentialError` as the preferred name for the error raised when no API key is provided (directly or via `MESA_API_KEY`)

### Changed

* `mesa.fs.mount()` now signs a short-lived access token locally from your API key instead of creating an ephemeral API key on the server. Repos are scoped by full `org/repo` name so signing needs no network round-trip, no server-side credential is created or left behind, and the mount expires on its own when the token does

### Deprecated

* Deprecate `MissingApiKeyError` in favor of `MissingCredentialError`. The old name is retained as an alias of the same class, so `except MissingApiKeyError` keeps working

## \[0.34.0] - 2026-06-01

### Added

* Changes in Mesa are now realtime by default. Concurrent editors mounted on the same change will see one another's modifications within a few seconds.
* Add `MesaFileSystem.subscribe(handler)` for filesystem invalidation callbacks across mounted changes. Call `unsubscribe()` on the returned subscription to stop.

### Removed

* Remove the experimental `multiplayer` filesystem APIs.

## \[0.33.0] - 2026-05-26

### Added

* Add `read_only` to `RepoConfig`. Pass `RepoConfig(name="my-repo", read_only=True)` to `fs.mount(...)` and the mesa daemon rejects writes to that repo with an `OSError` whose `errno` is `errno.EROFS`, so a single mount can carry a mix of writable and read-only repos.
* Add `type` aliases and `is_file()`, `is_dir()`, and `is_symlink()` helpers to generated content response models

### Changed

* Change responses now report parent change IDs instead of commit SHAs of prior versions of the same change.

### Removed

* **Breaking:** Remove the mount-wide `mode` parameter from `fs.mount(...)` and `MesaConfig`. Set `read_only` on each `RepoConfig` instead. The minted API key always carries `read` and `write` scopes; read-only enforcement is performed client-side by the mesa daemon

## \[0.32.0] - 2026-05-22

### Added

* Add `multiplayer.watch()` for async-iterator multiplayer event streaming. Returns a `MultiplayerEventStream` usable as an async context manager; yields `RemoteChangeEvent` (with `generation`) and `PeersChangedEvent` (with `count`).
* Add `multiplayer.on()` for callback-based multiplayer event streaming. Accepts a sync or async callback; returns an unsubscribe callable.

## \[0.31.0] - 2026-05-21

### Added

* Add `set_metadata` / `get_metadata` / `clear_metadata` on `MesaFileSystem` for per-file metadata as plain key/value pairs. `set_metadata` merges per key; passing `None` or an empty string as a value deletes that key, so one call can mix sets and deletes. `get_metadata` returns all keys including the read-only `org`/`repo`. `clear_metadata` removes every key on a path. Naming a reserved key raises `ValueError`.

### Changed

* **Breaking:** Rename the `mesa.content.get(...)` metadata surface from `xattrs` to `metadata`. Responses now expose optional `metadata` instead of `xattrs`, and directory listings filter via `metadata` key/value pairs instead of `xattr` pairs.

## \[0.30.0] - 2026-05-19

### Added

* Add `mesa.webhooks.on(...)` and `mesa.webhooks.receive(...)` for verifying and dispatching inbound Mesa webhooks
* Add `fs.bookmarks.move(repo, name, change_id=...)` for moving bookmarks from a mounted filesystem
* `mesa.content.get(...)` responses now expose optional `xattrs` metadata for files, symlinks, directories, and directory entries when present.
* Add `message` support to `fs.changes.new(...)` for setting the description of a newly created mounted-filesystem change

### Changed

* `mesa.changes.create(...)` and `mesa.changes.patch(...)` now accept empty string descriptions. Pass `None` to omit the field; pass `""` to create or update a change with no description.
* `mesa.bookmarks.merge(...)` now accepts `message`; pass `None` to use the generated merge description, or pass `""` to create the merge with no description.

## \[0.29.3] - 2026-05-18

### Fixed

* Make every `mesa.fs` write durable before the operation returns

## \[0.29.2] - 2026-05-17

### Added

* Add `mesa.bookmarks.get(repo=..., bookmark=...)` for direct bookmark lookup by name, and add `glob` filtering to `mesa.bookmarks.list(repo=..., glob=...)`
* Add optional `ref_globs` filters to `mesa.repos.sync_upstream(...)`: omit it to sync all supported branches and tags, or pass branch/tag glob strings such as `{"branches": "main"}`

### Fixed

* Fix `mesa.fs.mount()` dropping recently written file bytes by flushing pending mount writes before revoking the scoped API key

## \[0.29.0] - 2026-05-15

### Added

* Add `VIRTUAL_ROOT_CHANGE_ID` export for referencing the virtual-root sentinel change id from `mesa_sdk`
* Add `mesa.repos.sync_upstream(repo=..., direction=...)` to enqueue a sync with a repository's configured upstream. Returns the `sync` row; the worker processes it asynchronously. Read `repo.upstream.latest_sync`, call `mesa.repos.get_upstream_sync(repo=..., sync_id=...)`, list `mesa.repos.list_upstream_syncs(repo=...)`, or subscribe to `sync.{queued,in_progress,completed,failed}` webhooks
* Add `mesa.repos.get_upstream_sync(repo=..., sync_id=...)` and `mesa.repos.list_upstream_syncs(repo=...)` for reading repository upstream sync history
* `mesa.repos.create()` and `mesa.repos.update()` accept `upstream=UpstreamConfig(url=..., auth=...)` to set or replace the upstream remote inline. On `update()`, pass `upstream=None` to remove the upstream entirely, or omit the argument to leave it unchanged. Repository responses include the upstream configuration with `latest_sync`; secrets are never returned
* `UpstreamConfig.auth` is tri-state, mirroring the REST surface: default `UNSET` (on `update()` leaves any stored credential untouched; on `create()` produces a public upstream); `None` explicitly clears the stored credential; a `TokenAuth` or `UsernamePasswordAuth` sets or replaces it. Individual fields inside the auth object (`token`, `password`, `username`, `token_username`) are atomic and must be sent in full
* New public types in `mesa_sdk.types`: `UpstreamConfig`, `UsernamePasswordAuth`, `TokenAuth`, and the `UpstreamAuth` union

### Changed

* Resolving the default bookmark of a freshly created (never-written-to) repo continues to return the virtual root sentinel `change_id`. The server-side lazy-seed behavior is transparent to SDK consumers — the first write through any path advances the bookmark to a real change ([MES-1387](https://linear.app/mesa-dev/issue/MES-1387))

### Removed

* **Breaking:** Remove the public `mesa.raw` generated REST client attribute; use `mesa-rest` directly for low-level REST access

## \[0.28.2] - 2026-05-07

### Added

* Add `fs.changes.current(repo)` to query the currently active change on a mounted repo. Returns `ChangeInfo` with `change_id` and `commit_oid`.

## \[0.28.1] - 2026-05-06

### Changed

* Coordinate `MesaFileSystem` cache budgets across instances in a single process;
  `disk_cache.max_size_bytes=None` now auto-sizes against system resources instead of being unbounded

### Fixed

* Fix segfault on process exit caused by crash handler outliving the Python interpreter. The native extension now uninstalls the crash handler via `atexit` before teardown.
* Fix `rg` and other tools that resolve `/..` by clamping `resolve_path` at the filesystem root.

## \[0.28.0] - 2026-05-03

### Added

* Added support for conflicts in the FS interfaces. Conflicting files render `jj`-style conflict
  semantics.

### Fixed

* Raise `ConflictError` instead of a generic API error on concurrent bookmark writes.
* Fixed race condition in cache deallocation causing crashes on binding destruction.

## \[0.27.0] - 2026-04-30

### Changed

* Replace pure-Python wheel with platform-specific wheels containing a native
  extension (manylinux, musllinux, macOS arm64). Python 3.10+ required.
* Filesystem errors use Python's built-in exception hierarchy
  (`FileNotFoundError`, `IsADirectoryError`, `PermissionError`, etc.) instead of
  `MesaError` subclasses.

### Added

* Add `mesa.fs.mount()` async context manager for mounting repos as a virtual
  filesystem. Automatically mints a scoped API key on entry and revokes it on
  exit (with a 1-hour server-side TTL fallback).
* Add `MesaFileSystem` python interface with full async file I/O: `read`,
  `write`, `append`, `exists`, `stat`, `lstat`, `readdir`, `mkdir`, `rm`, `cp`,
  `mv`, `chmod`, `symlink`, `readlink`, `realpath`, and `utimes`.
* Add `fs.changes` namespace for change management on a mounted filesystem:
  `new`, `edit`, and `list`.
* Add `fs.bookmarks` namespace for bookmark management on a mounted filesystem:
  `create` and `list`.
* Add `Bash` class for running shell commands against a mounted filesystem via
  `fs.bash()`. Supports `env`, `cwd`, and `timeout_ms`.

## \[0.26.0] - 2026-04-29

### Fixed

* Fix repo list cache not being exercised through the SDK codepath, hitting an uncached API on every
  call.
