> ## 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.

# Rust

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

## Install

```rust theme={null}
// cargo add chronicle-sdk tokio --features tokio/full
use chronicle_sdk::Chronicle;

let client = Chronicle::from_env()?; // reads CHRONICLE_API_KEY and CHRONICLE_API_URL
// or: Chronicle::builder().api_key("chr_...").base_url("https://api.your-chronicle-deployment.com").build()?
```

Every method is `async` and returns `Result<T, chronicle_sdk::Error>`. Request
and response types live in `chronicle_sdk::types`; optional fields are
`Option<T>`, and params structs implement `Default`.

## 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).

```rust theme={null}
use chronicle_sdk::{Chronicle, types::{EvaluationCreateParams, WorldCompileParams, WorldCreateParams}};
use std::time::Duration;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = Chronicle::from_env()?;
    let example = client.worlds().examples().list().await?.items.into_iter()
        .find(|e| e.blueprint.scenario.tasks.iter().any(|t| t.key == "triage-duplicate-invoice"))
        .ok_or("The duplicate-invoice example is not available")?;
    let preview = client.worlds().compile(WorldCompileParams { blueprint: example.blueprint.clone() }).await?;
    if !preview.problems.is_empty() { return Err(format!("blueprint: {:?}", preview.problems).into()); }

    let world = client.worlds().create(WorldCreateParams {
        blueprint: example.blueprint,
        idempotency_key: "demo-1".into(),
        ..Default::default()
    }).await?;
    let world = client.worlds().wait(&world.world.id, Duration::from_secs(180)).await?;
    if world.status != "ready" {
        return Err(format!("world {}: {:?}; {:?}", world.world.id, world.status, world.launch_error).into());
    }
    let evaluation = world.evaluation.as_ref()
        .filter(|e| e.status == "ready")
        .ok_or_else(|| format!("Task setup is not ready for world {}; see the Worlds guide", world.world.id))?;

    let run = client.evaluations().create(EvaluationCreateParams {
        task_suite_id: evaluation.task_suite_id.clone(),
        agents: vec!["billing-agent@1.0.0".into()],
        idempotency_key: "demo-run-1".into(),
        ..Default::default()
    }).await?;
    let run = client.evaluations().wait(&run.id, Duration::from_secs(600)).await?;
    if run.status != "succeeded" { return Err(format!("evaluation {}: {:?}; inspect its trials", run.id, run.status).into()); }
    for task in client.evaluations().results(&run.id).await?.task_results {
        println!("{} {} {:?}", task.task_id, task.passed, task.failed_scorers);
    }
    Ok(())
}
```

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, add this inside `main`, before `Ok(())`.
It reads every page:

```rust theme={null}
use chronicle_sdk::types::PageParams;

let mut page = client.evaluations().trials()
    .list(&run.id, PageParams { limit: Some(100), ..Default::default() })
    .await?;
loop {
    for trial in &page.items {
        println!("{} {} {} {:?}", trial.id, trial.agent, trial.task_id, trial.status);
        for score in &trial.scores { println!("{} {:?} {}", score.name, score.score, score.passed); }
    }
    if !page.has_next_page() { break; }
    page = page.get_next_page().await?;
}
```

## Errors and configuration

As an alternative inside `main`, replace the client initialization with this
builder. The `Duration` import is in the complete program above.

```rust theme={null}
let client = Chronicle::builder()
    .timeout(Duration::from_secs(30))
    .max_retries(2)
    .build()?;

match client.worlds().retrieve("<world-id>").await {
    Ok(world) => println!("{}", world.world.id),
    Err(e) => eprintln!("{:?} {} {:?}", e.status_code(), e, e.request_id()),
}
```

`wait` helpers take a `Duration`; reaching it returns a timeout error without
cancelling the run. Pages have `items`, `has_next_page()`, and
`get_next_page().await?`. See [Errors and retries](/api-reference/reliability).
