Skip to content
sdk

Rust

Async-first. tokio + reqwest with rustls. Not in the Argand workspace, so cargo can pull it without compiling the rest of the engine.

Install

cargo add argand-client --git ssh://git@git.argand.org/nicweyand/argand.git

Or pin a revision in Cargo.toml:

[dependencies]
argand-client = { git = "ssh://git@git.argand.org/nicweyand/argand.git", branch = "main" }

Source-only from Forgejo. crates.io publish deferred to launch (mid-2026).

Hello world (anonymous)

src/main.rs rust
use argand_client::ArgandClient;

#[tokio::main]
async fn main() -> argand_client::Result<()> {
    let client = ArgandClient::new()?;
    let response = client.search("rust async runtime", 1, 10).await?;
    for hit in &response.results {
        println!("{}. {} -> {}", hit.rank, hit.title, hit.url);
    }
    Ok(())
}

Method surface

  • client.search(query, page, limit).awaitResult<SearchResponse>
  • client.lucky(query).awaitResult<String> (Location URL)
  • client.fetch(...) / client.cite(...) — return ArgandError::NotImplemented until v2.

Auth

let client = ArgandClient::with_api_key("your-argand-api-key")?;

Self-hosted + builder

use std::time::Duration;
use argand_client::{ArgandClient, RetryPolicy};

let client = ArgandClient::builder()
    .base_url("https://argand.example.org")
    .api_key("your-argand-api-key")
    .connect_timeout(Duration::from_secs(5))
    .request_timeout(Duration::from_secs(20))
    .retry(RetryPolicy {
        max_attempts: 5,
        base_delay: Duration::from_millis(100),
        max_delay: Duration::from_secs(4),
    })
    .build()?;

Retry semantics

Default: 3 attempts, 250ms → 8s exponential backoff. 429 and 5xx retry. Retry-After (seconds form) is honored. 401 / 403 raise ArgandError::Auth immediately and never retry.

Error types

ArgandError variants:

  • Auth { status, message } — 401/403, never retried.
  • RateLimit { status, retry_after, message } — 429 after retries.
  • Server { status, message } — 5xx after retries.
  • Timeout(message) — transport timeout.
  • Transport(message) — DNS / TLS / connection.
  • Protocol(message) — body doesn't match the contract.
  • NotImplemented(_) — v2-reserved (fetch, cite).
  • Unexpected { status, message } — anything that doesn't bucket above.
  • InvalidUrl(message) — URL construction failed.
use argand_client::{ArgandClient, ArgandError};

let client = ArgandClient::new()?;
match client.search("rust async runtime", 1, 10).await {
    Ok(resp) => println!("{} hits", resp.results.len()),
    Err(ArgandError::RateLimit { retry_after, .. }) => {
        println!("backoff exhausted; retry after {retry_after:?}");
    }
    Err(ArgandError::Auth { .. }) => println!("bad api key"),
    Err(ArgandError::Server { status, .. }) => println!("server {status}"),
    Err(ArgandError::NotImplemented(_)) => println!("v2-reserved"),
    Err(e) => return Err(e),
}