Overview
This example is a chat agent that answers natural-language questions about the data in a ClickHouse Cloud database. The agent discovers the schema, writes ClickHouse SQL, runs it through the official ClickHouse Node.js client, and streams back answers with markdown tables. Trigger.dev handles the chat session, turn loop, streaming, and resumability — the whole agent is onechat.agent() call and three tools.
Tech stack:
- Trigger.dev AI chat for the agent session, turn loop, and streaming
- ClickHouse Node.js client (
@clickhouse/client) for queries over HTTPS - AI SDK with Anthropic Claude for the model and tool calling
- Schema discovery tools:
listTablesreads table names, engines, and row counts fromsystem.tables;describeTablereturns column names and types using a boundIdentifierquery param, so table names are never interpolated into SQL strings - Read-only query tool:
runQueryaccepts SELECT-style statements only, enforced in code and backed by ClickHouse settings —readonly=2, a 1,000-row result cap, and a 30 second execution timeout - Self-correcting SQL: query errors are returned to the model as tool output, so the agent reads the ClickHouse error, fixes its SQL, and retries
- Single environment variable: the ClickHouse connection is one
CLICKHOUSE_URLwith the credentials embedded, set in the Trigger.dev dashboard
GitHub repo
View the ClickHouse chat agent repo
Click here to view the full code for this project in our examples repository on GitHub. You can
fork it and use it as a starting point for your own project.
How it works
The agent
The agent is defined withchat.agent(). Tools are declared on the config so tool results survive history re-conversion across turns, and the run function returns a streamText() call:
trigger/clickhouse-agent.ts
The query tool
runQuery guards against writes twice: a statement allowlist in code, and ClickHouse settings on the request itself. Errors are returned to the model instead of thrown, which is what makes the agent self-correct:
trigger/clickhouse-agent.ts
Connecting to ClickHouse
The client reads a singleCLICKHOUSE_URL environment variable — the HTTPS endpoint with credentials embedded — set in the Trigger.dev dashboard on the Environment Variables page:
trigger/clickhouse-agent.ts
Chatting with the agent
Runnpx trigger.dev@latest dev, then open the AI agents page in the dashboard and chat with clickhouse-agent in the playground. With a dataset like NYC Taxi loaded, asking “What were the top 5 busiest pickup days?” produces a listTables call, a describeTable call, a SQL aggregation, and a streamed markdown table of results.
Relevant code
- Agent + tools: trigger/clickhouse-agent.ts: the
chat.agent()definition, the three tools, the read-only guards, and the ClickHouse client - Trigger config: trigger.config.ts: project config pointing at the
trigger/directory
Learn more
AI chat overview
How chat agents, sessions, and the turn loop work.
Tools
Declaring tools on your agent and how they persist across turns.

