fastdata
Guide

Using fastdata

fastdata has two front ends over the same agent: a web chat and a terminal command. Both find fastdata.yaml by searching the current folder and its parents; pass -c path/to/fastdata.yaml to use another one.

Web chat

fastdata                         # same as `fastdata serve`
fastdata serve --port 9000 --no-open
OptionDefaultMeaning
-p, --port <port>8000Port. If it is taken, the next free one (up to +10) is used.
--host <host>127.0.0.1Interface to bind. Anything other than localhost makes your data reachable from the network; see Security.
--no-openDo not open the browser.

What you see for each question:

  1. Steps: a collapsible list of what the agent read and did ("Reading metrics/revenue.md").
  2. Query cards: the purpose, the SQL (copy button), the row count and timing, and a preview of the result. Show all loads the full result; Download CSV saves it.
  3. The answer, in Markdown: a direct answer with the key number in bold, a table, a few insights, Assumptions, the Query and Based on (the knowledge files used).
  4. Turns, time and cost of the answer.

Ask follow-ups in the same chat ("And for Germany only?"); the agent keeps the context. New chat starts over. Stop cancels a running answer.

Tip: links like http://localhost:8000/?q=How+many+orders+today open the chat and ask the question straight away, which is handy for bookmarks and team wikis.

Terminal: fastdata ask

fastdata ask "Which product categories bring in the most revenue?"

The answer (Markdown) goes to stdout; progress (steps, queries, cost) goes to stderr. So you can save or pipe just the answer:

fastdata ask "Monthly revenue for the last 12 months" > revenue.md
fastdata ask "Top 10 customers" | glow -        # render in the terminal with any Markdown viewer
OptionMeaning
--loop, -lKeep asking follow-up questions in the same conversation (see below).
--continueContinue the previous conversation (stored in .fastdata/last-session next to fastdata.yaml).
--session <id>Continue a specific conversation.
--newStart a new conversation without being asked about the previous one.
--results <file>Give the agent the results of a query you ran yourself (- reads stdin). See manual mode below.
--jsonPrint every event as one JSON object per line instead of Markdown, for scripts.

The exit code is 1 when the agent could not answer (for example it hit max_turns).

Continuing a conversation. In a terminal, when your previous conversation is less than a day old, fastdata ask asks whether to continue it. A follow-up in the same conversation reuses what the agent already read from the knowledge base instead of reading it again. Press Enter to continue, n for a new conversation, or pass --new / --continue to skip the question. Scripts (piped input, --json) always start a new conversation unless you pass --continue.

Several questions in a row. fastdata ask --loop keeps one conversation open and prompts for the next question after each answer:

$ fastdata ask --loop "Who are our top 5 customers?"
… answer …
› And what share of revenue do they bring in?
… answer, without re-reading the knowledge base …

In the loop, /results <file> [note] sends results of a query you ran yourself (manual mode), /new starts a new conversation, /exit or Ctrl+D quits, and Ctrl+C stops the current answer.

Running your own SQL: fastdata run

fastdata run runs a query you wrote through the connector, straight away. If the database rejects it (a typo, a wrong table or column name, a function your dialect does not have), Claude fixes the query, looking up the right names in the knowledge base, and fastdata runs the fixed version. This repeats until the query works or --max-fixes is reached.

fastdata run "SELECT country, COUNT(*) FROM customers GROUP BY country"
fastdata run --file report.sql --format csv > report.csv
cat query.sql | fastdata run -
$ fastdata run "SELECT c.country, SUM(oi.quantity * oi.price) FROM customer c JOIN …"
✗ SQLite error: no such table: customer
· Asking Claude to fix the query
✎ The table is `customers`, and the price column is `order_items.unit_price`.
    SELECT c.country, SUM(oi.quantity * oi.unit_price) FROM customers c JOIN …
✓ 8 row(s) in 26 ms · $0.0686
Ran the query after 1 fix(es):
    …
| country | revenue |
| --- | --- |
…

The rows go to stdout and progress to stderr, so redirecting saves just the result. When a fix was needed, the query that actually ran is printed, so you can copy it back into your file.

OptionDefaultMeaning
-f, --file <path>Read the query from a file. - as the query (or piped input) reads stdin.
--max-fixes <n>3How many times Claude may fix a failing query. 0 runs it as written and never calls Claude.
--format <format>tabletable (Markdown), csv, or json (sql, fixes, columns, rows, truncated).

What to expect:

  • A working query never reaches Claude. It costs nothing and is as fast as your database.
  • Claude sees the query and the error message, not result rows. It can read the knowledge base and nothing else, like the agent.
  • Fixes keep your intent: same question, tables, filters and columns. Every fixed query goes through the read-only guard again. A statement meant to change data (DELETE, UPDATE, …) is refused without asking Claude.
  • It stops early when Claude cannot fix the query (a lost connection, missing permissions, a timeout) or suggests a query that already failed. The exit code is then 1.
  • Rows are capped by limits.max_rows like every other query; raise it for bigger exports.

Needs a connector. In manual mode, run the query in your own SQL client.

Manual mode (no connector)

Without a connector in fastdata.yaml, fastdata cannot touch your database. It still does the hard part, finding the right tables and writing the query, and then hands the query to you.

In the web chat: the query card says Run this yourself. Copy the SQL, run it in your SQL client, then paste the output into the box under the query and click Analyze results. Any of these formats works: CSV, TSV (what you get when you copy cells from most SQL clients or a spreadsheet), JSON, or a Markdown table.

In the terminal:

fastdata ask "What is the cancellation rate by channel?"
# … run the printed query, save the output as results.csv …
fastdata ask --continue --results results.csv
# or pipe it in:
psql "$DB" --csv -c "SELECT …" | fastdata ask --continue --results -

You can add a note with the results: fastdata ask --continue --results results.csv "Focus on mobile".

Writing good questions

  • Name the time range ("last quarter", "since January") or accept the agent's stated assumption; it always lists the assumptions it made.
  • Use your business words. If "active customer" has a specific meaning, put it in glossary.md once and every answer will use it.
  • Ask follow-ups instead of restarting: "split that by country", "only enterprise".
  • If an answer is wrong, check Assumptions and Query first; then fix the knowledge base (usually a glossary entry, a metric definition or a table note) so it stays fixed.

HTTP API

The web chat uses a small local API you can also call from scripts:

EndpointPurpose
GET /healthLiveness check
GET /api/infoMode (execute or manual), model, dialect, connector, example questions
POST /api/chatBody { "message": "...", "sessionId"?: "...", "results"?: "..." }. Response is a Server-Sent Events stream of events. Returns 409 if that conversation is still answering.
GET /api/results/:idFull result as JSON; add ?format=csv for CSV
curl -N -X POST localhost:8000/api/chat \
  -H 'content-type: application/json' \
  -d '{"message":"How many customers do we have?"}'

Events

EventFields
sessionsessionId (send it back to continue), mode
steplabel, tool
texttext: the agent thinking out loud between steps
queryqueryId, sql, purpose, status (running or proposed)
resultqueryId, resultId, columns, rows (preview), rowCount, truncated, durationMs
query_errorqueryId, message
answermarkdown
errormessage
doneturns, costUsd, durationMs (always the last event)

Results are kept in memory (the last 200) for as long as the server runs.