mesa-sdk
Official Mesa Python SDK.
This is the primary Python SDK for Mesa. It wraps the generated mesa-rest client with ergonomic async resource namespaces and automatic org inference.
Python 3.10+ is required.
Install
pip install mesa-sdk
Quick Start
import asyncio
import os
from mesa_sdk import Mesa
async def main():
async with Mesa(private_key=os.environ["MESA_PRIVATE_KEY"]) as mesa:
repos = await mesa.repos.list()
print(repos)
asyncio.run(main())
Usage
Authentication
A signing private key belongs in a process you trust. Give anything less trusted, such as a sandbox or a worker running agent-generated code, a short-lived access token instead:
# On a trusted host, where the private key lives.
mesa = Mesa(private_key=os.environ["MESA_PRIVATE_KEY"])
# Anywhere you were handed a token; the SDK forwards it unchanged.
scoped = Mesa(auth={"access_token": access_token})
Pass exactly one of private_key or auth. When neither is present, the SDK reads MESA_PRIVATE_KEY. Private keys and access tokens already name the organization they belong to, so the client picks it up from the credential.
The Python SDK does not accept API keys as client credentials and does not read MESA_API_KEY. API keys remain supported by the Mesa CLI and direct backend interfaces.
Scoped access tokens
Mint a token in your trusted process and hand only that token to the sandbox or job that needs it:
minted = await mesa.tokens.create(
authors=[{"name": "Mesa Bot", "email": "mesa-bot@example.com"}],
scopes=["read", "write"],
repos=["acme/agent-workspace"],
ttl_seconds=60 * 60, # 1 hour
)
A token signed by a private key lasts 15 minutes by default and can be given up to 4 hours. A client built from an access token cannot mint another token.
Repositories
# List
repos = await mesa.repos.list()
# Create
repo = await mesa.repos.create(name="my-repo")
# Get
repo = await mesa.repos.get(repo="my-repo")
# Update
repo = await mesa.repos.update(repo="my-repo", name="renamed")
# Delete
await mesa.repos.delete(repo="my-repo")
Bookmarks
bookmarks = await mesa.bookmarks.list(repo="my-repo")
await mesa.bookmarks.create(repo="my-repo", name="feature-x", change_id="abc123")
await mesa.bookmarks.move(repo="my-repo", bookmark="feature-x", change_id="def456")
await mesa.bookmarks.merge(
repo="my-repo",
source="feature-x",
target="main",
message="Merge feature-x into main",
authors=[{"name": "Alice", "email": "alice@example.com"}],
)
await mesa.bookmarks.delete(repo="my-repo", bookmark="feature-x")
Changes
from mesa_sdk import FileUpsert
changes = await mesa.changes.list(repo="my-repo")
change = await mesa.changes.create(
repo="my-repo",
base_change_id="abc123",
message="Add feature",
authors=[{"name": "Alice", "email": "alice@example.com"}],
files=[FileUpsert(path="hello.txt", content="Hello, world!")],
)
change = await mesa.changes.get(repo="my-repo", change_id="def456")
Content & Diffs
content = await mesa.content.get(repo="my-repo", change_id="abc123")
diff = await mesa.diffs.get(
repo="my-repo",
base_change_id="abc123",
head_change_id="def456",
)
API Key Management
An admin-scoped private-key or access-token client can still create, list, and revoke API keys for CLI and direct backend integrations. The SDK cannot use the returned API key as its own credential.
keys = await mesa.api_keys.list()
key = await mesa.api_keys.create(name="ci-key", scopes=["read", "write"])
await mesa.api_keys.revoke(key_id=key.id)
Webhook Targets
endpoints = await mesa.webhook_targets.list()
endpoint = await mesa.webhook_targets.create(url="https://example.com/hook", events=["change.created"])
await mesa.webhook_targets.update(webhook_target_id=endpoint.id, events=["push"])
await mesa.webhook_targets.delete(webhook_target_id=endpoint.id)
Webhook Handlers
Register handlers with mesa.webhooks.on(...) and pass the raw request body
and headers to mesa.webhooks.receive(...). receive verifies the signature,
parses the payload, and dispatches registered handlers.
from fastapi import FastAPI, Request
from mesa_sdk import Mesa
app = FastAPI()
mesa = Mesa(private_key=os.environ["MESA_PRIVATE_KEY"], webhook_secret="whsec_...")
mesa.webhooks.on("push", lambda event: print(event["data"]["updates"]))
@app.post("/webhooks/mesa")
async def mesa_webhook(request: Request):
await mesa.webhooks.receive(await request.body(), request.headers)
return {"ok": True}
Virtual Filesystem
Mount repositories as a local filesystem for direct file I/O. The mount() context manager handles setup and teardown automatically.
async with mesa.fs.mount(
repos=["my-repo"],
authors=[{"name": "Mesa Bot", "email": "mesa-bot@example.com"}],
) as fs:
data = await fs.read("/my-org/my-repo/src/main.py")
await fs.write("/my-org/my-repo/src/new_file.py", b"print('hello')")
entries = await fs.readdir("/my-org/my-repo/src")
Read-only Repos
Pass RepoConfig(..., mode="ro") to mount a repo read-only. Writes to it raise OSError: [Errno 30] Read-only file system. A single mount can mix read-only and writable repos.
from mesa_sdk import RepoConfig
async with mesa.fs.mount(
repos=[RepoConfig("my-repo", mode="ro")],
authors=[{"name": "Mesa Bot", "email": "mesa-bot@example.com"}],
) as fs:
data = await fs.read("/my-org/my-repo/README.md")
Multiple Repos
Mount several repositories at once. Each repo appears as a top-level directory.
async with mesa.fs.mount(
repos=["repo-a", "repo-b"],
authors=[{"name": "Mesa Bot", "email": "mesa-bot@example.com"}],
) as fs:
a = await fs.read("/repo-a/file.txt")
b = await fs.read("/repo-b/file.txt")
Pin to Bookmark or Change
Use RepoConfig with at to pin a mount to a specific bookmark or change.
from mesa_sdk import RepoConfig
async with mesa.fs.mount(
repos=[
RepoConfig("my-repo", at={"bookmark": "feature-x"}),
RepoConfig("other-repo", at={"change_id": "abc123"}),
],
authors=[{"name": "Mesa Bot", "email": "mesa-bot@example.com"}],
) as fs:
data = await fs.read("/my-org/my-repo/file.txt")
Bash
Run shell commands inside the mounted filesystem with fs.bash().
async with mesa.fs.mount(
repos=["my-repo"],
authors=[{"name": "Mesa Bot", "email": "mesa-bot@example.com"}],
) as fs:
bash = fs.bash(env={"FOO": "bar"}, cwd="/my-org/my-repo", timeout_ms=30000)
result = await bash.exec("ls -la")
print(result.stdout, result.stderr, result.exit_code)
bash.exec() returns an ExecResult with stdout: bytes, stderr: bytes, and exit_code: int.
Changes and Bookmarks (on the Filesystem)
Create and manage changes and bookmarks directly from a mounted filesystem.
async with mesa.fs.mount(
repos=["my-repo"],
authors=[{"name": "Mesa Bot", "email": "mesa-bot@example.com"}],
) as fs:
# Changes
change = await fs.changes.new("my-repo", bookmark="main")
change = await fs.changes.edit("my-repo", change_id="abc123")
changes = await fs.changes.list("my-repo", limit=50)
result = await fs.changes.checkpoint("my-repo", message="did some work")
# Bookmarks
await fs.bookmarks.create("my-repo", "feature-y")
await fs.bookmarks.move("my-repo", "main", change_id=change)
bookmarks = await fs.bookmarks.list("my-repo")
Disk Cache
Enable on-disk caching to speed up repeated mounts.
from mesa_sdk import DiskCacheConfig
async with mesa.fs.mount(
repos=["my-repo"],
authors=[{"name": "Mesa Bot", "email": "mesa-bot@example.com"}],
disk_cache=DiskCacheConfig(path="/tmp/mesa-cache", max_size_bytes=1_000_000_000),
) as fs:
data = await fs.read("/my-org/my-repo/file.txt")
Filesystem Errors
Filesystem operations raise standard Python exceptions:
| Exception | Condition |
|---|---|
FileNotFoundError |
Path does not exist |
FileExistsError |
Path already exists (e.g. mkdir without parents) |
IsADirectoryError |
Expected a file, got a directory |
NotADirectoryError |
Expected a directory, got a file |
OSError |
General I/O failure; read-only repos use the read-only filesystem errno |
NotImplementedError |
Operation not supported (e.g. link) |
Low-Level REST Access
For operations not covered by the resource namespaces, install and use mesa-rest directly, or call the API with your own HTTP client:
from mesa_rest.api.repo import list_repos
from mesa_rest.client import AuthenticatedClient
client = AuthenticatedClient(
base_url="https://api.mesa.dev/v1",
token="mk_...",
prefix="Bearer",
)
response = await list_repos.asyncio_detailed("acme", client=client)
Configuration
Mesa accepts the following keyword arguments:
| Parameter | Type | Default | Description |
|---|---|---|---|
private_key |
str | None |
MESA_PRIVATE_KEY env var |
Signing private key for trusted processes |
auth |
MesaAuth | None |
None |
A private key or an access token, passed as one object |
api_url |
str |
https://api.mesa.dev/v1 |
Base URL for the Mesa API |
vcs_url |
str | None |
None |
Optional VCS gateway override. Only use when self-hosting Mesa. |
org |
str | None |
Read from the credential | Optional organization check. It must match the organization encoded in the credential. |
user_agent |
str | None |
None |
Custom user agent suffix |
webhook_secret |
str | None |
None |
Secret used by mesa.webhooks.receive(...) |
Error Handling
The SDK raises typed exceptions for API errors:
from mesa_sdk import Mesa, NotFoundError, AuthenticationError
async with Mesa() as mesa:
try:
repo = await mesa.repos.get(repo="nonexistent")
except NotFoundError:
print("Repo not found")
except AuthenticationError:
print("Invalid credential")
| Exception | HTTP Status | Description |
|---|---|---|
ValidationError |
400, 406 | Invalid request parameters |
AuthenticationError |
401 | Invalid or missing credential |
AuthorizationError |
403 | Insufficient permissions |
NotFoundError |
404 | Resource not found |
ConflictError |
409 | Resource conflict |
RateLimitError |
429 | Rate limit exceeded |
ServerError |
5xx | Server-side error |
All API exceptions inherit from ApiError, which inherits from MesaError.
Package Relationship
mesa-sdkis the ergonomic, main SDK.mesa-restis the generated REST client used under the hood.
Use mesa-rest directly, or call the API with your own HTTP client, when you need low-level REST access beyond the resource namespaces.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distributions
Built Distributions
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file mesa_sdk-0.45.0-cp310-abi3-musllinux_1_2_x86_64.whl.
File metadata
- Download URL: mesa_sdk-0.45.0-cp310-abi3-musllinux_1_2_x86_64.whl
- Upload date:
- Size: 9.6 MB
- Tags: CPython 3.10+, musllinux: musl 1.2+ x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via:
uv/0.11.14 {"installer":{"name":"uv","version":"0.11.14","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Amazon Linux","version":"2023","id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c15f75510124dceecad4e12b588e74318865b80570366900d50f26cb7770c485
|
|
| MD5 |
6d691217543db72d21c191cf42a9d90a
|
|
| BLAKE2b-256 |
cc61839716ae844fbb58712fe67a561ad74a22af93cc8fd0546972c1dcbc34e6
|
File details
Details for the file mesa_sdk-0.45.0-cp310-abi3-musllinux_1_2_aarch64.whl.
File metadata
- Download URL: mesa_sdk-0.45.0-cp310-abi3-musllinux_1_2_aarch64.whl
- Upload date:
- Size: 9.0 MB
- Tags: CPython 3.10+, musllinux: musl 1.2+ ARM64
- Uploaded using Trusted Publishing? No
- Uploaded via:
uv/0.11.14 {"installer":{"name":"uv","version":"0.11.14","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Amazon Linux","version":"2023","id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
082bae2b1f67c1e50394785a76589e7fcf32757443cd7f692150a711b5537ddf
|
|
| MD5 |
1ce018ea91ddceb6aebe0af2ec40778a
|
|
| BLAKE2b-256 |
091594b01830da9d5f352be066797164c5252c66a3201b81d44c1e75887b1f46
|
File details
Details for the file mesa_sdk-0.45.0-cp310-abi3-manylinux_2_38_aarch64.whl.
File metadata
- Download URL: mesa_sdk-0.45.0-cp310-abi3-manylinux_2_38_aarch64.whl
- Upload date:
- Size: 8.9 MB
- Tags: CPython 3.10+, manylinux: glibc 2.38+ ARM64
- Uploaded using Trusted Publishing? No
- Uploaded via:
uv/0.11.14 {"installer":{"name":"uv","version":"0.11.14","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Amazon Linux","version":"2023","id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
639e9663e1e4fe6a0b498d159efc9f8f42e7e00a0fae22f53cadc3690eefeafb
|
|
| MD5 |
7bc9eb43c9383b57352f44cd954b94cd
|
|
| BLAKE2b-256 |
8417ebd39bc9007d1a3035dc6c53e3d8a6c0fdb3943b76ddde3bafbe8b8f593e
|
File details
Details for the file mesa_sdk-0.45.0-cp310-abi3-manylinux_2_34_x86_64.whl.
File metadata
- Download URL: mesa_sdk-0.45.0-cp310-abi3-manylinux_2_34_x86_64.whl
- Upload date:
- Size: 9.3 MB
- Tags: CPython 3.10+, manylinux: glibc 2.34+ x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via:
uv/0.11.14 {"installer":{"name":"uv","version":"0.11.14","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Amazon Linux","version":"2023","id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
5367172055f067f3c914abe9c1f36467245397c1da0ddcadf5ffafba17e698c1
|
|
| MD5 |
01b3d442cbb3d867779a2ef77068dbd4
|
|
| BLAKE2b-256 |
cb53c948e193276616f649358444f98fd0cd30bdb2f4491df365e85a390945db
|
File details
Details for the file mesa_sdk-0.45.0-cp310-abi3-macosx_11_0_arm64.whl.
File metadata
- Download URL: mesa_sdk-0.45.0-cp310-abi3-macosx_11_0_arm64.whl
- Upload date:
- Size: 8.3 MB
- Tags: CPython 3.10+, macOS 11.0+ ARM64
- Uploaded using Trusted Publishing? No
- Uploaded via:
uv/0.11.14 {"installer":{"name":"uv","version":"0.11.14","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Amazon Linux","version":"2023","id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
efbb218676eb600720d09f035f4f9963ced5bffc193623ec29d0414cea8c3375
|
|
| MD5 |
c5087ae166c7f8711c84aedea6902f2c
|
|
| BLAKE2b-256 |
639f34cd4438fe1c4e7fc86abb39b37d5ab24792e59b75c9bfbd5c7d9357d219
|