> ## Documentation Index
> Fetch the complete documentation index at: https://hub.hcompany.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Embed with Python

> Use HoloDesktop CLI's Python agent client to run desktop sessions from your own code.

Reach for the Python client when you want desktop sessions inside your own code, a script, demo harness, test runner, or local tool, instead of shelling out to `holo run`.

The Python client starts or attaches to the same local `hai-agent-runtime` process used by the CLI, MCP, and ACP surfaces.

## Basic script

After installing HoloDesktop CLI, import the agent client from `holo_desktop`:

```python theme={null}
import asyncio

from holo_desktop.agent_client import AgentApiClient, SpawnConfig, ensure_running
from holo_desktop.agent_client.requests import build_session_request


async def main() -> None:
    daemon = await ensure_running(SpawnConfig(port=18795))
    try:
        async with AgentApiClient(daemon.base_url, daemon.token) as client:
            request = build_session_request(
                task="Open TextEdit and write a short note saying HoloDesktop CLI is embedded",
                max_steps=10,
                max_time_s=120,
            )
            session_id = await client.create_session(request)
            stream = client.stream(session_id)

            async for event in stream.events():
                print(event.type)

            print(stream.answer)
    finally:
        await daemon.aclose()


asyncio.run(main())
```

Run it with:

```bash theme={null}
python your_script.py
```

From a source checkout, run it through `uv` instead: `uv run python your_script.py`.

## Use hosted or local mode

Hosted mode uses the same login state as the CLI. Sign in once:

```bash theme={null}
holo login
```

Local mode passes model settings at runtime spawn:

```python theme={null}
daemon = await ensure_running(
    SpawnConfig(
        port=18795,
        model="Hcompany/Holo-3.1-35B-A3B",
        base_url="http://localhost:8000/v1",
    )
)
```

The model and base URL are process-level settings. Start a separate runtime process when you need to switch model backend.

## Keep logs for a run

To choose where runtime event logs are written:

```python theme={null}
from pathlib import Path

daemon = await ensure_running(
    SpawnConfig(
        port=18795,
        runs_dir=Path("/tmp/holo-runs"),
    )
)
```

The CLI equivalent is:

```bash theme={null}
holo run --runs-dir /tmp/holo-runs "Open TextEdit and write test"
```

## Send another message

The client exposes pause, resume, cancel, and mid-run messages:

```python theme={null}
await client.pause(session_id)
await client.resume(session_id)
await client.send_message(session_id, "Continue, but do not send anything.")
await client.cancel(session_id)
```

Use these methods for interactive tools. For one-shot scripts, create a session, stream to end-of-turn, and close the daemon.

## Handle cleanup

Always close the daemon:

```python theme={null}
finally:
    await daemon.aclose()
```

If your script spawned the runtime, closing the daemon stops it. If it attached to an already-running runtime on the same port, closing the daemon only releases the client-side handle. If your program is interrupted while a session is active, cancel the session or close the daemon before exiting, or the runtime may keep working until its timeout or safety budget.

## What to avoid

* Do not pass secrets or hidden context only in your app state. HoloDesktop CLI sees the task string and the configured `~/.holo` context, not your surrounding Python variables.
* Do not switch `model` or `base_url` per session. Those are runtime process settings.
* Do not leave a session running after your program exits. Cancel or close when interrupted.

## What's next

Use [Debug a failed run](/holo-desktop-cli/how-to/debug-failed-run) to inspect runtime logs, or see the [expense-report example](/holo-desktop-cli/examples/expense-report-automation) for a larger tested harness.
