Conversation history
How agent chat history works, how to enable server-side persistence, and which authentication is required.
Agent chat history is stored in browser localStorage by default — no server setup needed. Enable server-side persistence when you want history shared across devices, preserved after a browser clear, or visible to multiple users.
How persistence works
- Persistence off — every conversation is local to the browser. Clearing browser data loses history.
- Persistence on, unauthenticated user — falls back to localStorage. Server stores require a user identity to scope history correctly.
- Persistence on, authenticated user — history is read and written to the configured server store.
Enable server persistence
Server-side persistence requires two things:
CHM_FEATURE_CONVERSATION_DB=truemust be set at build time (beforebun run build). The clientVITE_FEATURE_CONVERSATION_DBvalue is derived from it and baked into the bundle, so it cannot be changed at runtime. It also requires Clerk auth to be active (CHM_AUTH_PROVIDER=clerk).- A backend must be reachable at runtime.
CHM_FEATURE_CONVERSATION_DB=true
CHM_AUTH_PROVIDER=clerk
CHM_CLERK_PUBLISHABLE_KEY=pk_live_...# Runtime — select or force a backend:
CONVERSATION_STORE_BACKEND=postgres # or: agentstate, d1, memory
DATABASE_URL=postgresql://user:pass@host:5432/dbWhen CONVERSATION_STORE_BACKEND is not set, the server auto-selects the first available backend in the order described below.
Backend resolution order
When CONVERSATION_STORE_BACKEND is not set (or set to an unrecognized value), the server picks the first available backend in this order:
AgentState
Selected when AGENTSTATE_API_KEY is set and CONVERSATION_STORE_BACKEND is not d1, postgres, or memory.
Cloudflare D1
Selected when the CHM_CLOUD_D1 binding is present (Cloudflare Workers only).
Postgres
Selected when DATABASE_URL is set.
Memory
Fallback in development/CI. Conversations are lost on process restart.
You can force a specific backend by setting CONVERSATION_STORE_BACKEND to agentstate, d1, postgres, or memory.
AgentState self-host quickstart
AgentState is a cloud-hosted conversation store. It works on any deployment target (Cloudflare Workers, Docker, Kubernetes, Vercel).
Get an API key
Get an API key at agentstate.app.
Set build-time variables
The client VITE_* values are derived from these:
CHM_FEATURE_CONVERSATION_DB=true
CHM_AUTH_PROVIDER=clerk
CHM_CLERK_PUBLISHABLE_KEY=pk_live_...Set runtime variables
AGENTSTATE_API_KEY=as_live_...
# CONVERSATION_STORE_BACKEND=agentstate # optional — auto-selected when key is presentDeploy
No migrations needed — AgentState manages the schema.
Per-platform wiring:
Add the key via wrangler secret put:
wrangler secret put AGENTSTATE_API_KEY# wrangler.toml [vars]
CONVERSATION_STORE_BACKEND = "agentstate"docker run -d --name chmonitor -p 3000:3000 \
-e AGENTSTATE_API_KEY='as_live_...' \
-e CONVERSATION_STORE_BACKEND='agentstate' \
ghcr.io/chmonitor/chmonitor:vX.Y.Zkubectl create secret generic chmonitor-agentstate \
--from-literal=AGENTSTATE_API_KEY='as_live_...'# in ConfigMap
CONVERSATION_STORE_BACKEND: "agentstate"Request / response flow
On each request the server loads the thread from the store, runs the agent, then writes the updated thread back before streaming the response to the browser.
Auth requirement
Server stores require an authenticated user identity to namespace threads. If the request is unauthenticated, the server skips persistence and the browser keeps local history. To enable server persistence, configure an auth provider — see Authentication.
Deprecated alias
NEXT_PUBLIC_FEATURE_CONVERSATION_DB=true is accepted as an alias for VITE_FEATURE_CONVERSATION_DB=true but is deprecated. Do not use it for new deployments.