# Sessions and persistence

> Run multiple turns, retain state, and save or restore selected resources.

A session owns an agent’s execution context across turns. Start with `InMemoryStore`; use `FileStore` when state must survive process restarts. Persistence stores only registered serializable resources, not an arbitrary snapshot of every object in memory.

## Initialize the server

This setup belongs inside an async function returning `Result`. Add your agent’s model and tool plugins as needed.

```rust
use std::sync::Arc;
use polaris_ai::plugins::PersistencePlugin;
use polaris_ai::sessions::{InMemoryStore, SessionsAPI, SessionsPlugin};
use polaris_ai::system::server::Server;


let mut server = Server::new();
server
    .add_plugins(PersistencePlugin)
    .add_plugins(SessionsPlugin::new(Arc::new(InMemoryStore::new())));
server.finish().await?;
let sessions = server.api::<SessionsAPI>().expect("SessionsPlugin required").clone();
```

`finish()` builds the server without entering its long-running service loop. Use `server.cleanup().await` when your application finishes. `run().await` is for services that should wait for shutdown, so do not put your first turn after that call.

## Register an agent and create a session

The following assumes `MyAgent` implements [Agent](/docs/polaris/core-concepts/agents.md). The string used for `AgentTypeId` must equal its `name()` return value.

```rust
use polaris_ai::agent::Agent;
use polaris_ai::sessions::{AgentTypeId, SessionId};


let agent = MyAgent;
let agent_type = AgentTypeId::from_name(agent.name());
sessions.register_agent(agent)?;
let id = SessionId::new();
sessions.create_session(sessions.create_context(), &id, &agent_type)?;
```

Current session creation takes an owned `SystemContext`, not `&Server`. `sessions.create_context()` uses the factory captured at startup. `create_session_with(context, &id, &agent_type, initializer)` inserts application configuration before `Agent::setup` runs.

Registration validates the graph. Missing agent types, invalid graphs and setup failures return `SessionError` rather than creating a usable session.

## Execute turns

```rust
let result = sessions.process_turn(&id).await?;
println!("{} nodes in {:?}", result.nodes_executed(), result.duration());
```

Use `process_turn_with` to supply per-turn input. Here `UserInput` is a local resource expected by your agent:

```rust
sessions.process_turn_with(&id, |ctx| {
    ctx.clear_outputs();
    ctx.insert(UserInput("Summarize this document".into()));
}).await?;
```

Define `UserInput` and implement `LocalResource` in your application. For IO-based agents, inject `UserIO` instead. A session serializes concurrent access to its context. `try_process_turn` is available when you would prefer a busy error over waiting.

For short-lived work, `scoped_session` returns a `SessionGuard` that removes its live session when dropped. `run_oneshot` runs one turn and extracts a typed result. See the [public session reference](https://github.com/RadiantAILabs/polaris/blob/main/docs/reference/sessions.md/) for these patterns.

## Checkpoints and rollback

Automatic checkpointing is enabled by default; `without_auto_checkpoint()` disables it. Checkpoints are in-process serialized snapshots for rollback. Saving to a backing store is a separate operation.

```rust
let turn = sessions.checkpoint(&id).await?;
sessions.rollback(&id, turn).await?;
```

Rollback restores registered persisted resources and discards newer checkpoints. Reinsert non-persisted configuration or handles with `with_context`, then call `setup_session` if the agent needs initialization again. Rollback does not undo external tool side effects such as sending a message or editing a remote record.

## Register what should persist

A persistent resource implements `LocalResource`, `Storable`, `Serialize` and `Deserialize`. Register its serializer with `PersistenceAPI::register::<T>(plugin_id)` as part of plugin setup. Choose a stable storage key and schema version. The [persistence API reference](https://github.com/RadiantAILabs/polaris/blob/5ff84646db63589d58bf87956976d749b8c754de/crates/polaris_core_plugins/src/persistence.rs) contains a complete serializer-registration example.

Do not expect secrets, network clients or unregistered state to reappear after restoration. Use the initializer on `resume_session_with` to supply those runtime dependencies.

## Save and resume

```rust
sessions.save_session(&id).await?;
// In a new process with the same store and registered agent type:
sessions.resume_session(sessions.create_context(), &id).await?;
```

`resume_session_with(context, &id, initializer)` runs the initializer after deserialization and before the agent’s setup. Handle a missing saved session separately from a storage or schema error; do not silently replace every failed restore with an empty session.

To use disk storage, replace `InMemoryStore::new()` with `FileStore::new("data/sessions")`. The `file-store` feature is enabled by default; add it explicitly if you disabled default features. `SessionStore` also supports custom backends through `save`, `load`, `delete` and `list` methods.

Next: [serve sessions over HTTP](/docs/polaris/provided-plugins/http-api.md).
