Skip to main content
The Mesa Python SDK (mesa-sdk) provides a typed Python client for interacting with the Depot API. It follows the same OpenAPI contract as the TypeScript SDK, with resource-based accessors, pagination support, retries, and structured errors.

Installation

pip install mesa-sdk

Quick Start

import os
from mesa_sdk import Mesa

client = Mesa(
    api_key=os.environ["MESA_API_KEY"],
)

# Create a repository
repo = client.repos.create(
    org="my-org",
    body={"name": "my-repo"},
)

# List repositories
repos_page = client.repos.list(org="my-org")
print(repos_page)

Configuration

You can configure authentication, server URL, timeout, and retries when constructing the client.
from mesa_sdk import Mesa

client = Mesa(
    # Required: API key for authentication
    api_key="your-api-key",

    # Optional: Override base URL
    server_url="https://depot.mesa.dev/api/v1",

    # Optional: Global timeout in milliseconds
    timeout_ms=30_000,

    # Optional: Retry configuration
    retry_config={
        "strategy": "backoff",
        "backoff": {
            "initial_interval": 500,
            "max_interval": 60_000,
            "exponent": 1.5,
            "max_elapsed_time": 300_000,
        },
    },
)

Environment Variables

The SDK can read credentials from environment variables when not explicitly configured:
  • MESA_API_KEY - your API key

Resources

The SDK organizes methods into resource namespaces that mirror the API structure.

Repositories

# Create a repository
repo = client.repos.create(
    org="my-org",
    body={
        "name": "my-repo",
        "default_branch": "main",  # optional
    },
)

# List repositories (paginated)
repos_page = client.repos.list(
    org="my-org",
    limit=50,
    cursor="...",  # optional
)

# Get a specific repository
repo = client.repos.get(
    org="my-org",
    repo="my-repo",
)

# Update a repository
updated = client.repos.update(
    org="my-org",
    repo="my-repo",
    body={"name": "new-name"},
)

# Delete a repository
client.repos.delete(
    org="my-org",
    repo="my-repo",
)

Branches

# List branches
branches_page = client.branches.list(
    org="my-org",
    repo="my-repo",
)

# Create a branch
branch = client.branches.create(
    org="my-org",
    repo="my-repo",
    body={
        "name": "feature-branch",
        "head_sha": "abc123...",
    },
)

# Delete a branch
client.branches.delete(
    org="my-org",
    repo="my-repo",
    branch="feature-branch",
)

Commits

# List commits
commits_page = client.commits.list(
    org="my-org",
    repo="my-repo",
    ref="main",  # optional
)

# Get a commit
commit = client.commits.get(
    org="my-org",
    repo="my-repo",
    sha="abc123...",
)

# Create a commit
new_commit = client.commits.create(
    org="my-org",
    repo="my-repo",
    body={
        "branch": "main",
        "message": "Add README",
        "author": {
            "name": "Bot",
            "email": "bot@example.com",
        },
        "edits": [
            {
                "path": "README.md",
                "action": "create",
                "content": "# Hello from Mesa\n",
            }
        ],
    },
)

Content

# Get file content
content = client.content.get(
    org="my-org",
    repo="my-repo",
    path="src/index.py",
    ref="main",  # optional
)

# Handle file vs directory responses
if getattr(content, "type", None) == "file":
    print(content.content)
else:
    print(content.entries)

Diffs

diff = client.diffs.get(
    org="my-org",
    repo="my-repo",
    base="main",
    head="feature-branch",
)

for file in diff.files:
    print(f"{file.status}: {file.path}")

Merge

# Merge a branch into another (fast-forward when possible)
result = client.merge.perform(
    org="my-org",
    repo="my-repo",
    base="main",
    body={
        "head": "feature-branch",
        "author": {
            "name": "Bot",
            "email": "bot@example.com",
        },
    },
)

print(result.merge_type)  # "fast_forward" or "merge_commit"
print(result.sha)          # Resulting commit SHA
# Merge with a custom commit message
result = client.merge.perform(
    org="my-org",
    repo="my-repo",
    base="main",
    body={
        "head": "feature-branch",
        "message": "Ship feature X",
        "author": {
            "name": "Bot",
            "email": "bot@example.com",
        },
    },
)
# Merge and delete the head branch afterward
result = client.merge.perform(
    org="my-org",
    repo="my-repo",
    base="main",
    body={
        "head": "feature-branch",
        "author": {
            "name": "Bot",
            "email": "bot@example.com",
        },
        "delete_branch": True,
    },
)

