Open source · Apache 2.0

DBA Brain

A database operations toolkit for people who are on call.

Health metrics from SQL Server, Oracle, PostgreSQL and MySQL, graded against policies you write. Backups proven by restoring them. Told to you on a schedule, without an agent on any monitored machine.

pip install dbabrain
one JSON envelope, whatever happened
{
  "success": true,
  "operation": "restore-full",
  "message": "Restored SALESDB_STG to
              2026-08-07 01:40:00.",
  "error": null,
  "data": { },
  "metrics": { "duration_ms": 41230 }
}
Four enginesSQL Server, Oracle, PostgreSQL, MySQL
No agentInstalls nothing on your databases
No telemetrySends nothing anywhere by itself
Python 3.12+One extra per database driver
What it does

Graded verdicts, not raw rows

DBA Brain collects health metrics from your SQL Server, Oracle, PostgreSQL and MySQL instances, grades them against policies you write, runs your scheduled SQL, takes backups and proves them by restoring them, checks objectives against real measurement history, and tells you about it, on a schedule, without an agent on any monitored machine.

It sends nothing anywhere by itself. No telemetry, no usage reporting, no update check. It connects to the databases and hosts you list, and, only if you turn it on, to a chat service. Nothing else.

Health metrics

Around ninety metrics across four engines: availability, capacity, performance, recoverability, security, maintenance. Collected and normalised into one shape.

Graded, not dumped

Every measurement is graded against a policy you wrote. You read a verdict (OK, WARNING, CRITICAL) and pull the evidence only for what came back bad.

Backups proven by restore

Runs backups, restores them onto a disposable target, verifies the result and records what was proven and when. The restore is the proof.

Scheduled SQL

Your own SQL, on a schedule or on request, against approved targets, delivered as text or a spreadsheet. The SQL is a reviewable file, never a string in config.

Reports

Fleet inventory, per-server metrics, index usage and SLA pages, with a freshness gate so a stale number is never reported as a current one.

SLA / SLO

Indicators computed from stored measurement history, objectives evaluated with an error budget, and how much of it is left.

Alerts and chat commands

Telegram delivery, one message at a time. Commands people send back are gated by the person's clearance and the chat's.

Config as code

Every decision is a JSON file you keep in version control. A threshold change is a diff and a review, not an edit to somebody's script.

Secrets kept encrypted

PBKDF2-HMAC-SHA256 + Fernet. The passphrase is supplied at run time and never written to disk, a log or the store. Passwords travel on stdin, never argv.

What it is not

Not an AI agent

It is what an agent operates. Nothing here talks to a model or decides anything on its own.

Not a dashboard product

The primary interface is a CLI; the primary output is a record in a database you own.

Installs nothing on your databases

No agent, no extension, no stored procedure. It logs in with a read-only account and asks questions.

Screenshots

What it produces

Real report pages from a live estate, with every name replaced by a stable fake one. Click an image to open it full size.

Fleet inventory and health report: server counts per engine, critical findings ordered by severity with a recommended action
Fleet inventory: every instance, its health, and a priority list of what to act on first, each with a recommended next step.
Per-server metrics page: health score, status cards for availability, CPU, memory, disk, backup and security, and a list of problems
Server metrics: one card per health area, showing the worst reading, the rule that graded it and what it means.
SLA / SLO compliance page with overall verdict and per-engine cards
SLA / SLO compliance: verdict per engine, computed from stored history with no database connections.
Index usage report for one SQL Server instance: total, unused, cold and droppable indexes
Index usage: total, unused, cold and droppable indexes per instance, with how long the counters cover.
How it works

One run, end to end

Whoever starts it (the daemon, a person, a chat command or an AI agent), a run takes the same path. The app hands one JSON request to transport, which starts the shared operations CLI; that CLI reaches the database or host and answers with one JSON envelope. Results land in the runtime store, and reports and alerts are built from there.

Scroll sideways to see the whole diagram.
CALLERS APP SHARED LAYERS YOUR ESTATE Daemon (schedule) Person (shell) Chat command AI agent App CLI metrics sql_tasks backup_restore sla · reports sre · control one JSON object in, one JSON object out transport starts process common.cli JSON on stdin SQL Server Oracle PostgreSQL MySQL / MariaDB Linux / Windows read-only login, SSH or WinRM job_runs, measurements Runtime store SQLite or PostgreSQL Reports Web host :8080 Telegram alerts

Every command answers in the same envelope, whether the work succeeded or not:

json
{
  "success": true,
  "operation": "restore-full",
  "message": "Restored SALESDB_STG to 2026-08-07 01:40:00.",
  "error": null,
  "data": { },
  "metrics": { "duration_ms": 41230 }
}

From a measurement to an alert

