# Python SDK

> Connect Python to a running local Code server, iterate one turn or follow a session, answer specific permissions, and cancel work with the correct lifecycle.

Source: https://kaitoi.io/docs/cli/python-sdk/
Section: Kaitoi CLI / Editors and automation
Written for: Python developers integrating local Code sessions.
Prerequisites: Python 3.11 or newer with the kaitoi-code package installed; A running kaitoi code serve process
Last reviewed: 2026-10-24

---

`KaitoiCodeClient` is a synchronous client for an already running local Code
server. It does not start that server or act as a hosted model SDK. The import
comes from the Python package `kaitoi-code`; installing a bundled CLI executable
alone does not make it importable in every Python environment. This guide
describes the **0.9.0** package API.

## Connect and send a turn

Start `kaitoi code serve` in another terminal. Then, in your project:

```python
from kaitoi_code.sdk import KaitoiCodeClient

with KaitoiCodeClient.from_running_server() as client:
    with client.create_session(".", trust="read", mode="plan") as session:
        for event in session.send("Explain this project"):
            print(event.kind)
```

This example submits a real model request when executed. The SDK resolves the
relative workspace path. `create_session` defaults to `trust="none"`; choose
`read` or `edits` explicitly for the intended access. Other options include
provider, model, mode, resume, and command availability.

`from_running_server()` selects the newest compatible running discovery record;
pass `pid=...` to select a specific server. When serve uses `--token-file`, it
does not write a discovery record: construct `KaitoiCodeClient(base_url, token)`
with your protected local values. The client accepts loopback URLs and disables
environment proxies and redirects.

## Distinguish watching from stopping


The client owns HTTP connections; a served session owns ongoing work; a Turn
iterator follows one submitted turn until turn.end. Closing or leaving that
iterator stops following events only. Session.cancel requests cancellation.
Session.close stops and closes the served session while preserving its log.
Client.close releases the client's connections.

The four controls act on different tracks: turn.close and client.close disconnect observation; session.cancel requests the running work to stop; session.close stops and closes the served session. Retained log evidence remains separate from open connections.

*Figure: Closing the view of a turn is different from canceling the work.*

`session.send(...)` starts work immediately and returns a `Turn`. Iteration and
`turn.wait()` drain through its `turn.end`. Events expose `kind`, `data`,
`sequence`, and `id`. By contrast, `session.events(after=...)` follows the
session-wide stream and can span multiple turns.

**Breaking iteration or calling `turn.close()` does not cancel work.** Call
`session.cancel()` to request cancellation, then inspect progress before sending
another turn. `session.close()` stops and closes the served session; its saved
log remains. `client.close()` only releases HTTP connections. Context managers
apply those respective close operations on exit.

## Answer concrete permission requests

`send` can take an `on_permission` callback. It receives a `PendingPermission`
with `id`, `action`, `operation`, `summary`, `details`, and `decisions`. Present
that request to the responsible operator and return one of its advertised
decisions. Returning `None` leaves it pending for an explicit answer.

With no callback, requests can remain pending until answered or timed out.
Do not implement a callback that blindly approves every action, and do not
assume every request supports session-wide approval. The
[HTTP guide](/docs/cli/session-api/) explains trust, decisions, timeouts, and
the one-turn-at-a-time constraint.

For Python execution of local **recipes**, use the distinct Runtime API in
`kaitoi_runtime`. It has a different purpose and lifecycle from Code sessions.
