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

# Python

> Install the Chronicle Python SDK and run your first evaluation.

## Install

```python theme={null}
# pip install chronicle-sdk
from chronicle import Chronicle

client = Chronicle()  # reads CHRONICLE_API_KEY and CHRONICLE_API_URL
# or: Chronicle(api_key="chr_...", base_url="https://api.your-chronicle-deployment.com")
```

Python 3.9 or later. Use `with Chronicle() as client:` to close connections
when a script exits.

## Run an evaluation

Before running this example, [register `billing-agent@1.0.0` and configure its
run command](/platform/agents). Set `CHRONICLE_API_KEY` and `CHRONICLE_API_URL`
using [Authentication](/api-reference/authentication). The script selects the
built-in world by its `triage-duplicate-invoice` task key; it stops if that
example is unavailable.

The keys `demo-1` and `demo-run-1` identify this first attempt. Keep them when
retrying the same inputs; change them when you want a new world or evaluation.
If task setup is not ready, keep the returned world ID and follow
[task setup recovery](/api-reference/worldsmith#retry-task-setup).

```python theme={null}
from chronicle import Chronicle

with Chronicle() as client:
    example = next((e for e in client.worlds.examples.list().items
                    if any(t.key == "triage-duplicate-invoice"
                           for t in e.blueprint.scenario.tasks)), None)
    if example is None:
        raise RuntimeError("The duplicate-invoice example is not available")
    preview = client.worlds.compile(blueprint=example.blueprint)
    if preview.problems:
        raise RuntimeError(preview.problems)

    world = client.worlds.create(blueprint=example.blueprint, idempotency_key="demo-1")
    world = client.worlds.wait(world.world.id, timeout=180)
    if world.status != "ready":
        raise RuntimeError(f"World {world.world.id}: {world.status}; {world.launch_error}")
    if world.evaluation is None or world.evaluation.status != "ready":
        raise RuntimeError(f"Task setup is not ready for world {world.world.id}; see the Worlds guide")

    run = client.evaluations.create(
        task_suite_id=world.evaluation.task_suite_id,
        agents=["billing-agent@1.0.0"],
        idempotency_key="demo-run-1",
    )
    run = client.evaluations.wait(run.id, timeout=600)
    if run.status != "succeeded":
        raise RuntimeError(f"Evaluation {run.id}: {run.status}; inspect its trials")
    for result in client.evaluations.results(run.id).task_results:
        print(result.task_id, "passed" if result.passed else "failed", result.failed_scorers)
```

In the dashboard, evaluations are under **Backtests**.
[Inspect the example task](/product-explorer#agent-task) and compare it with
the [trial scores](/api-reference/evaluations#inspect-trials).

To see individual scores, put this inside the same `with Chronicle()` block
after the run finishes (or open a new client and use the saved run ID):

```python theme={null}
for trial in client.evaluations.trials.list(run.id).auto_paging_iter():
    print(trial.agent, trial.task_id, trial.status)
    for score in trial.scores:
        print("  ", score.name, score.score, score.passed)
```

## Async

Every method is available on `AsyncChronicle` with the same names.

```python theme={null}
import asyncio
from chronicle import AsyncChronicle

async def main():
    async with AsyncChronicle() as client:
        world = await client.worlds.retrieve("<world-id>")
        print(world.status)

asyncio.run(main())
```

## Errors and configuration

```python theme={null}
from chronicle import APIError, Chronicle

client = Chronicle(timeout=30.0, max_retries=2)

try:
    client.worlds.retrieve("<world-id>")
except APIError as e:
    print(e.status_code, e.message, e.request_id)
```

Timeouts are in seconds. Pages have `items`, `has_next_page()`,
`get_next_page()`, and `auto_paging_iter()`. Models are in `chronicle.types`
and use `snake_case`. See [Errors and retries](/api-reference/reliability).