print(result.branch_deleted)  # True
The merge endpoint returns 409 MERGE_CONFLICT when the branches have conflicting changes that cannot be auto-resolved. Catch this error to handle conflicts in your workflow.

Admin (API Keys)

# Create API key
new_key = client.admin.create_api_key(
    org="my-org",
    body={
        "name": "CI Key",
        "scopes": ["git:read", "git:write"],
    },
)
print(new_key.key)

# List API keys
keys = client.admin.list_api_keys(org="my-org")

# Revoke API key
client.admin.revoke_api_key(
    org="my-org",
    id="key_123",
)

LFS (Large File Storage)

# Request upload URLs
upload = client.lfs.upload(
    org="my-org",
    repo="my-repo",
    body={
        "objects": [{"oid": "sha256-hash...", "size": 12_345_678}],
    },
)

# Request download URLs
download = client.lfs.download(
    org="my-org",
    repo="my-repo",
    body={
        "objects": [{"oid": "sha256-hash...", "size": 12_345_678}],
    },
)

Pagination

List endpoints support cursor-based pagination.
cursor = None

while True:
    page = client.repos.list(
        org="my-org",
        cursor=cursor,
        limit=100,
    )

    for repo in page.result.repos:
        print(repo.name)

    cursor = page.result.next_cursor
    if not cursor:
        break

Error Handling

The SDK raises exceptions for request and response failures. Catch and branch on error type or status as needed by your application.
try:
    client.repos.get(org="my-org", repo="missing")
except Exception as exc:
    # Handle SDK-specific errors in your application layer.
    # Common categories: auth errors, validation errors, not found,
    # conflict, and transport failures.
    print(f"Request failed: {exc}")
    raise

Error Shape

API errors follow a consistent shape:
{
  "error": {
    "code": "NOT_FOUND",
    "message": "Repository not found",
    "details": {}
  }
}

Per-Request Options

You can override client defaults for a single request (for example timeout, retries, or headers).
repo = client.repos.get(
    org="my-org",
    repo="my-repo",
    request_options={
        "timeout_ms": 60_000,
        "headers": {
            "X-Custom-Header": "value",
        },
    },
)

Complete Example

import os
from mesa_sdk import Mesa


def main() -> None:
    client = Mesa(api_key=os.environ["MESA_API_KEY"])

    # Create repository
    client.repos.create(
        org="my-org",
        body={"name": "example-repo"},
    )

    # Initial commit on main
    client.commits.create(
        org="my-org",
        repo="example-repo",
        body={
            "branch": "main",
            "message": "Initial commit",
            "author": {
                "name": "Bot",
                "email": "bot@example.com",
            },
            "edits": [
                {
                    "path": "README.md",
                    "action": "create",
                    "content": "# Example Repository\n",
                }
            ],
        },
    )

    # Create feature branch from latest main commit
    commits_page = client.commits.list(
        org="my-org",
        repo="example-repo",
        ref="main",
        limit=1,
    )
    head_sha = commits_page.result.commits[0].sha

    client.branches.create(
        org="my-org",
        repo="example-repo",
        body={
            "name": "feature",
            "head_sha": head_sha,
        },
    )

    # Commit feature change
    client.commits.create(
        org="my-org",
        repo="example-repo",
        body={
            "branch": "feature",
            "message": "Add feature",
            "author": {
                "name": "Bot",
                "email": "bot@example.com",
            },
            "edits": [
                {
                    "path": "feature.py",
                    "action": "create",
                    "content": "FEATURE_ENABLED = True\n",
                }
            ],
        },
    )

    # Diff feature against main
    diff = client.diffs.get(
        org="my-org",
        repo="example-repo",
        base="main",
        head="feature",
    )

    print(f"Changes: {len(diff.files)} files")

    # Merge feature branch into main and clean up
    merge = client.merge.perform(
        org="my-org",
        repo="example-repo",
        base="main",
        body={
            "head": "feature",
            "author": {
                "name": "Bot",
                "email": "bot@example.com",
            },
            "delete_branch": True,
        },
    )

    print(f"Merged via {merge.merge_type}: {merge.sha}")


if __name__ == "__main__":
    main()
For endpoint behavior and payload details shared across all SDKs, see the HTTP API Reference.