Storage
Introduction
Section titled “Introduction”Storage exists on both sides. The server keeps conversations, checkpoints, usage and more behind ports, with PostgreSQL as the default backend. The client keeps small things, such as unsent drafts and the theme, in a KeyValueStorage that you supply.
Keeping drafts on the client
Section titled “Keeping drafts on the client”You supply three async methods. The kit’s stores keep drafts, the theme preference, the last open conversation and finished presentation decks in it. The demo web app backs it with localStorage:
import { draftStore, resilientStorage, type KeyValueStorage } from '@pilotoo/chat-core';
const local: KeyValueStorage = { getItem: async (key) => localStorage.getItem(key), setItem: async (key, value) => localStorage.setItem(key, value), removeItem: async (key) => localStorage.removeItem(key),};
export const drafts = draftStore(resilientStorage(local), { prefix: 'myapp.pilotoo.' });createMemoryStorage() serves a host with nothing to persist to. On React Native, back the same interface with your own storage library.
resilientStorage never throws or rejects. A failing storage, such as a private window that blocks localStorage, falls back to memory for the session, so only persistence is lost.
With @pilotoo/ui/chat, ChatProvider takes storage and storagePrefix for the last open conversation and defaults to localStorage.
Replacing a server store
Section titled “Replacing a server store”Each server port has a default backend, and you replace any of them through the option of the same name in PilotooModule.forRoot. This server keeps conversations in its own database:
PilotooModule.forRoot({ env: process.env, conversationStore: myConversationStore,});If you supply every persistence port yourself, no database connection is made. See Running without PostgreSQL.
On a user’s own machine the local backend keeps the same data in one SQLite file instead.
Options
Section titled “Options”Client stores
Section titled “Client stores”| Store | Holds |
|---|---|
draftStore |
Unsent composer text per conversation (NEW_CONVERSATION_DRAFT for a new one) |
themePreferenceStore |
system, light or dark |
lastConversationStore |
The conversation to reopen |
presentationDeckStore |
Finished presentation decks |
All take { prefix }; every key carries it.
Server stores
Section titled “Server stores”The PostgreSQL tables are created on first use, in the pilotoo_app schema. Nothing needs a manual migration step.
| Data | Option | Default backend | Tables |
|---|---|---|---|
| Conversation catalog | conversationStore |
PostgreSQL | conversations |
| Agent definitions (the tenant’s own agents) | agentDefinitionStore, agentDefinitionSource |
PostgreSQL | agent_definitions, tenant_provisioning |
| Run checkpoints | checkpointer |
PostgreSQL | LangGraph’s checkpoint tables, in the pilotoo_langgraph schema |
| Run events | runEventStorage |
PostgreSQL | run_events |
| Background subagent tasks | backgroundTaskStorage |
PostgreSQL | background_tasks |
| Token usage | usageStore |
PostgreSQL | usage_calls |
| Schedules and their runs | scheduleStorage |
PostgreSQL | schedules, schedule_runs |
| Uploaded files | attachmentStore |
S3-compatible bucket when ATTACHMENTS_S3_BUCKET is set, otherwise off |
none: objects in the bucket |
Provider, profile, system-agent and skill definitions are files under the configuration folder, not database rows. See Models, Agents and Skills. A few small bookkeeping tables, such as seed_upgrades, also live in pilotoo_app; they are internal.
Preview features
Section titled “Preview features”These stores belong to features in preview. See Workflows and Connections.
| Data | Option | Default backend | Tables |
|---|---|---|---|
| Workflow definitions, runs and run events | workflowStorage |
PostgreSQL | workflows, workflow_runs, workflow_run_events |
| Connections, pending OAuth states, tenant provider configs, audit log and locks | ConnectionStorage port |
PostgreSQL | connections, connection_oauth_states, connection_provider_configs, connection_audit, connection_locks |
Next steps
Section titled “Next steps”- Choose the server’s database setup in The server.
- Run without PostgreSQL: the local backend.