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

# Clients

> Create executions, inspect them, and resolve approvals

`rebuno.Client` creates executions and inspects what they did. Your backend, a
script, or an operator uses it, not the agent handler.

```python theme={"theme":{"light":"min-light","dark":"material-theme-ocean"}}
from rebuno import Client

client = Client(
    base_url="http://localhost:8080",  # or REBUNO_URL
    api_key="...",                     # or REBUNO_API_KEY
    timeout=35.0,                      # default
)
```

`base_url` is required, from the argument or `REBUNO_URL`. `api_key` is optional
and sent as `Authorization: Bearer ...` when present.

`Client` is an async context manager, so it closes its connection pool:

```python theme={"theme":{"light":"min-light","dark":"material-theme-ocean"}}
async with Client() as client:
    execution = await client.create("dev-agent", input={"prompt": "hello"})
    ...
```

Otherwise call `await client.close()` when you're done.

## Executions

```python theme={"theme":{"light":"min-light","dark":"material-theme-ocean"}}
# create an execution (dispatches the agent)
execution = await client.create(
    "dev-agent",
    input={"prompt": "hello"},   # optional; shape matches the handler signature
)

execution = await client.get(execution.id)   # current state
await client.cancel(execution.id)             # request cancellation
```

`create` and `get` return an [`Execution`](#models). Poll `get` or read the
event log to watch it progress.

## Event log and steps

Read the raw event stream, or the steps it produced:

```python theme={"theme":{"light":"min-light","dark":"material-theme-ocean"}}
events = await client.events(execution.id, after_seq=0, limit=100)

steps = await client.list_steps(execution.id, status="")   # status filter optional
step = await client.get_step(execution.id, step_id)
```

`events` is paginated by `after_seq`: pass the last `event_seq` you've seen.
`limit` defaults to 100.

## Approvals

When policy requires approval for a step, the execution blocks and an approval
is created. Inspect and resolve them through `Client`:

```python theme={"theme":{"light":"min-light","dark":"material-theme-ocean"}}
pending = await client.list_approvals(status="pending")   # default status

await client.grant_approval(pending[0].id, decided_by="alice", rationale="looks fine")
# or
await client.deny_approval(pending[0].id, decided_by="alice", rationale="not allowed")

one = await client.get_approval(approval_id)
```

Granting an approval lets the kernel re-dispatch. The handler replays its
recorded steps and proceeds past the one that was waiting. From the handler's
perspective the blocked call simply returns once approved.

## Errors

Failed requests raise typed exceptions: `NotFoundError`, `UnauthorizedError`,
`ForbiddenError`, `ValidationError`, `PolicyError`, `NetworkError`, and others,
all subclasses of `rebuno.RebunoError`. See [Errors](/sdk/python/errors).

## Models

`Client` returns pydantic models. They ignore unknown fields, so kernel
additions won't break you.

* `Execution`: `id`, `agent_id`, `input`, `status`, `output`,
  `failure_reason`. `status` is an `ExecutionStatus`, one of `pending`,
  `running`, `blocked`, `completed`, `failed`, `cancelled`.
* `Step`: `step_id`, `execution_id`, `kind`, `target`, `args_hash`,
  `occurrence`, `status`, `idempotency`, `args`, `result`, `error`.
* `Event`: `execution_id`, `event_seq`, `type`, `payload`, `occurred_at`.
* `Approval`: `id`, `step_id`, `execution_id`, `status`, `message`,
  `decided_by`, `rationale`.

These live in `rebuno.types`.
