Core concepts
Resources
Resources are shared state that systems read and write through typed parameters.
Resources are shared state that systems read and write. Every piece of data a system needs — configuration, conversation history, the output of a previous system — is a resource that the framework injects as a typed parameter.
use polaris_ai::system::resource::{GlobalResource, LocalResource};use polaris_ai::system::param::{Res, ResMut};use polaris_ai::system::system;
#[system]async fn greet(config: Res<AppConfig>, mut memory: ResMut<ContextManager>) { memory.messages.push(format!("Hello from {}", config.agent_name));}You declare what you need, and the framework provides it. There is no manual lookup, no string keys, and no runtime casting.
Global and local resources
Section titled “Global and local resources”Resources fall into two categories based on their lifetime and mutability.
Global resources live for the lifetime of the server. They are read-only and shared across all execution contexts. Configuration, model registries, and tool registries are typical global resources.
Local resources are created fresh for each execution context. They are mutable and isolated, so concurrent agent executions never interfere with each other. Conversation history and loop state are typical local resources.
| Scope | Marker trait | Lifetime | Access |
|---|---|---|---|
| Global | GlobalResource |
Server | Res<T> (read-only) |
| Local | LocalResource |
Per-context | Res<T> or ResMut<T> |
Defining resources
Section titled “Defining resources”A resource is any type that implements a marker trait. For a global resource, implement GlobalResource. For a local resource, implement LocalResource.
use polaris_ai::system::resource::{GlobalResource, LocalResource};
struct AppConfig { agent_name: String, model_id: String,}
impl GlobalResource for AppConfig {}
struct ContextManager { messages: Vec<String>,}
impl LocalResource for ContextManager {}
impl ContextManager { fn new() -> Self { Self { messages: Vec::new() } }}The marker traits do not require methods. The marker traits exist only to enforce the access rules at the type level: you cannot accidentally take ResMut<AppConfig> on a global resource, and you cannot share a local resource across contexts.
Registering resources
Section titled “Registering resources”You register resources on the Server before execution starts. Global resources are inserted directly. Local resources are registered with a factory function that produces a fresh instance for each context.
use polaris_ai::system::server::Server;
let mut server = Server::new();
server.insert_global(AppConfig { agent_name: "research-agent".into(), model_id: "claude-sonnet-4-20250514".into(),});
server.register_local(ContextManager::new);Plugins typically handle registration in their build() method, so you rarely call these methods directly unless you are writing a plugin or setting up a server by hand.
Reading resources with Res and ResMut
Section titled “Reading resources with Res and ResMut”Systems declare resource dependencies as function parameters. Res<T> provides read-only access and walks up the context hierarchy to find the resource — it can reach global resources from any context. ResMut<T> provides mutable access but is scoped to the current context only.
use polaris_ai::system::system;use polaris_ai::system::param::{Res, ResMut};
#[system]async fn act( config: Res<AppConfig>, mut memory: ResMut<ContextManager>,) -> String { let prompt = format!("{}: processing {} messages", config.agent_name, memory.messages.len()); memory.messages.push(prompt.clone()); prompt}Both Res<T> and ResMut<T> dereference to T, so you access fields and methods directly.
Reading system outputs with Out
Section titled “Reading system outputs with Out”When a system returns a value, the next system in the graph can read it with Out<T>. The type parameter matches the return type of the preceding system.
use polaris_ai::system::param::Out;
struct AnalysisResult { summary: String,}
#[system]async fn analyze(config: Res<AppConfig>) -> AnalysisResult { AnalysisResult { summary: format!("Analysis by {}", config.agent_name), }}
#[system]async fn report(result: Out<AnalysisResult>, mut memory: ResMut<ContextManager>) { memory.messages.push(result.summary.clone());}Outputs belong to the current context and do not resolve through parent scopes. Out<T> reads the most recently stored output of type T, not necessarily the immediately preceding node. Clear stale outputs with ctx.clear_outputs() when reusing a context for a new independent turn. Successful execution moves the last output into ExecutionResult; it does not clear every typed output slot.
Error outputs with ErrOut
Section titled “Error outputs with ErrOut”When a fallible system fails, recovery systems on an error edge can read the error context with ErrOut<T>. This is covered in detail in Error handling and retries.
Putting it together
Section titled “Putting it together”Here is a complete example that defines both resource types, registers them, and uses them in systems that form a sequential pipeline.
use polaris_ai::system::resource::{GlobalResource, LocalResource};use polaris_ai::system::param::{Res, ResMut, Out};use polaris_ai::system::server::Server;use polaris_ai::system::system;
struct AppConfig { agent_name: String,}
impl GlobalResource for AppConfig {}
struct ReactState { is_complete: bool,}
impl LocalResource for ReactState {}
#[system]async fn initialize(config: Res<AppConfig>) -> String { format!("Starting {}", config.agent_name)}
#[system]async fn process( greeting: Out<String>, mut state: ResMut<ReactState>,) { state.is_complete = true;}
let mut server = Server::new();server.insert_global(AppConfig { agent_name: "my-agent".into() });server.register_local(|| ReactState { is_complete: false });The initialize system reads the global configuration through Res<AppConfig>. The process system reads the output of initialize through Out<String> and mutates the local state through ResMut<ReactState>. The global resource is shared and immutable; the local resource is private to this execution context and freely mutable.
For how resources are organized into parent-child scopes, see Context hierarchies. For the graph that connects these systems, see Graphs.
Copyright © 2026, Radiant AI Limited.