Metadata-Version: 2.1
Name: mesa_sdk
Author: Mesa
Author-email: support@mesa.dev
Home-page: https://mesa.dev
License: Apache-2.0
Description-Content-Type: text/markdown
Summary: Official Mesa Python SDK
Project-URL: Repository, https://github.com/mesa-dot-dev/depot
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: Apache Software License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Requires-Python: >=3.10
Requires-Dist: mesa-rest>=0.6.0
Version: 0.24.0

# mesa-sdk

Official Mesa Python SDK.

This is the primary Python SDK for Mesa. It wraps the generated [`mesa-rest`](https://pypi.org/project/mesa-rest/) client with ergonomic async resource namespaces and automatic org inference.

Python 3.10+ is required.

## Install

```bash
pip install mesa-sdk
```

## Quick Start

```python
import asyncio
from mesa_sdk import Mesa

async def main():
    async with Mesa(api_key="mk_...") as mesa:
        repos = await mesa.repos.list()
        print(repos)

asyncio.run(main())
```

## Usage

### Org Resolution

The SDK resolves your default organization automatically via `/whoami` on first use. You can bypass this by passing `org` to the constructor or overriding per-call:

```python
# Default: org inferred from /whoami (lazy, cached)
mesa = Mesa(api_key="mk_...")
repos = await mesa.repos.list()

# Constructor org bypasses /whoami entirely
mesa = Mesa(api_key="mk_...", org="acme")
repos = await mesa.repos.list()

# Per-call override
repos = await mesa.repos.list(org="other-org")
```

### Repositories

```python
# 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

```python
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")
await mesa.bookmarks.delete(repo="my-repo", bookmark="feature-x")
```

### Changes

```python
from mesa_sdk import Author, FileUpsert

changes = await mesa.changes.list(repo="my-repo")
change = await mesa.changes.create(
    repo="my-repo",
    base_change_id="abc123",
    message="Add feature",
    author=Author(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

```python
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 Keys

```python
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)
```

### Webhooks

```python
webhooks = await mesa.webhooks.list()
webhook = await mesa.webhooks.create(url="https://example.com/hook", events=["change.created"])
await mesa.webhooks.delete(webhook_id=webhook.id)
```

### Raw Client Access

For operations not covered by the resource namespaces, you can use the underlying `mesa-rest` `AuthenticatedClient` directly:

```python
from mesa_rest.api.repo import list_repos

response = await list_repos.asyncio_detailed("acme", client=mesa.raw)
```

## Configuration

`Mesa` accepts the following keyword arguments:

| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `api_key` | `str \| None` | `MESA_API_KEY` env var | API key for authentication |
| `api_url` | `str` | `https://api.mesa.dev/v1` | Base URL for the Mesa API |
| `org` | `str \| None` | Resolved from `/whoami` | Default organization slug |
| `user_agent` | `str \| None` | `None` | Custom user agent suffix |

## Error Handling

The SDK raises typed exceptions for API errors:

```python
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 API key")
```

| Exception | HTTP Status | Description |
|-----------|-------------|-------------|
| `ValidationError` | 400, 406 | Invalid request parameters |
| `AuthenticationError` | 401 | Invalid or missing API key |
| `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-sdk` is the ergonomic, main SDK.
- `mesa-rest` is the generated REST client used under the hood.

Use `mesa.raw` when you need direct access to the generated `AuthenticatedClient`.

