
"If you give an agent a tool, then nobody has to fish."
SQLBot is a new kind of interface for your database. Instead of writing SQL queries yourself, you delegate high-level analytical tasks to an AI agent. It reasons through your request, executing a chain of queries and analyzing the results until it arrives at a complete answer—all while keeping your data safe with built-in safeguards.
It represents the next logical layer on the modern data stack, building directly on the power of SQL and dbt.
Most people use SQL through apps. Maybe you're comfortable writing raw SQL queries if you're a wizard. Most people aren't.

Sure, SQL powers most relational databases—it's incredibly powerful. But here's the thing: even simple questions can turn into sprawling queries with multiple joins and cryptic table relationships. Want to see what a "basic" customer lookup actually looks like? Here's what you'd need to write just to get someone's rental history from the Sakila database:
-- Raw SQL: Get rental history for customer 526
SELECT
f.title,
f.description,
r.rental_date
FROM customer c
JOIN rental r
ON c.customer_id = r.customer_id
JOIN inventory i
ON r.inventory_id = i.inventory_id
JOIN film f
ON i.film_id = f.film_id
WHERE
c.customer_id = 526
ORDER BY
r.rental_date DESC;
This is hard to reuse and requires every user to understand the database's join logic.

Here's where dbt changes the game. Those database wizards who understand all the table relationships? They can package their knowledge into macros and schemas that business users can actually work with. That ugly query above becomes a simple, self-documenting function:
-- In a file like `macros/get_customer_rental_history.sql`
{% macro get_customer_rental_history(customer_id) %}
SELECT
f.title,
f.description,
r.rental_date
FROM customer c
JOIN rental r
ON c.customer_id = r.customer_id
JOIN inventory i
ON r.inventory_id = i.inventory_id
JOIN film f
ON i.film_id = f.film_id
WHERE
c.customer_id = {{ customer_id }}
ORDER BY
r.rental_date DESC;
{% endmacro %}
Suddenly, business users can access complex database operations without needing to understand the underlying join logic:
-- A business user can now write this instead:
{{ get_customer_rental_history(customer_id=526) }}
The real magic happens in dbt's schema.yml files—they're like institutional memory for your database. Wizards document what each table and column actually means in plain English, creating a shared vocabulary that makes databases accessible to entire teams.

