# Macrofold Rust SDK

Typed asynchronous resource methods and resumable run streams using Reqwest and Tokio.

Works with [Macrofold Cloud](https://staging.macrofold.ai/docs/raw/cloud.md) and [self-hosted deployments](https://staging.macrofold.ai/docs/raw/self-hosting.md). Use the same resource methods with the origin and API key for your deployment. For help integrating an existing application, use the [coding-agent setup prompt](https://staging.macrofold.ai/docs/raw/agents.md).

## Install from source

Add the local crate to your application's `Cargo.toml`:

```toml
[dependencies]
macrofold = { path = "/absolute/path/to/Macrofold/sdk/rust" }
tokio = { version = "1", features = ["macros", "rt-multi-thread"] }
```

Tested with Rust 1.94.1. Native TLS is the default; select `default-features = false, features = ["rustls"]` to use Rustls.

## Start a run

Set `MACROFOLD_API_KEY` to a scoped dashboard key and copy a project ID. Select a harness and model directly; no saved agent or session is required. This example uses Codex and OpenAI’s GPT-5.4 mini. The model catalog determines the provider. Managed execution uses your credits; use `fixture-model` with the local simulator for free development.

```rust
use macrofold::{Macrofold, ClientError, models::RunCreate};
use std::io::Write;

#[tokio::main]
async fn main() -> Result<(), ClientError> {
    let client = Macrofold::new()?;
    let mut input = RunCreate::new("Create hello.txt containing Hello world.".into());
    input.project_id = Some("YOUR_PROJECT_ID".parse()?);
    input.harness = Some(macrofold::models::run_create::Harness::Codex);
    input.model = Some("gpt-5.4-mini".into());
    input.billing_mode = Some(macrofold::models::run_create::BillingMode::Managed);
    let run = client.runs().create(input).await?;
    let id = run.run_id.to_string();
    client.runs().stream_text(&id, "0", |text| {
        print!("{text}");
        std::io::stdout().flush().expect("stdout write failed");
        true
    }).await?;
    Ok(())
}
```

The default origin is `https://app.macrofold.ai`. The builder supports explicit keys and custom origins; missing or empty credentials return an error:

```rust
let client = Macrofold::builder()
    .base_url("http://localhost:3210")
    .api_key("YOUR_LOCAL_API_KEY")
    .build()?;
```

## Resource methods

`client.runs().get(id).await?` fetches status; `client.runs().cancel(id).await?` cancels a job. Query and header parameters use named structs in `macrofold::resources`; for default pagination use `client.projects().list(Default::default()).await?`.

[Every public operation](https://staging.macrofold.ai/docs/raw/sdk/reference.md) has a resource method. Request/response models live in `macrofold::models`. The API validates conditional selectors, ownership, and model/BYOK configuration. Money remains strings.

## Recovery and streaming

Mutations generate idempotency keys automatically. REST calls make one attempt. Use `resource.with_options(RequestOptions { idempotency_key: Some(key), ..Default::default() })` to persist your own identity, or set `organization` to select a user membership. `ClientError` can be downcast to `RequestError`, which retains the original generated error and `idempotency_key`. Inspect remote state and retry the same body and key after an uncertain outcome.

`stream_text()` emits only assistant text fragments. `events()` exposes structured events, and `stream()` remains available. Streams reconnect from the last delivered cursor and suppress duplicates. The callback returns `true` to continue or `false` to detach. Dropping the future also detaches; neither cancels the remote job. Save the event sequence for process restarts, and use `runs().cancel()` when you mean to stop the agent.

The resource's `organization` option applies to stream connections, reconnects, and history checks without changing other resources.

`workspaces().write_file()` uploads a `PathBuf` with `WriteFileParams` containing its remote path and observed revision. `read_file()` returns a Reqwest response; consume its bytes or stream and inspect headers for revision metadata.

## Wait for the complete response

```rust
let result = client.runs().wait_with_timeout(&id, std::time::Duration::from_secs(300)).await?;
println!("{:?} {:?}", result.output_text, result.checkpoint_id);
```

`wait(&id)` has no overall timeout. It polls until execution and persistence finish and returns the typed result; optional Git synchronization is separate. `wait_with_timeout` raises a `WaitTimeoutError` containing `run_id`, and drops in-flight local work. Dropping either future detaches without cancelling execution.

Both text streaming and waiting return a `ClientError` that can be downcast to `RunFailedError` for failed, cancelled, timed-out, or unsuccessfully persisted runs. It includes `run_id`, typed `status`, `failure_code`, and the full typed `result`. Partial text may precede failure; transport/authentication errors retain their existing types. `Macrofold` and `Client` refer to the same client type.

## Read persisted files

```rust
client.runs().wait(&run.run_id.to_string()).await?;
let response = client.workspaces().read_file(
    &run.workspace_id.to_string(),
    macrofold::resources::ReadFileParams {
        path: "hello.txt".into(),
        download: None,
    },
).await?;
let content = response.bytes().await?;
println!("{}", std::str::from_utf8(&content)?);
```

Keep the returned bytes for binary files; consume or drop the response to release its resources.

Direct reads return the complete file up to 4 MiB. During execution they use the last published revision. See [reading files](https://staging.macrofold.ai/docs/raw/workspaces/read-files.md) for HTTP usage, larger downloads, permissions, and errors.

## Advanced access

Generated free functions in `macrofold::apis` remain available using `client.configuration()`. Those low-level mutation calls require explicit idempotency keys. Constructors require HTTPS except on loopback hosts and refuse redirects. For refreshed OAuth credentials, construct a new client with the renewed token.

See [API conventions](https://staging.macrofold.ai/docs/raw/api/conventions.md) for pagination, permissions, and asynchronous work.

## Choose a harness

The same run methods support `codex`, `claude-code`, `opencode`, `hermes`, `deepseek`, and `pi`. Select a compatible model from the catalog. See [harness capabilities and examples](https://staging.macrofold.ai/docs/raw/harnesses.md).