1Collect~90 metrics per engine
2Normaliseone shape for all engines
3Gradeagainst your policy in data/*.json
4Storeruntime store
5Report / alert / SLAby severity and error budget

A backup is proven by restoring it

1Backupfull / diff / log
2Copyto a disposable target
3Restorelatest or point in time
4Verifythe result
5Recordwhat was proven, and when
6Clean upand apply retention

Why: cheap for an AI agent, fine without one

The command a person runs is byte-for-byte the command an agent runs, so there is one code path to audit, and every run is logged the same way whoever started it.

  WITHOUT a tool                        WITH DBA Brain
  agent -> raw SQL -> agent             agent -> DBA Brain -> database

  "check this database"                 "check this database"
    -> SELECT ... dm_os_wait_stats        -> one JSON request
    <- every row, into the context
    -> SELECT ... sys.databases           <- one graded envelope:
    <- every row, into the context             41 checks, 40 OK,
    -> ... once per check, per run             1 WARNING: appdb
    <- all of it, healthy or not               log backup 31h old

The saving is not compression. It is not sending what nobody needed to read. And no model is required: remove the agent and the daemon, schedules, reports and alerts all still run.

Backup & restore

A backup that outlives the host it came from

A backup kept on the database host is lost together with it. A dead disk takes the database and every backup written next to it, so a backup on the same disk as the database is one of the biggest holes there is. A lost host, or any other failure of that machine, takes every disk it has. Ransomware goes further: it encrypts every drive and every share the infected host can write to.

DBA Brain proves every backup at each step and keeps a proven copy away from the database host.

Done built in DBA Brain 0.33.0, which is not released yet: the version on PyPI is 0.30.0. In progress being built now, in no version yet.
Scroll sideways to see the whole diagram.
DATABASE HOST DBA BRAIN (ANOTHER HOST) REPOSITORY (OUTSIDE THE DB HOST) DRILL VM 1 · Backupverified by the engine 2 · Hash at the sourceSHA-256 + size in bytes 3 · Re-check on diskCHANGED / MISSING · partly Catalogthe first hash can neverbe changed 8 · History, reportsper file · partly copy 4 · Copyhash + bytes, copy again 5 · Scanviruses, ransomware markers 6 · Mark verifiedonly then may the source go delete the source: optional, off by default 7 · Restore drill chain checked, restored, databases opened and queried · partly the run, its result and every file it used

Solid boxes: done in 0.33.0. Dashed boxes: in progress. "partly": the step below says what is still being built.

Each backup run, step by step

FULL, DIFF and LOG backups for SQL Server; a base backup plus WAL for PostgreSQL; RMAN for Oracle.

1Back up, verified by the engine

SQL Server RESTORE VERIFYONLY WITH CHECKSUM, PostgreSQL pg_verifybackup, Oracle RMAN VALIDATE.

Done

2Hash at the source

SHA-256 and size in bytes, taken on the database host when the backup ends and stored in the catalog on another host. The first hash can never be changed, not even by a direct UPDATE: a database trigger refuses it.

Done

3Check it again later

Re-hash the file on the source and compare with the stored hash: an encrypted or altered file shows CHANGED, a vanished one MISSING.

Done by hand, verify-backup-files
In progress on every cycle

4Copy to the repository

A shared folder or another VM, outside the database host. Hash before and after, compare checksum and bytes, copy again on a mismatch up to copy_max_retry; every attempt is recorded.

Done the copy gate, used by restores and copy-only
In progress the copy after every backup run

5Scan the copy

ClamAV, plus ransomware markers: ransom notes, locked-file extensions, a canary file. An infected copy is quarantined and reported CRITICAL; the source is never deleted.

In progress

6Mark the copy verified

Checksum, bytes and scan all pass. Only then may the source be deleted on the database server: a switch per entry, off by default, and never on a copy command's exit code alone.

In progress

7Restore drills

Daily, weekly or monthly, on an independent VM, only from verified copies: the chain is checked (FULL → DIFF → LOG, base backup + WAL), restored, and the databases opened, queried and checked for consistency. The run, its result and every file it used are recorded.

Done restore from proven copies, databases opened and queried
In progress reading from the repository, drill tiers, consistency checks on every engine

8History and reports

Per server, database and file: which files were backed up, copied, verified, scanned, and used by which drill with what result.

Done on the server and fleet pages
In progress coverage and success rates

Configuration

Every field is mandatory, so nothing is left to a default nobody wrote down. upgrade-config adds them to existing entries with the values that keep today's flow: offload_enabled: false, offload_scan: "none", offload_delete_source: false, restore_from: "server".

json
{
  "backups": [
    {
      "backup_id": "APPDB_FULL",
      "server_id": "db-server",
      "jobs": [
        { "job": "database", "databases": ["APPDB", "SALESDB"], "all_databases": false },
        { "job": "log", "databases": [], "all_databases": true }
      ],
      "offload_enabled": true,
      "offload_server_id": "repository-vm",
      "offload_folder": "/srv/backups/db-server",
      "offload_copy_max_retry": 3,
      "offload_scan": "clamav",
      "offload_delete_source": false,
      "offload_source_share": "",
      "offload_source_username": "",
      "offload_source_password_ref": ""
    }
  ],
  "restores": [
    { "id": "drill-vm-daily", "restore_from": "server" }
  ]
}

An excerpt: the fields this flow adds. The rest of each entry is unchanged.

  • A backup job names its databases as a list, or an empty list with "all_databases": true.
  • offload_* on a backup entry: the repository by server_id and folder, the copy retries, the scan ("none" or "clamav") and whether the source may be deleted once the copy is verified.
  • A Windows source read over SMB also states offload_source_share, offload_source_username and offload_source_password_ref, the three together.
  • A restore entry states restore_from: "server" or "repository".
  • In 0.33.0 these fields are written and checked. The copy, scan and delete they switch on are in progress, and "restore_from": "repository" is refused until reading from the repository is built.
Architecture

15 components

Ten apps, each doing one job with its own CLI and never importing another app, and five shared layers that every app stands on. The list is closed, and every component has exactly one reference doc.

Who may call whom

Scroll sideways to see the whole diagram.
10 apps jobs · metrics · sql_tasks · reports · telegram backup_restore · sla · sre · control · webhost import transportthe one client dbruntime store logging_opslogs, job_runs commonoperations, CLI only starts common.cli lib pure rules: imported everywhere, runs nothing
  • common may not be imported: it is only ever run as a CLI.
  • lib may not run a CLI: it is only ever imported.
  • No app imports another app. No shared layer imports an app.
  • Each rule has a guard test beside it, so the diagram describes what is true, not just what was intended.

Apps

03App command daemon

db_ops/jobs · db-ops daemon

The scheduler: runs each app on its own interval inside its allowed hours, skips one that is still running.

04Metrics engine

db_ops/metrics

Around ninety metrics across four engines, collected and normalised into one shape.

05SQL task runner

db_ops/sql_tasks

Your own SQL, on a schedule or on request, against approved targets, as text or a spreadsheet.

06Reports

db_ops/reports

Scheduled reports and inventory pages, with a freshness gate against stale numbers.

07Chat delivery and commands

db_ops/telegram

Delivers the outgoing queue and executes commands, gated by the person's and the chat's clearance.

08Backup / restore

db_ops/backup_restore

Runs backups, restores them onto a disposable target, verifies, and records what was proven.

09SLA / SLO compliance

db_ops/sla

Indicators from stored measurement history, objectives with an error budget.

10SRE

db_ops/sre

Provisions disposable lab databases for drills: single instances or small HA clusters, in Docker or on VMs.

11Control

db_ops/control

Builds and deploys the toolkit to another node, and watches the toolkit itself.

12Web host

db_ops/webhost

Serves the rendered reports over HTTP and hosts the console. Publishes files, never generates them.

Shared layers

01Runtime store

db_ops/db

The toolkit's own data: job runs, measurements, report state, delivery queue, restore history. SQLite to start, PostgreSQL later.

02Logging engine

db_ops/logging_ops

Scoped application logs, runtime logs, shared errors and daily archives.

13Common

db_ops/common · CLI only

Reaching a host, running SQL, moving a file, rotating a password. Every command takes one JSON object.

14Lib

db_ops/lib · import only

Pure rules: time windows, notify routing, severity, formatting. Imports nothing from the rest.

15Transport

db_ops/transport

The one client: starts common.cli and db.cli for every component. Imports only lib.

Install

Get started

Python 3.12+. Each database driver is an extra, so you install only what you run. Published on PyPI via trusted publishing.

[postgres]PostgreSQL, pure Python
[mysql]MySQL / MariaDB, pure Python
[oracle]Oracle, no client library needed for 12.1 and newer
[mssql]SQL Server, also needs Microsoft's ODBC driver
[ssh], [winrm]OS-level metrics on Linux / Windows hosts
[all]everything

Install

shell
python -m venv .venv
.venv/bin/pip install 'dbabrain[postgres]'

Five-minute try-out with a throwaway PostgreSQL container

shell
cd examples/postgres-quickstart
docker compose up -d
python -m db_ops.db.cli      --config config.json init
python -m db_ops.metrics.cli --config config.json collect --dry-run
python -m db_ops.metrics.cli --config config.json collect
python -m db_ops.metrics.cli --config config.json report
Contact

Donations and investment

DBA Brain is free, open source, and maintained by one person. If you would like to donate, sponsor the project, or talk about investment or partnership, please get in touch directly.

For bugs and feature requests, please use GitHub issues. For security problems, follow the security policy rather than email.