SQLBot adds the final layer: an AI agent that uses the structure dbt provides while keeping your data protected. The agent is armed with two crucial pieces of information from your dbt profile:
schema.yml): It reads your table and column descriptions to understand what your data means.macros/*.sql): It learns your reusable business logic to solve complex tasks more efficiently.Built-in Safeguards: SQLBot includes read-only protections and query validation to prevent dangerous operations like DROP, DELETE, or UPDATE commands, ensuring your data stays safe while you focus on analysis rather than syntax.
This layered approach gives you the best of all worlds: the raw power of SQL, the structure and reusability of dbt, the conversational intelligence of an AI Agent, and the peace of mind that comes with built-in safety controls.
Because the agent understands this stack, you no longer write SQL or dbt. You state a business goal.
You: "I want to run a 'customer of the month' promotion. First, identify our single best customer based on their total lifetime payment amount. Once you have that customer, find out which actor they have rented the most movies from. I'll need the customer's full name, their email address, the full name of their favorite actor, and the count of films they've rented by that actor."
SQLBot accepts the task and begins its reasoning process, writing and executing the necessary SQL.
Query 1: Find the Top Customer
SELECT p.customer_id, c.first_name, c.last_name, c.email, SUM(p.amount) AS total_payments
FROM payment p
JOIN customer c ON p.customer_id = c.customer_id
GROUP BY p.customer_id
ORDER BY total_payments DESC
LIMIT 1
✔ Query passes safeguard against dangerous operations.
▷ Query Result → Success: Query completed
Query 2: Find Their Favorite Actor
WITH cust_rentals AS (
SELECT r.rental_id, r.inventory_id
FROM rental r
WHERE r.customer_id = 526
), films AS (
SELECT cr.rental_id, i.film_id
FROM cust_rentals cr
JOIN inventory i ON cr.inventory_id = i.inventory_id
), film_actor_map AS (
SELECT f.rental_id, fa.actor_id
FROM films f
JOIN film_actor fa ON f.film_id = fa.film_id
)
SELECT a.first_name || ' ' || a.last_name AS actor_name, COUNT(*) AS rentals_by_actor
FROM film_actor_map fam
JOIN actor a ON fam.actor_id = a.actor_id
GROUP BY fam.actor_id
ORDER BY rentals_by_actor DESC, actor_name ASC
LIMIT 1
✔ Query passes safeguard against dangerous operations.
▷ Query Result → Success: Query completed
It then delivers a synthesized answer, even suggesting the next logical step.
SQLBot:
Got it — we'll find the top customer by total payments, then their most-rented actor.
Approach:
- Query total lifetime payments by customer to get the top customer.
- For that customer, join rentals → inventory → film_actor → actor to find the actor with the highest rental count.
Results:
- Customer: KARL SEAL
- Email: KARL.SEAL@sakilacustomer.org
- Favorite actor: UMA WOOD
- Films rented from that actor: 6
Next step suggestion: Want a quick profile for this customer (total rentals, average spend, preferred categories)?
The traditional approach requires you to:
SQLBot flips this model. Instead of writing SQL, you delegate analysis:
The result? You spend time on strategy and insights, not syntax and debugging.
schema.yml and dbt macros to generate accurate, business-aware queries.;) to bypass the agent and run it directly.--profile mycompany).SQLBot includes powerful data export functionality that allows you to save query results in multiple formats:
.xlsx format with proper formattingAfter running any successful query, you can export the results using natural language:
# After running a query, simply ask to export
> "Show me the top 10 customers by revenue"
[Query executes and shows results]
> "Export this to CSV"
> "Save this as Excel"
> "Export to Parquet format"
> "Save this to /path/to/my/reports as Excel"
sqlbot_query_1_20241201_143022.csv)./tmp directory by default (created automatically)pip install sqlbot
# Verify installation
sqlbot --help
Create a .env file in the root directory with your API key and database credentials.
# OpenAI API Configuration
OPENAI_API_KEY=your_openai_api_key_here
# SQLBot LLM Configuration
SQLBOT_LLM_MODEL=gpt-5
SQLBOT_LLM_MAX_TOKENS=10000
SQLBOT_LLM_TEMPERATURE=0.1
SQLBOT_LLM_VERBOSITY=low
SQLBOT_LLM_EFFORT=minimal
SQLBOT_LLM_PROVIDER=openai
SQLBot supports both local and global dbt profile configurations:
.dbt/profiles.yml in your project directory for project-specific configurations~/.dbt/profiles.yml for system-wide configurationsSQLBot automatically detects and prioritizes local profiles when available.
PostgreSQL:
qbot:
target: dev
outputs:
dev:
type: postgres
host: "{{ env_var('DB_SERVER') }}"
user: "{{ env_var('DB_USER') }}"
password: "{{ env_var('DB_PASS') }}"
dbname: "{{ env_var('DB_NAME') }}"
SQL Server:
qbot:
target: dev
outputs:
dev:
type: sqlserver
driver: 'ODBC Driver 17 for SQL Server'
server: "{{ env_var('DB_SERVER') }}"
database: "{{ env_var('DB_NAME') }}"
user: "{{ env_var('DB_USER') }}"
password: "{{ env_var('DB_PASS') }}"
Then, test your connection: dbt debug
This is the most important step. Create a profiles/qbot/models/schema.yml file. The agent's performance depends heavily on clear, detailed descriptions for your tables and columns.
version: 2
sources:
- name: my_database
schema: dbo
tables:
- name: customers
description: "Contains one record per customer, including personal details and account creation date."
columns:
- name: customer_id
description: "Unique identifier for each customer (Primary Key)."
# Start interactive mode
sqlbot
# Delegate a task from the command line
sqlbot "How many new customers did we get last month?"
🚀 Recommended: Use our standalone demo project for the easiest SQLBot experience:
# Clone the demo project (includes everything you need)
git clone https://github.com/AnthusAI/SQLBot-Sakila-SQLite
cd SQLBot-Sakila-SQLite
# Install SQLBot and dependencies
pip install -e .
# Set up the Sakila database (SQLite - no server required!)
sqlbot setup sakila
# Start exploring with natural language queries
sqlbot --profile Sakila
Try these queries:
Why SQLite? No database server installation required! The Sakila database runs entirely from a single .db file with:
The SQLBot-Sakila-SQLite demo project demonstrates the recommended project structure for SQLBot:
your-database-project/
├── .sqlbot/ # All SQLBot configuration
│ ├── config.yml # SQLBot settings
│ ├── agents/ # Custom database knowledge
│ └── profiles/YourDB/ # Database files and config
├── .dbt/profiles.yml # Local dbt connection config
├── pyproject.toml # Python dependencies
└── README.md # Project documentation
Key benefits:
.sqlbot/ folderThe complete project is available on GitHub under the MIT license.