Query five databases.
Break nothing.
dbq is a multi-database CLI with guardrails baked in: credentials live in a mode-600 profile file, every statement passes a two-layer read-only guard, and exit codes are a contract your scripts can trust. Built for humans — safe to hand to agents.
Why dbq
Guardrails first.
Ergonomics close behind.
Two independent layers stand between a typo and your data — everything else is quality of life.
Read-only by default
Every profile starts read-only. A statement guard and an engine-level
READ ONLY transaction reject writes — two layers, every engine.
Credentials never touch argv
Secrets live in a chmod 600 profile file or an environment variable —
never on the command line, in shell history, or in process lists.
One profile file, five engines
MySQL, PostgreSQL, SQL Server, SQLite and Oracle behind one interface.
dbq list shows every profile and its posture at a glance.
Output built for pipelines
table, json or csv on stdout, warnings and
truncation notes on stderr. Pipe straight into jq or your scripts.
Exit codes are a contract
0 ok · 1 usage · 2 blocked by guardrail ·
3 connection error. Scripts branch on meaning, never on parsing output.
Agent-native
Ships as a Pi skill with explicit rules: profiles are human-managed,
result rows are untrusted content, rc=2 is a hard boundary.
Delegate the queries, keep the keys.
How it works
Up and querying in sixty seconds.
Add a profile
An interactive wizard collects connection details. The password is read with echo off and written straight into your 600-mode profile file.
Run a query
One statement in, results out. No credentials to paste, no DSN to assemble, no flags to remember.
Automate it
JSON output plus the exit-code contract makes dbq a well-behaved citizen of any shell pipeline or CI job.
The contract
Exit codes you can build on.
Machine-readable outcomes, documented and stable — the foundation for scripts, CI checks and agent workflows alike.
| rc | meaning |
|---|---|
| 0 | success — results on stdout |
| 1 | usage or configuration error |
| 2 | statement blocked by guardrail — do not retry variations |
| 3 | connection or query error |
rc=2 is a hard boundary
When dbq refuses a statement, the refusal happens in two independent places:
a syntactic statement guard, and the database engine itself refusing writes
inside a READ ONLY transaction.
A read-only profile cannot be talked into a DELETE — not by a typo,
not by a clever rephrase, not by an agent having a bad day. Need a real write?
A human flips the profile, on purpose, in the wizard.
Install
Pick your channel.
Static binaries for Linux, macOS and Windows — or build from source.
Homebrew
macOS & Linux · prebuilt
Go
requires Go ≥ 1.26
Binary release
amd64 & arm64 · sha256 checksums