> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.nvidia.com/nemo/relay/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.nvidia.com/nemo/relay/_mcp/server.

# Rust Quick Start

This quick start shows the smallest Rust workflow that emits scope, tool, and LLM events.

## Choose an Install Path

Pick the installation path that matches whether you are using a published package or a
local checkout.

### Install from a Package Manager

Use the published crates when you are consuming a release:

```bash
cargo add nemo-relay@0.5.0
cargo add serde_json
cargo add tokio --features macros,rt-multi-thread
```

Install the published NeMo Relay CLI separately when you need coding-agent hook
and LLM gateway observability:

```bash
cargo install nemo-relay-cli@0.5.0
```

### Install from the Repository

Use a path dependency when your application is consuming a local checkout:

```toml
[dependencies]
nemo-relay = { path = "../NeMo-Relay/crates/core" }
serde_json = "1"
tokio = { version = "1", features = ["macros", "rt-multi-thread"] }
```

* `nemo-relay` is the core Rust runtime surface.
* `tokio` provides the async runtime used by the managed tool and LLM helpers in
  this quick start.
* `nemo-relay-adaptive` is a companion crate for adaptive runtime primitives and
  Redis-backed learning components when you need adaptive behavior later, but it
  is not required for this minimal direct-runtime example.
* `nemo-relay-cli` is a binary crate. Use `cargo install nemo-relay-cli@0.5.0`
  when you need the NeMo Relay CLI.

## Run One Scope, One Tool Call, and One LLM Call

The example below creates a scope, records an initialization mark, runs one
managed tool call, and runs one managed LLM call through the public Rust APIs.
Place it in `src/main.rs` in the same Cargo project where you added the
dependencies above, then run `cargo run`.

```rust
use nemo_relay::api::llm::{llm_call_execute, LlmCallExecuteParams, LlmRequest};
use nemo_relay::api::scope::{
    self, EmitMarkEventParams, PopScopeParams, PushScopeParams, ScopeAttributes, ScopeType,
};
use nemo_relay::api::subscriber::{deregister_subscriber, flush_subscribers, register_subscriber};
use nemo_relay::api::tool::{tool_call_execute, ToolCallExecuteParams};
use serde_json::json;
use std::sync::Arc;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    register_subscriber(
        "quickstart-printer",
        Arc::new(|event| {
            println!("{} {}", event.kind(), event.name());
        }),
    )?;

    let handle = scope::push_scope(
        PushScopeParams::builder()
            .name("demo-agent")
            .scope_type(ScopeType::Agent)
            .attributes(ScopeAttributes::empty())
            .data(json!({"binding": "rust"}))
            .build(),
    )?;

    scope::event(
        EmitMarkEventParams::builder()
            .name("initialized")
            .parent(&handle)
            .data(json!({"ok": true}))
            .build(),
    )?;

    let tool_result = tool_call_execute(
        ToolCallExecuteParams::builder()
            .name("search")
            .args(json!({"query": "hello"}))
            .func(Arc::new(|args| Box::pin(async move {
                Ok(json!({"echo": args["query"]}))
            })))
            .parent(handle.clone())
            .build(),
    )
    .await?;

    let llm_result = llm_call_execute(
        LlmCallExecuteParams::builder()
            .name("demo-provider")
            .request(LlmRequest {
                headers: Default::default(),
                content: json!({"messages": [{"role": "user", "content": "hi"}]}),
            })
            .func(Arc::new(|request| Box::pin(async move {
                Ok(json!({
                    "messages": request.content["messages"],
                    "ok": true
                }))
            })))
            .parent(handle.clone())
            .model_name("demo-model")
            .build(),
    )
    .await?;

    println!("{tool_result}");
    println!("{llm_result}");

    scope::pop_scope(PopScopeParams::builder().handle_uuid(&handle.uuid).build())?;
    flush_subscribers()?;
    let _ = deregister_subscriber("quickstart-printer")?;
    Ok(())
}
```

## What Success Looks Like

You should see:

* Event lines for the root scope, managed tool and LLM lifecycles, plus the
  `initialized` mark event
* `{"echo":"hello"}` from the tool call
* A final object containing `ok: true` and the echoed message payload from the
  LLM callback

Native subscriber delivery is asynchronous, so flush before checking subscriber
output. If you only see the returned JSON values and no event lines, the tool
and LLM callbacks ran but you did not verify instrumentation.

That tells you two things:

* The direct Rust runtime APIs ran successfully.
* Emitted events were observable through the subscriber system.

## What to Learn Next

Use these links to continue from the quick start into the core runtime concepts.

* Use [Scopes](/about-nemo-relay/concepts/scopes), [Middleware](/about-nemo-relay/concepts/middleware), [Subscribers](/about-nemo-relay/concepts/subscribers), and [Plugins](/about-nemo-relay/concepts/plugins) for the runtime model.