# Python SDK — Integration Guide

The `meshpocalypse-semantic` Python SDK provides async Python access to the Meshpocalypse mesh.

## Install

```bash
pip install meshpocalypse-semantic
```

**Requires:** Python ≥ 3.10, NATS server, `nats-py >= 2.8.0`

## Async context manager pattern

`MeshNode` must always be used as an `async with` context manager. This is the only supported usage — do not call methods outside the block, and do not create background tasks in `__init__`.

```python
from meshpocalypse_semantic import MeshNode

async with MeshNode("nats://localhost:4222") as mesh:
    # mesh is connected here
    await mesh.publish("mesh.events.hello", b"hello world")
# mesh is drained and disconnected here
```

### Accessing sub-clients

```python
async with MeshNode() as mesh:
    sparql_client = mesh.sparql   # SparqlClient
    atf_client = mesh.atf         # ATFClient
```

Accessing `mesh.sparql` or `mesh.atf` outside the `async with` block raises `RuntimeError`.

## SparqlClient

`mesh.sparql` exposes SPARQL queries and updates against the mesh RDF graph, routed via the TypeScript SPARQL bridge over NATS.

### SELECT query

```python
rows = await mesh.sparql.query(
    "PREFIX mesh: <https://meshpocalypse.dev/ontology#> "
    "SELECT ?agent ?status WHERE { "
    "  ?agent a mesh:Agent ; mesh:status ?status . "
    "} LIMIT 10"
)
for row in rows:
    print(row["agent"]["value"], row["status"]["value"])
```

Returns a `list[dict]` in [W3C SPARQL JSON format](https://www.w3.org/TR/sparql11-results-json/).

### UPDATE

```python
await mesh.sparql.update(
    "PREFIX mesh: <https://meshpocalypse.dev/ontology#> "
    "INSERT DATA { "
    "  <https://meshpocalypse.dev/instance/my-agent> a mesh:Agent ; mesh:status \"idle\" . "
    "}"
)
```

### Errors

| Exception | When |
|---|---|
| `SparqlQueryError` | Bridge returns an error response |
| `ValueError` | Empty query string |
| `nats.errors.TimeoutError` | No response within timeout (default 10 s) |

## ATFClient

`mesh.atf` exposes trust-level queries to the ATF service.

```python
from meshpocalypse_semantic import ATFLevel

level = await mesh.atf.get_trust_level("did:mesh:my-agent")
print(f"Trust level: {level.name} ({int(level)})")

# Boolean check
if await mesh.atf.check_minimum("did:mesh:my-agent", ATFLevel.SENIOR):
    print("Agent has operational access")
```

### ATF levels

| Value | Name | Meaning |
|---|---|---|
| 0 | `INTERN` | No trust — read-only, supervised |
| 1 | `JUNIOR` | Limited write access |
| 2 | `SENIOR` | Full operational access |
| 3 | `PRINCIPAL` | Cross-mesh authority |
| 4 | `SYSTEM` | Root — infrastructure only |

### Errors

| Exception | When |
|---|---|
| `ATFError` | Service returns an error or unknown level |
| `ValueError` | Empty agent_id |

## Publishing

```python
await mesh.publish("mesh.events.my-subject", b"raw bytes payload")
```

## Configuration

The SDK accepts a NATS URL and API keys as configuration parameters. Credentials are not managed by the SDK — pass them as arguments or via environment variables:

```python
import os
nats_url = os.environ.get("NATS_URL", "nats://localhost:4222")
async with MeshNode(nats_url) as mesh:
    ...
```

## Development / local install

```bash
git clone https://github.com/one137th/Meshpocalypse
cd Meshpocalypse/sdks/python
pip install -e ".[dev]"
pytest
```

## See also

- [Python SDK demo](../../examples/python-sdk-demo/)
- [Semantic Kernel adapter](./semantic-kernel.md)
