# Python library (coming soon)

A Python client for the Silan engine lives in the repository at SDKs/python. It is not published yet.

:::caution[Coming soon]
The Python library is not released. It lives in the Silan repository at `SDKs/python` and is not on PyPI. Never install a package named `silan` from PyPI: it is not Silan's. The app's **Connections** page says the same: the Python SDK comes later.
:::

Silan's Python library wraps the REST API for scripts and tests on the Mac that holds the devices. Status: **coming soon**. This page describes what is in the repository today, so you know its shape before it ships. Until then, use the [REST API](/integrations/rest/) directly, or start `silan mcp` from Python the way the [agent loop examples](/integrations/build-your-own-agent-loop/) do.

## What is in the repository

| File | What it holds |
|---|---|
| `silan/client.py` | `Client`, `devices()`, `claim()`, a device handle with `tap`, `type_text`, `wait_for`, `screenshot`, and `call()` for any operation |
| `silan/scenario.py` | A `Scenario` builder with roles and steps, a preview |
| `silan/errors.py` | `SilanError` with the engine's `code`, the HTTP `status` and `candidates` |
| `silan/_operations.py` | Generated from `Specs/openapi.yaml`, one entry per `operationId`. Not edited by hand |
| `tests/` | Offline tests, and live tests that need an engine and a device |

Standard library only, Python 3.9 or later.

## Setup

Nothing to install today. When it ships, the steps will be these, and the repository's `README.md` already describes them:

1. Make a key on **Connections**, under **For developers**, with **New key**, and put it in `SILAN_API_KEY`. The library does not read the engine's local key file itself.
2. Let the client find the engine. It tries, in order: `silan.Client(url=...)`, the `SILAN_URL` variable, the port in `~/Library/Application Support/Silan/engine.json`, then `http://127.0.0.1:47800`.
3. Import it and claim a device.

## The shape of the client

```python
import silan

client = silan.Client()          # finds the engine; the key comes from SILAN_API_KEY
for device in client.devices():
    print(device.id, device.name)

with client.claim("ios:00008120-001A2B3C4D5E6F70") as lease:
    phone = lease.device()
    phone.tap(text="Checkout")
    phone.type_text("hello", submit=True)
    assert phone.wait_for(text="Sent", timeout_ms=5000)
    open("screen.png", "wb").write(phone.screenshot())
```

`claim` makes a lease and gives it back when the block ends. Every operation in the OpenAPI document is also reachable by its `operationId`, with the spec's parameter names or snake case:

```python
client.call("listNotifications", device_id="android:R58M123ABC", app_id="com.example.chat")
client.call("act", device_id="ios:...", body={"action": {"type": "swipe", "direction": "up"}})
```

An error raises `silan.SilanError` with the catalog `code`, such as `TARGET_NOT_FOUND`, the HTTP `status`, and `candidates` when a target matched more than one element.

## Try it

There is nothing to try yet outside the repository. With a copy of it, the offline tests run with no engine:

```sh
cd SDKs/python
python3 -m unittest discover -s tests -t .
```

With `SILAN_URL`, `SILAN_API_KEY` and `SILAN_TEST_DEVICE` set, the same command also runs the live tests against your engine and a device.

## Limits

- Not published, not released, not proved on a real device. The status is coming soon.
- Scenarios and their reports in the library are a preview that is not tested yet. Do not rely on them in CI.
- The library speaks REST, so it needs a key. It does not read the local key file, and it cannot make keys: make them in the app.
- Like the REST API, it reaches the engine on this Mac only. There is no headless or CI use without the Silan app.
- The `silan_mcp.py` helper in `Examples/agent-loops` is not this library. It speaks MCP to `silan mcp` over stdio and is meant for an agent loop.