Skip to content

Persistence

Without a database every store is in memory and everything ends with the process. That is deliberate — it makes the first agent work with no infrastructure — but it is not where you stop.

builder.AddAgentPrism()
.UsePostgreSql(connectionString); // AgentPrism.PostgreSql
Package Choose it when
AgentPrism.PostgreSql The default. The only one with vector search for knowledge
AgentPrism.SqlServer You already run SQL Server
AgentPrism.Sqlite One node, or a durable local development setup

All three implement the same store contracts and pass the same shared contract tests. Their operational limits differ: only PostgreSQL supports Knowledge, only PostgreSQL keeps the AOT promise, and SQLite is a single-node choice.

Binding from configuration is the usual shape:

.UsePostgreSql(builder.Configuration.GetSection(AgentPrismPostgreSqlOptions.SectionName))
appsettings.json
{
"AgentPrism": {
"PostgreSql": {
"ConnectionString": "",
"SchemaName": "agentprism",
"AutoApplyMigrations": true,
"CommandTimeoutSeconds": 30,
"EnableKnowledge": false
}
}
}
Provider Namespace Migration coordination
PostgreSQL Separate agentprism schema by default pg_advisory_lock, scoped to the schema
SQL Server Separate agentprism schema by default; your dbo objects stay untouched sp_getapplock, scoped to the schema
SQLite No schema support; agentprism_ table prefix by default A sidecar file lock next to the database

Rename SchemaName or TablePrefix when your conventions require it. A bare SQLite Data Source=:memory: connection is rejected because each opened connection would see a different database; use a shared in-memory URI for tests.

The SQL files ship embedded in the assembly and are applied when the application starts. Two properties make that safe with several instances starting at once:

  • The runner takes the provider-specific lock shown above, so instances serialize instead of racing.
  • Each applied file’s SHA-256 is recorded. If the content later differs from what was applied, startup fails loudly rather than running against a schema that is not what the code expects.

Set AutoApplyMigrations = false when schema changes are their own deployment step. AgentPrism then verifies but does not write. The diagnostics endpoint can report whether the schema is current, but it is deliberately not mapped by default because it exposes setup details:

app.MapAgentPrism("/agentprism", options =>
{
options.EnableDiagnosticsEndpoint = true;
});

After that opt-in, GET /agentprism/api/diagnostics is an Admin surface and still passes through the configured access layers.

Runs, events, and tool calls survive restarts, so the console shows real history rather than the current process. Sessions can be read back as chat history rather than an opaque blob — which is also what makes branching a conversation possible. Queued runs, schedules, evals, experiments, and quotas all become usable, since they depend on state outliving a request.

A recorded run is data, and recorded runs accumulate. Retention policies set an age or row limit per target — run events, tool calls, traces, jobs, webhook deliveries, eval results, checkpoints, and more.

Database policies take precedence. When no database policy exists and AgentPrism:Retention:Enabled is true, configuration falls back to built-in target defaults, such as 30 days for run events and 14 days for spans. With retention disabled, nothing is deleted. An archive: true policy also deletes nothing when no IArchiveSink is registered; data loss is the failure mode the worker avoids.

Cleanup runs through the job queue. Preview a policy before you execute it:

Terminal window
curl 'http://localhost:5081/agentprism/api/retention/preview'
curl -X POST 'http://localhost:5081/agentprism/api/retention/run'

A durable audit_log can be verified: GET /api/audit/verify walks a hash chain and reports whether any entry was altered or deleted after it was written. And because sessions, runs, and conversations are real rows now, a data subject’s content can be found and erased by identity, not just aged out — see Data subject rights.