Getting started
Your first agent
Run a complete graph without credentials, then add a model call.
Start in the hello-polaris project from Installation. First check the execution path without a model or network request.
1. Run one system
Section titled “1. Run one system”Replace src/main.rs with this complete program:
use polaris_ai::graph::{Graph, GraphExecutor};use polaris_ai::system::{server::Server, system};
#[system]async fn greet() -> String { "Hello from Polaris!".to_owned()}
#[tokio::main]async fn main() -> Result<(), Box<dyn std::error::Error>> { let mut server = Server::new(); server.finish().await?; let mut graph = Graph::new(); graph.add_system(greet); assert!(graph.validate().is_ok(), "graph must be valid"); let mut ctx = server.create_context(); let result = GraphExecutor::new() .execute(&graph, &mut ctx, None, None) .await?; println!( "{}", result.output::<String>().expect("greet returns a String") ); Ok(())}cargo runAfter compilation, the program prints:
Hello from Polaris!#[system] adapts greet into a graph system. graph.add_system(greet) adds one step. The executor runs it and returns its typed output. graph.validate() checks the graph structure before execution.
server.finish().await? completes plugin startup. It is asynchronous: calling finish() without awaiting it does not initialise your server.
2. Add a model call
Section titled “2. Add a model call”Enable the anthropic feature as shown in Installation. Replace src/main.rs with this complete program:
use polaris_ai::graph::{Graph, GraphExecutor};use polaris_ai::models::{AnthropicPlugin, ModelRegistry, ModelsPlugin};use polaris_ai::system::param::Res;use polaris_ai::system::prelude::SystemError;use polaris_ai::system::{server::Server, system};
#[system]async fn ask_llm(registry: Res<ModelRegistry>) -> Result<String, SystemError> { let model_id = std::env::var("POLARIS_MODEL") .unwrap_or_else(|_| "anthropic/claude-sonnet-5-5".to_owned()); let llm = registry .llm(&model_id) .map_err(|err| SystemError::ExecutionError(err.to_string()))?; let response = llm .builder() .system("Answer in one sentence.") .user("What is Rust's ownership model?") .generate() .await .map_err(|err| SystemError::ExecutionError(err.to_string()))?; Ok(response.text())}
#[tokio::main]async fn main() -> Result<(), Box<dyn std::error::Error>> { let mut server = Server::new(); server .add_plugins(ModelsPlugin) .add_plugins(AnthropicPlugin::from_env("ANTHROPIC_API_KEY")); server.finish().await?; let mut graph = Graph::new(); graph.add_system(ask_llm); assert!(graph.validate().is_ok(), "graph must be valid"); let mut ctx = server.create_context(); let result = GraphExecutor::new() .execute(&graph, &mut ctx, None, None) .await?; println!( "{}", result.output::<String>().expect("ask_llm returns a String") ); Ok(())}Set ANTHROPIC_API_KEY in the environment using your normal secret-management method, then run cargo run again. This makes a billable model request. The result should be a one-sentence answer; wording will vary.
The default is Claude Sonnet 5.5. Choose another model available to your account without editing the code:
POLARIS_MODEL=anthropic/claude-opus-5-5 cargo runanthropic/ selects the registered provider; the rest is the provider’s model ID. See Anthropic’s current model list. To use a different provider, enable its Cargo feature, register its plugin and configure its credentials too.
Authentication errors indicate a missing or invalid key; a model-access error is a separate issue. The pinned Polaris version may not have pricing entries for newer models, so missing cost estimates do not mean a request is free.
What to change next
Section titled “What to change next”- Add a second system that consumes the previous output with
Out<String>: Systems. - Run a complete tool-using agent: ReAct CLI.
- Test your graph without paid model calls: Testing agents.
This first example is intentionally a single model invocation. The graph becomes a multi-step agent when you add tool use, branching, memory and a stopping condition.
Copyright © 2026, Radiant AI Limited.