Storage and durability
Choose a runtime store, understand its guarantees, and integrate Noir with an existing database without surrendering ownership.
Noir's database field accepts a RuntimeStore, not a raw ORM client. The distinction matters because reliable agents need protocol operations in addition to ordinary queries.
What the core store persists
- inbound event deduplication and queue state
- renewable worker leases and retry availability
- bounded conversation history
- successful tool-step checkpoints
- pending and decided approvals
- outbound queue state and provider delivery receipts
The interface is deliberately provider-neutral. Your implementation can use Drizzle, Prisma, Kysely, raw SQL, DynamoDB, SQLite, or another transactional store.
Local development
memoryStore() is zero-setup and useful for tests or a single local process. State disappears on restart and cannot coordinate replicas.
import { memoryStore } from '@noir-agent/agent/store/memory'
const database = memoryStore()Included Postgres store
import { postgresStore } from '@noir-agent/agent/store/postgres'
const database = postgresStore(process.env.DATABASE_URL!)
await database.migrate()You can pass the same postgres client used by the rest of the application. The store creates Noir's tables only when migrate() is called.
Bring your own ORM
Keep your schema and client in your repository, then implement the RuntimeStore methods using your transaction and migration conventions. The contract requires atomic ownership checks for claims and decisions. enqueueInbound and appendMessage must be idempotent. saveToolStep must not overwrite a successful checkpoint with a competing replay.
Optional feature stores
Schedules, tasks, sandboxes, connections, secrets, traces, usage, snapshots, quality, and other stateful capabilities expose their own store contracts. This keeps the core store small and lets applications adopt features independently. The included Postgres implementations can share one SQL client.
Migration and shutdown
Run migrations before agent.start(), preferably in one explicit startup capability. Close a shared SQL client exactly once after dependent stores stop. A schema change and its migration should ship together.