Skip to main content
All notable changes to this project will be documented in this file. The format is based on Common Changelog, and this project adheres to Semantic Versioning.

0.48.1 - 2026-09-15

Fixed

  • Fix filesystem checkpoint on empty repositories by initializing the first change before saving and advancing bookmarks

0.48.0 - 2026-09-10

Changed

  • Breaking: Rename SigningKeyAuthor to Author for commit attribution and rename the existing committer Author dataclass to Committer
  • Breaking: Consolidate LayoutSpec and the Layout wrapper into a validated, plain Layout mapping, serialize it with json.dumps(), and rename FsNamespace to FilesystemDefinitions

Added

  • Add authors and authored_at to change.created and change.evolved webhook events; email is null when none was supplied
  • Add authors and authored_at to change results

Removed

  • Breaking: Remove the deprecated singular author from change results and from normalized change.created / change.evolved webhook events; read authors and authored_at instead. Raw mesa_rest responses keep author for API compatibility
  • Breaking: Remove the undocumented block_size_bytes keyword from DiskCacheConfig. Disk cache block size is an internal tuning knob and was never declared in the type stubs
  • Breaking: Remove MesaFileSystem.connect() from the public surface; open a filesystem with mesa.fs(layout=..., authors=...).mount(), which mints the mount’s token with scopes derived from the layout. MesaFileSystem remains exported for annotating the value mount() yields
  • Breaking: Remove legacy comma-separated repository tag filters from mesa.repos.list(); pass a structured filter dictionary instead
  • Breaking: Remove auth and access-token construction from Mesa; construct with Mesa() or Mesa(private_key=...) plus the usual keyword options, and pass scoped tokens to the CLI, mounted MesaFS environments, or direct REST calls instead
  • Breaking: Remove API-key management methods
  • Breaking: Remove mesa.tokens.create(). Mint through a layout definition instead: mesa.fs(layout=..., ttl=...).token(), which scopes the token to the repositories the layout declares

[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)

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.