.sql file is touched — so test coverage gaps never reach main.
The agent can also be invoked as a sub-agent by the PR reviewer, allowing the reviewer to delegate test-writing as part of a broader code review rather than just flagging the gap in its verdict.
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.
- Write access to the repository you want to run the workflow on
- Ability to add repository secrets and create GitHub Actions workflows
- Quick Start
- YAML Configuration
- Tools Reference
- Agent-to-Agent Delegation — required reading if you plan to invoke this agent from the PR reviewer
- Slack — the agent posts a test summary to
#data-qualityviapost_slack_message
What You’ll Build
By the end of this guide you’ll have:- A
test-maintainerDinoAI agent YAML that reads changed models, infers appropriate tests, writes them to the schema YAML, runsdbt test, iterates until green, and commits the result - A Python driver script that collects changed
.sqlfiles from the PR and triggers one agent session per model in parallel - A GitHub Actions workflow that runs automatically on every PR that adds or modifies a dbt™ model
What the Agent Does Per Model
Once triggered for a model, the agent works through five steps without stopping:dbt test before reporting completion — it never commits tests it hasn’t verified pass. If a test fails after being written, the agent diagnoses the failure, adjusts the test definition or SQL, and retries before giving up.
The absence of
invoke_agent from the tool allowlist means this agent cannot delegate further. When used as a child of the PR reviewer, the delegation graph stays exactly two levels deep — the reviewer delegates, the test maintainer executes.Tests the Agent Writes
The agent infers test candidates by reading the model SQL and upstream source definitions. It writes the following categories of tests:
The agent never writes a test it cannot justify from the SQL. When a test candidate is ambiguous it adds a
# TODO: confirm test logic with owner comment in the YAML rather than guessing.
Architecture Overview
How It Works
When a PR is opened or updated, GitHub Actions runstest_maintainer.py, which collects all changed .sql files from the diff and fires one test-maintainer agent session per model in parallel. Each session reads the model, infers and writes tests, runs dbt test, iterates until green, and commits to the PR branch. The driver script polls all sessions concurrently and posts a single completion comment to the PR once every session has finished, summarising what was written per model.
1
Create the Agent YAML
Create the following file in your repository at
.dinoai/agents/test-maintainer.yml..dinoai/agents/test-maintainer.yml
notify_parent_session is included in the allowlist so this agent can be invoked as a sub-agent by the PR reviewer. When triggered directly from the GitHub Actions workflow, the tool is present but never called — it only activates when a parent session ID is passed via invoke_agent.2
Create the Driver Script
Create
scripts/test_maintainer.py. This script runs inside GitHub Actions and is responsible for:- Collecting all changed
.sqlfiles from the PR diff - Firing one
test-maintaineragent session per changed model in parallel - Posting a “started” comment to the PR immediately
- Polling all sessions concurrently until each completes
- Posting a single completion comment to the PR with a per-model summary
scripts/test:maintainer.py
Sessions run in parallel via
ThreadPoolExecutor — if a PR changes three models, all three agent sessions start at the same time. Total wall-clock time is bounded by the slowest single model, not the sum of all three.The script exits with code
1 if any session fails or times out, which marks the GitHub Actions job as failed. This makes test-writing failures visible in the PR checks panel alongside lint and CI results.3
Add Your Paradime Credentials to GitHub Secrets
The driver script authenticates with Paradime using three values. Add the following as GitHub Actions secrets in your repository under Settings → Secrets and variables → Actions:
PARADIME_API_KEYPARADIME_API_SECRETPARADIME_API_ENDPOINT
GITHUB_TOKEN and GITHUB_REPOSITORY are provided automatically by GitHub Actions — you do not need to add them as secrets.4
Create the GitHub Actions Workflow
Create
.github/workflows/test-maintainer.yml. This triggers the driver script automatically whenever a PR adds or modifies a file inside models/..github/workflows/test-maintainer.yml
The
paths: filter restricts the workflow to .sql files inside models/ only. PRs that touch only YAML, Python, or documentation files will not trigger the agent.contents: write is required so the agent can commit and push the updated schema YAML files back to the PR branch. Without it, the git push inside the agent session will fail with a permissions error.What the PR Experience Looks Like
Once the workflow is set up, the experience for a PR author is:- They open a PR adding or modifying a dbt™ model
-
A comment appears on the PR immediately:
🧪 DinoAI test maintainer started — PR #42: feat/add-revenue-mart Writing and running missing tests for 2 model(s):
fct_orders(models/marts/fct_orders.sql)stg_payments(models/staging/stg_payments.sql)
feat/add-revenue-mart. Check#data-qualityfor live updates. -
A new commit appears on their branch:
test: add missing tests for fct_orders [DinoAI] -
A completion comment appears on the PR with a per-model breakdown:
🧪 DinoAI test maintainer — complete
✅
Tests added:fct_ordersunique+not_nullonorder_id,not_nulloncustomer_id,accepted_valuesonstatus(values: pending, shipped, delivered, returned) All 4 tests passing. Committed to branch:feat/add-revenue-mart✅
Tests added:stg_paymentsunique+not_nullonpayment_id,relationshipsonorder_id→stg_ordersAll 3 tests passing. 1 data quality warning onamount(severity: warn — negative values found, investigate before promoting to error) 2/2 models had tests written and committed tofeat/add-revenue-mart. -
The same summary is posted to
#data-qualityon Slack.
Using as a Sub-Agent of the PR Reviewer
If you have the PR reviewer set up, you can addtest-maintainer to its agents_squad so the reviewer delegates test-writing rather than just flagging the gap in its verdict.
Add the following to your pr-reviewer-e2e.yml:
invoke_agent("test-maintainer", ...) when it detects missing test coverage, and the test maintainer will call notify_parent_session with its findings once complete so the reviewer can include the result in its final verdict.
When used as a sub-agent, the test maintainer receives the branch name and model name via the
invoke_agent message rather than from the GitHub Actions context. Make sure the PR reviewer includes both in its delegation message.File Structure
Your repository should look like this after completing the setup:Related Docs
- PR Reviewer tutorial — the parent agent that can delegate to this one
- Agent-to-Agent Delegation — how to invoke this agent from the PR reviewer
- 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
run_terminal_commandandnotify_parent_session - Slack Integration — connecting Slack to Paradime
- Paradime API & Credentials — where to find your API endpoint, key, and secret