Recipes · Recipe

Query a connected database

Ask a business question and get an answer backed by governed, read-only SQL.

This recipe shows how to ask a business question and get an answer backed by governed, read-only SQL — without the agent or user writing any SQL themselves.

The question

"How many orders shipped last month?" — asked against a connected PostgreSQL database.

Prerequisites

The project must have a database source connected and synced. Check with discover: the database source should show status: "indexed".

Step 1: Search the database source

bash
curl -X POST "$ECHO_URL/projects/$PROJECT_ID/knowledge/search" \
  -H "X-API-Key: $SERVICE_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "query": "orders shipped last month", "sources": ["database"], "top_k": 5 }'

The hits identify the relevant tables and columns — public.orders, the shipped_at column, the status column.

Step 2: Understand the schema

Fetch the table's ref to see its full schema, column types, and relations:

bash
curl -X POST "$ECHO_URL/projects/$PROJECT_ID/knowledge/fetch" \
  -H "X-API-Key: $SERVICE_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "ref": "database:postgresql:analytics:public.orders" }'

The response includes column definitions, detected relationships (foreign keys, inferred joins), and sensitivity classifications.

The governance model

When an agent queries a connected database, every query runs under strict governance:

  • Read-only role — verified at connection time. The credentials cannot write.
  • Query validation — the SQL is checked before execution.
  • Enforced limits and timeouts — no unbounded scans.
  • Cost gate — expensive queries are blocked.
  • Per-user audit trail — every query is logged with who ran it.
  • Results flow to the agent, never to Echo's storage — raw rows are never persisted.

What Echo stores about a database

Echo stores knowledge *about* the database — schema, catalog, column types, sensitivity classifications, statistics — but never the data itself. Sensitive columns are classified before anything is persisted. Tagged columns keep statistics only: their values are masked, never stored, never sent to a model.

Next: Configuration.