Before You StartParadime
- Your Paradime API endpoint, API key, and API secret — generate these under Workspace Settings → API. Make sure to enable
DinoAI agent APIcapabilities. Requires Admin access.
- Your Paradime workspace must have an active BigQuery connection with sufficient permissions to read job metadata. The agent calls
get_bigquery_query_performance_statsto retrieve performance stats for the BigQuery jobs that each dbt™ model produced.
- A Bolt schedule name — the script reads job IDs directly from the latest run’s
run_results.jsonartifact, which maps each dbt™ model to the BigQuery job it produced - One or more BigQuery job IDs supplied directly via CLI flag or environment variable, if you already know which models are expensive
- Slack — the agent posts the PR link and a cost summary to
#finopsviapost_slack_message
What You’ll Build
By the end of this guide you’ll have:- A Poetry project wired to the Paradime SDK
- A
run_query_optimizer.pytrigger script that reads dbt™ model results from Bolt artifacts (or accepts job IDs directly), filters to the top costly models by bytes processed, and hands the full context to the agent - A
query-optimizerDinoAI agent YAML that diagnoses anti-patterns, rewrites dbt™ model SQL and config, opens a PR, and notifies Slack
What the Agent Does
Once triggered, the agent works through five phases without stopping:main, and never guesses — if a business decision is required it leaves a TODO comment in the SQL and calls it out in the PR description.
Anti-Patterns the Agent Detects and Fixes
Architecture Overview
How It Works
run_query_optimizer.py loads configuration from environment variables, optionally reads the latest Bolt run’s run_results.json artifact to extract the BigQuery job ID produced by each dbt™ model, filters to the top-N costliest models above a configurable bytes threshold (default: 10 GB), then triggers a single query-optimizer DinoAI agent session with the full model context pre-embedded in the opening message. The script polls every 20 seconds until the agent completes or times out (default: 60 minutes), then prints the full optimisation report to stdout. An optional follow-up drill-down on a single model can be sent within the same session.
1
Set Up the Poetry Project
Create the following Install dependencies by running:
pyproject.toml at the same directory level as your dbt_project.yml. This is required so the agent can locate and rewrite dbt™ model files correctly during the optimisation pass.pyproject.toml
The only two third-party dependencies are
requests (for downloading Bolt artifacts) and paradime-io (the Paradime SDK). All other imports — argparse, os, sys, textwrap, time — are part of the Python standard library.2
Create the Agent YAML
Create the following file in your repository at
.dinoai/agents/query-optimizer.yml. This defines the agent’s role, five-phase goal, anti-pattern knowledge, guardrails, and Slack output channel..dinoai/agents/query-optimizer.yml
tools.mode: allowlist restricts the agent to only the tools listed. This is important for a write-capable agent — it prevents accidental access to tools outside the intended optimisation workflow.The Slack channel is set to
#finops by default. Update slack.channel before committing if your team routes cost alerts to a different channel.3
Create the Trigger Script
Create
scripts/run_query_optimizer.py. This script reads dbt™ model results from Bolt artifacts (or accepts BigQuery job IDs directly via CLI), filters to the top costly models by bytes processed, builds a structured opening message with all pre-fetched metadata, triggers the query-optimizer agent, and polls until completion.scripts/run:query:optimizer.py
The script accepts
--schedule-name or --job-ids but not both — they are mutually exclusive. When --schedule-name is used, the script reads run_results.json from the latest Bolt run and maps each dbt™ model name to the BigQuery job ID it produced. When --job-ids is used, the agent receives the job IDs directly and resolves the model files itself via performance stats.When no models are found above the bytes threshold the script exits cleanly with code
0 — this makes it safe to run on a schedule even when recent Bolt runs had no costly models.4
Set Your Environment Variables
Store your secrets in Paradime before scheduling. Go to Account Settings → Environment Variables and add the following:
Your Paradime API endpoint, key, and secret are available under Workspace Settings → API. Make sure the key has
DinoAI agent API capabilities enabled.5
Run the Optimizer Manually
Option A — Automatically detect costly dbt™ models from a Bolt schedule:Option B — Supply BigQuery job IDs directly (when you already know which models are expensive):Option C — Include a follow-up drill-down on a specific dbt™ model:You should see output like:The agent then posts its full optimisation plan and PR link to stdout, and a cost summary to
#finops on Slack.Schedule with Bolt
Run the optimizer automatically on a recurring cadence so costly dbt™ models are caught and fixed without any manual intervention. The schedule reads the latest Bolt run’srun_results.json, identifies the top offending models by bytes processed, and triggers the agent to fix and PR them.
Add Environment Variables to Paradime
Go to Account Settings → Environment Variables and confirm the variables from the previous step are saved. Bolt schedules read from the same environment variable store, so no additional setup is needed.Create the Bolt Schedule
Go to Bolt → Schedules and click New Schedule. Name it something likeQuery Cost Optimizer and add the following two commands in order:
Replace
your_dbt_production_schedule with the exact name of the Bolt schedule that runs your dbt™ models in production. The script reads that schedule’s run_results.json artifact, which contains a record per dbt™ model including the BigQuery job ID it produced.poetry install runs first on every execution so that any dependency updates committed to pyproject.toml are picked up automatically — no manual intervention needed after a dependency bump.Choose a Schedule Frequency
The right cadence depends on how frequently your production dbt™ models run and how quickly costs accumulate in your warehouse. The table below covers the most common options:For most teams, weekdays at 8 AM (
0 8 * * 1-5) is a sensible default — it runs after overnight production dbt™ models have completed, so the latest run_results.json artifacts are always available. The script exits cleanly with code 0 when no dbt™ models exceed the bytes threshold, so there is no cost or noise on quiet days.File Structure
Your repository should look like this after completing the setup:pyproject.toml must sit at the same directory level as dbt_project.yml. The agent uses run_terminal_command, read_file, and write_file to navigate and rewrite your dbt™ project files, so the working directory at session start must be the repo root.Related Docs
- Programmable Agents — Quick Start — getting started with DinoAI agents
- Programmable Agents — YAML Configuration — full reference for agent config options
- Programmable Agents — Tools Reference — all available tools including
get_bigquery_query_performance_statsandpost_slack_message - Bolt — Schedules — creating and managing Bolt schedules
- Paradime SDK — Artifacts — accessing run artifacts including
run_results.json - Slack Integration — connecting Slack to Paradime
- Paradime API & Credentials — where to find your API endpoint, key, and secret