AI Agent
The AI Agent turns natural language into ClickHouse insights. Ask a question and the agent plans a series of read-only tool calls — querying system tables, inspecting schema, comparing hosts, spotting anomalies — then streams back a concise answer with optional inline charts.
The agent connects through the same ClickHouse host and user as the rest of the dashboard. Its visibility is bounded by the grants on that user. By default it only runs read-only queries. Keep control tools off and use a restricted ClickHouse user for safe exposure.
What it can do
Section titled “What it can do”| Category | What the agent covers |
|---|---|
| Schema exploration | List databases, tables, columns; explore tables relevant to a topic |
| Query analysis | Running, slow, failed, and expensive queries; EXPLAIN plans; optimization advice |
| System health | Server metrics, disks, errors, anomaly detection |
| Storage, merges & mutations | Part sizes, active merges, stuck mutations, merge throughput |
| Replication & cluster | Replication lag, queue, ZooKeeper/Keeper status, cluster topology |
| Schema & data-type advice | ORDER BY/keys, codecs, skip indexes, column type right-sizing |
| Tuning & upgrades | Hardware-based settings, version-upgrade guidance |
| Charts & visualization | Run SQL and render an interactive chart inline |
A small set of tools delivers this: dedicated primitives for the common reads, and the query tool plus an expert skill recipe for everything else. See Capabilities for the full list.
Skills — when a question needs domain depth, the agent loads a bundled expert guide (a skill) with copy-pasteable SQL recipes before answering. Eighteen skills cover data analysis, anomaly detection, query tuning, schema & data-type design, hardware tuning, version upgrades, concept explanations, incident response, plan-and-verify, and the core domains (replication, cluster, storage, migration, security, best practices, troubleshooting, system tables). Available skills: GET /api/v1/agent/skills.
Plan and verify — for multi-step tasks (incident triage, investigations, find-and-fix) the agent authors a live checklist with update_plan, keeps one step in progress, and verifies each result before stating it. Simple one-step questions skip the plan. See Capabilities for details.
Quick start
Section titled “Quick start”Set at minimum one environment variable:
LLM_API_KEY=your-provider-keyThen open /agents in the dashboard, pick a host, and start asking questions. The agent uses OpenRouter by default (https://openrouter.ai/api/v1) with the free model tier.
For full configuration options see Configuration.
Child pages
Section titled “Child pages”- Configuration — all env vars, providers, access control
- Capabilities — tools, skills, plan & verify, examples
- Conversation History — how history works, how to enable server persistence
- Store Backends — per-backend setup (D1, ClickHouse, Postgres, …)
- AgentState — managed/self-hosted persistence with AI enrichment (auto-titles, follow-ups)
Conversation history backends
Section titled “Conversation history backends”Agent chat history is persisted by a server-side ConversationStore chosen at deploy time by environment variables. Four backends are available:
| Backend | Selected when | Notes |
|---|---|---|
| Browser | conversation-DB feature flag off | localStorage only; history is per-browser, no server setup |
| AgentState | AGENTSTATE_API_KEY is set | Managed or self-hosted conversation-history service; optional AI enrichment |
| D1 | a Cloudflare D1 binding is present | Cloudflare-native SQLite |
| Postgres | DATABASE_URL is set | Any PostgreSQL-compatible database |
Selection priority when persistence is enabled: AgentState (if AGENTSTATE_API_KEY) → D1 (Cloudflare binding) → Postgres (DATABASE_URL) → Memory (last-resort, non-persistent). With the feature flag off, history stays in the Browser.
Server persistence requires VITE_FEATURE_CONVERSATION_DB=true and an authenticated user — configure Clerk (VITE_AUTH_PROVIDER=clerk + CLERK_SECRET_KEY) so history can be scoped per user. Unauthenticated sessions always fall back to browser history. See Authentication.
AgentState
Section titled “AgentState”AgentState is a conversation-history database-as-a-service for AI agents. Use it when you want managed (or self-hosted) persistence that survives browser clears and is shared across devices, plus optional AI enrichment — auto-generated conversation titles and follow-up question suggestions — and per-project analytics. It is self-hostable as a single Cloudflare Worker (see duyet/agentstate) and ships an npm SDK (@agentstate/sdk).
Per-user isolation is built in: each thread is namespaced by AgentState external_id as <userId>:<conversationId> and tagged user:<userId>, so one project key safely holds every user’s history without cross-talk.
Environment variables (all server-side):
| Variable | Required | Default | Purpose |
|---|---|---|---|
AGENTSTATE_API_KEY | to enable | — | as_live_... project key; its presence activates the AgentState backend |
AGENTSTATE_BASE_URL | no | https://agentstate.app/api | endpoint; override to point at a self-hosted instance |
AGENTSTATE_AI_ENRICH | no | false | enable auto-title + follow-up suggestions |
CONVERSATION_STORE_BACKEND | no | auto | force agentstate when a Cloudflare D1 binding is also present |
Still requires VITE_FEATURE_CONVERSATION_DB=true and a Clerk auth provider (VITE_AUTH_PROVIDER=clerk + CLERK_SECRET_KEY).
Setup (hosted)
Section titled “Setup (hosted)”- Sign in at agentstate.app and create a project.
- Create an API key — it is prefixed
as_live_and shown once, so copy it immediately. - Set it server-side:
VITE_FEATURE_CONVERSATION_DB=trueAGENTSTATE_API_KEY=as_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx## Optional: turn on auto-titles + follow-up suggestionsAGENTSTATE_AI_ENRICH=trueSetup (self-host)
Section titled “Setup (self-host)”Run your own AgentState Worker per duyet/agentstate, then point the dashboard at it:
VITE_FEATURE_CONVERSATION_DB=trueAGENTSTATE_API_KEY=as_live_your_self_hosted_keyAGENTSTATE_BASE_URL=https://your-agentstate-host/apiLocal dev
Section titled “Local dev”Against a locally running AgentState instance, use the seed test key:
VITE_FEATURE_CONVERSATION_DB=trueAGENTSTATE_BASE_URL=http://localhost:8787AGENTSTATE_API_KEY=as_live_TEST_KEY_FOR_LOCAL_DEV_ONLY_1234567890abVerify it’s active
Section titled “Verify it’s active”- Settings sidebar — the agent settings sidebar shows a read-only Conversation History section naming the active backend (e.g.
AgentState). - Endpoint —
GET /api/v1/conversations/backendreports the active backend and whether enrichment is available:
curl https://your-host/api/v1/conversations/backend## => { "backend": "agentstate", "supportsAiEnrichment": true }AI enrichment
Section titled “AI enrichment”When AgentState is active and AGENTSTATE_AI_ENRICH=true:
- Auto-title — new conversations get a concise generated title instead of a placeholder.
- Follow-ups — the chat suggests follow-up questions after a turn. The dashboard reads them from
GET /api/v1/conversations/$id/follow-ups.
With enrichment off, conversations persist normally but titles and follow-up suggestions are not generated.
AI Insights persistence
Section titled “AI Insights persistence”Separate from chat history, the AI Insights panel on /overview persists the
short observations it generates through its own pluggable store, mirroring the
conversation backends above. It is additive opt-in via one env var and
defaults to ClickHouse, so existing deployments are unaffected.
INSIGHTS_STORE_BACKEND=auto # auto | clickhouse | d1 | postgres | agentstate | memory| Value | Backend | Prerequisite |
|---|---|---|
auto (default) | ClickHouse monitoring_findings table | writable monitoring connection |
clickhouse | same as auto | writable monitoring connection |
d1 | Cloudflare D1 insights_findings table | INSIGHTS_D1 binding, else CONVERSATIONS_D1 |
postgres | Postgres insights_findings table | DATABASE_URL |
agentstate | AgentState State store | AGENTSTATE_API_KEY (+ optional AGENTSTATE_BASE_URL) |
memory | in-process (ephemeral) | — |
The D1, Postgres, and AgentState backends reuse the same env / bindings as the
conversation store. auto resolves to ClickHouse and never silently follows
other env; if an explicitly selected backend is missing its prerequisite, the
engine logs a warning and falls back to ClickHouse. GET /api/v1/insights/backend
reports the active backend ({ "backend": "d1" }), and the overview panel shows
a read-only “Stored in <backend>” footer.
HTTP API
Section titled “HTTP API”curl -X POST https://your-host/api/v1/agent \ -H "Content-Type: application/json" \ -H "Authorization: Bearer $AGENT_API_TOKEN" \ -d '{"message": "Which queries are running right now?", "hostId": 0}'hostId is a zero-based numeric index; defaults to 0.
MCP Server
Section titled “MCP Server”The dashboard exposes an MCP (Model Context Protocol) endpoint at /api/mcp. The same implementation runs in the standalone Cloudflare MCP Worker (apps/mcp). All tools are read-only by design — write and DDL statements are rejected.
Agent settings sidebar
Section titled “Agent settings sidebar”The MCP Servers section of the agent settings sidebar shows the built-in clickhouse-monitor server with its live connection status, tool count, resource count, and version — fetched from GET /api/v1/mcp/info. Click a server row to see the full tool and resource list. The built-in server is always enabled and cannot be toggled off. Custom server registration (“Connect new server”) is not yet available.
MCP tools
Section titled “MCP tools”| Tool | Purpose |
|---|---|
query | Execute a read-only SQL query (SELECT / WITH / DESCRIBE / EXPLAIN only) |
list_databases | List all databases with their engines and comments |
list_tables | List tables in a database with row counts and sizes |
get_table_schema | Get column definitions for a table including types, defaults, and comments |
get_metrics | Key server metrics: version, uptime, active connections, memory usage |
get_running_queries | Currently running queries ordered by elapsed time |
get_slow_queries | Slowest completed queries from the query log |
get_merge_status | Currently running merge operations with progress and elapsed time |
explore_table_schema | Three-mode schema exploration: databases → tables → full schema with relationships |
Read-only enforcement
Section titled “Read-only enforcement”The query tool — the only tool that accepts arbitrary SQL — validates every statement before execution via validateSqlQuery (@chm/sql-builder). It throws on any write or DDL statement and on dangerous ClickHouse commands. Allowed prefixes: SELECT, WITH (CTE), DESCRIBE, EXPLAIN. Rejected: INSERT, ALTER, DROP, CREATE, TRUNCATE, RENAME, DELETE, UPDATE, SYSTEM RELOAD/FLUSH/KILL/SHUTDOWN, GRANT, REVOKE, ATTACH, DETACH, KILL, SET, multi-statement payloads (; chaining), and dangerous table functions (remote(), url(), s3(), etc.).
All other MCP tools run fixed SELECT queries and pass readonly: '1' to the ClickHouse connection — they cannot issue writes regardless of the validator.
Security
Section titled “Security”- Use a read-only ClickHouse user scoped to the system tables the dashboard needs.
- Keep control tools off (
AGENT_ENABLE_CONTROL_TOOLS=false, the default) unless you trust the user and need kill/optimize. - On public deployments, require authentication:
CHM_FEATURE_AGENT_ACCESS=authenticated. - Keep LLM keys server-side — never in
VITE_*variables (those are baked into browser JS at build time).