fastdata lets an AI write and run SQL on your data, so it is built so that no single mistake (including a model error or instructions hidden in the data) can change data or leak credentials.
What fastdata guarantees
Queries are read-only, enforced three times.
- fastdata's guard checks every query before it reaches the connector. It allows exactly one
statement starting with
SELECT,WITH,SHOW,DESCRIBE,EXPLAIN,VALUES,TABLEor a read-onlyPRAGMA. It rejects write and admin keywords anywhere in the query (INSERT,UPDATE,DELETE,MERGE,DROP,CREATE,ALTER,TRUNCATE,GRANT,COPY,CALL,SET,INTO, …), functions with side effects or file access (nextval, advisory locks,pg_notify,pg_sleep,pg_read_file,dblink,load_file, …), SQLite pragmas that write, unterminated comments or quotes, and backslashes inside quotes (databases disagree on whether\'ends a string, which could otherwise hide a second statement). Where databases read the same text differently in other ways (nested/*comments, MySQL's/*! … */,#and--without a space,$$…$$,[…]), it checks the reading that shows more SQL, or rejects the query. It ignores comments and string contents, so text like'DROP TABLE'inside a string is fine. Quote a column that happens to be named like a keyword:"update". - The built-in executors run every query in a read-only transaction over Postgres's extended
protocol, which refuses more than one statement per call (Postgres), or open the file
read-only (SQLite), with a timeout.
fastdata doctor --querygoes through the same guard. - Your database role, which must only have
SELECTrights. This is the real guarantee: it holds even if everything above fails. See Connectors.
fastdata never holds database credentials. They live in the connector's environment or in a
remote service. fastdata.yaml only references environment variables. The Claude process does
not get them: DATABASE_URL and the variables the connector block refers to are removed from
its environment.
The agent is sandboxed. It can read files inside the knowledge folder and call the query tool, nothing else (file paths and search patterns that point outside the folder are refused): no shell, no file writes, no web access. It does not load your personal Claude Code settings, plugins or MCP servers.
The model sees little data. At most limits.preview_rows rows (default 50) of each result
reach the model, and a query fetches at most limits.max_rows rows (default 100; the
built-in executors stop in the database). Those rows go only to the UI and the CSV download.
Data is not instructions. The agent is told to treat query results, pasted results and knowledge files as data. Even if a value says "ignore your instructions", there is no tool the agent could misuse.
The web server is local. It binds to 127.0.0.1 and rejects requests with a foreign Host
header or from other origins, so web pages you visit cannot use it to query your database.
Answers cannot send data out. A Content-Security-Policy lets the chat page load and connect to this server only, and images in answers are shown as links rather than loaded. Text in your data that tries to make the model put results into an image URL gets nowhere.
What fastdata does not do (yet)
- No login. Anyone who can reach the server can ask questions. Keep the default
--host 127.0.0.1, or put an authenticating proxy in front of it for a team. - No row-level permissions. Everyone using one fastdata instance sees what its connector's role sees. Use database permissions (separate roles, row-level security) to limit that.
rules.mdis guidance, not enforcement. The agent follows it, but sensitive columns should also be hidden from the connector's role.
Where your data goes
- Questions, knowledge files and result previews are sent to Claude (Anthropic, or Bedrock / Vertex AI if you configured them) to produce answers.
fastdata learnsends schema metadata (table and column names, types, keys, comments, row counts) and the most common values of category-like columns to Claude. Columns whose names suggest personal data or free text are never sampled;--no-samplessends no values at all.fastdata runsends nothing to Claude while your query works. When it fails, the query and the database's error message go to Claude so it can fix the query; result rows never do.- Full results stay on your machine, in the fastdata process's memory.
- Conversation transcripts are stored locally by the Claude Agent SDK under Claude Code's
config folder (
~/.claude/projects/).
Checklist for a real database
- A dedicated read-only role with
SELECTonly on the tables people should query -
default_transaction_read_only = onand astatement_timeouton that role - Credentials in
.envor a secret manager,.envnot committed - Personal-data columns listed in
rules.md, and hidden from the role where possible - Server on
127.0.0.1, or behind an authenticating proxy