Claude Agent SDK · Python · DuckDB · read-only
Prism
Plain English in, verified SQL and a chart out
A data analyst agent that turns a question into SQL, runs it in a sandbox, checks the result against the question it was asked, and renders a chart. If the query returns something implausible it re-queries instead of charting nonsense.
What makes it special
read → run → check → chart- 01Read
Reads the schema before it writes SQL
Prism is told never to guess a column name, so it starts by pulling tables, types, row counts and the notes a type cannot carry, like refunds living on the order rather than the line. If a query still hits a missing column, the error comes back with a hint to re-read the schema, not to try another guess.
describe_schema()agents/prism-analyst/prism/warehouse.py
- 02Run
Read-only, three layers deep
A parser refuses anything but a single SELECT before DuckDB sees it, and the connection itself is opened read-only in case that parser has a bug. The agent has no shell, file or web tools at all, so the only way to the data is one SELECT at a time.
run_sql()agents/prism-analyst/prism/warehouse.pyagents/prism-analyst/prism/analyst.py
- 03Check
Checks the answer against the question
Every result comes back with computed warnings: a group key that never reaches the aggregate, a rate landing exactly on ½, a denominator under 25. That is how it catches a tidy 50% retention rate that is really 4,312 orders divided by 2,156 customers.
inspect_result()agents/prism-analyst/prism/selfcheck.py
- 04Chart
Won’t chart a number it doesn’t trust
It is instructed to say so and re-query rather than plot a result it distrusts. The chart tool also refuses forms that mislead: a line across categories with no order, a donut with negative or more than six slices, a fourth series the validated palette has no colour for.
render_chart()agents/prism-analyst/prism/charts.py
Inside the demo
3 scenarios- 01
Revenue by channel, Q2
Schema first, one readable query, then the chart the data shape asks for.
question inrevenue by channel for Q2
- 02
Self-check kills its own query
The first query returns a clean-looking 50% - and cannot answer the question. Prism says so and re-queries.
question inwhat is our 90-day retention for customers who frist ordered in Q1, split by channel?
- 03
Query fails on a column that does not exist
run_sql comes back ok:false with a binder error. Prism re-reads the schema instead of guessing a column name.
question intop 5 products by refund rate last month
Under the hood
pythonArchitecture
- stack
- Claude Agent SDK · Python
- pattern
- Agent loop with sandboxed code execution
- why this, and what it costs
- Letting the model write and run code beats hand-built query tools the moment questions get compositional: you cannot pre-build a tool for every aggregation. The price is a sandbox you must actually isolate, and output you must validate before trusting.
Tools
3- describe_schemasafe
Return tables, columns and types available to query.
- run_sqlsafe
Execute a read-only SQL query in the sandbox and return rows.
- render_chartsafe
Render a chart from a result set.
Source
runnable- real source
- agents/prism-analyst/prism/analyst.py
- packages
- claude-agent-sdk
- duckdb
- pandas
- written against
- api_documentation/claude-agent-sdk-python.md
Watch it throw out its own 50%.
Inside, each question runs step by step: Prism reads the schema, each query lands with its rows and timing, and a result it rejects stays on screen, struck through, while the chart is drawn from the one that replaced it.