Open source · MIT · Pure stdlib

The database workbench
built for the AI era

Every database tool assumes a human at the keyboard. Quarry assumes an agent — and gives it one safety-railed query kernel with many faces: CLI, GUI, agent skill, MCP.

$pipx install quarry-db
Star on GitHub
Quarry GUI — data grid with env switcher and multi-tab editor
agent session
$ qy exec shop --sql "select …" --format json
✓ exit 0 — auto LIMIT applied

$ qy exec shop --sql "delete from orders"
✗ exit 8 — blocked without --write
Why Quarry

Agents need different guarantees than humans

DBeaver, TablePlus, pgAdmin — great tools, all designed for a person clicking. But more and more queries are run by AI agents, in skills, scripts, and CI. An agent can't "be careful". The tool has to be.

{} Results a machine can parse

GUI/MCP/Python return {columns, rows, rowCount, truncated, elapsedMs, engine, sql}; CLI JSON returns row arrays — a stable, structured contract. No screen-scraping, no prose parsing.

Rails that live in the kernel

Query entry points share read-only defaults and row caps. Write authorization is explicit: CLI and MCP add prod confirmation; Python callers supply their own authorization. The GUI query interface stays read-only.

± Deterministic error contract

CLI query exit codes distinguish success, connection/execution failures and safety blocks. Parameter and command-specific errors have their own meanings; GUI/MCP/Python expose structured errors. See the contract below.

We didn't bolt a chatbot onto a database GUI.
Your agent already is one — Quarry gives it a safe socket into your data.

The human face

And a real workbench for you

qy gui serves a local, zero-build web workbench over the same kernel: grouped connection tree with an environment switcher (prod turns red), a multi-tab SQL editor with autocomplete, one-click EXPLAIN, a type-aware grid with keyboard navigation and a collapsible JSON inspector, searchable history — light & dark, English & 中文, drafts and bounded result snapshots persist when browser storage is available. Large results stay in-session. Redis keys already support a collapsible namespace tree.

Quarry GUI — data grid with env switcher and multi-tab editor
Architecture

One core, many faces

Connection management, query execution, schema introspection, and safety rails live in one importable kernel. Everything else is a thin shell. Shared fixes benefit the query interfaces; each interface defines its own authorization and error presentation.

quarry.core

connections · execution · introspection · safety rails · result contract

qy CLI — humans & scripts
qy gui local web GUI — humans
qy mcp MCP server — agents, natively
skill Claude Code & friends
Safety rails

Read-only by default. Escalation is explicit and graduated.

CLI writes require --write; prod also requires confirmation or --yes. MCP writes need server and per-call opt-in, plus confirm_prod on prod. Python callers authorize with allow_write=True; GUI queries are read-only. Read queries without an outer LIMIT default to 500 rows; --max-rows 0 disables the cap. Utility/locking queries are not rewritten; Redis caps after receipt. Environments default to dev.

0
success — rows optional
2
connection / CLI syntax error
3
query execution error
8
safety block
Workspace as code

Your connections and queries are files, not clicks

A workspace is just a directory: connections.toml plus named queries as plain .sql files with metadata headers. Version query files and credential-free configuration templates in your repo; keep real connection credentials local. Quarry aggregates multiple workspaces into one view.

connections.toml
[shop_dev]
url    = "postgresql://user:password@dev.example.com:5432/shop"
db     = "shop"
env    = "dev"

[shop_prod]
url    = "postgresql://user:password@prod.example.com:5432/shop"
db     = "shop"
env    = "prod"

[internal_db]
url      = "postgresql://user:password@127.0.0.1:5432/appdb"
ssh_host = "bastion.example.com"  # auto tunnel
queries/shop/recent_orders.sql
-- @name: recent_orders
-- @db: shop
-- @desc: Latest orders with customer names
-- @param: days (int, default=7)
SELECT o.id, c.name, o.amount, o.status
FROM orders o JOIN customers c ON c.id = o.customer_id
WHERE o.created_at > now() - make_interval(days => :days)
ORDER BY o.created_at DESC;

Same logical database across dev / staging / prod folds into an env-set — one saved query runs against any environment: qy run recent_orders --env prod.

Engines & footprint

Nearly zero dependencies

The base package and GUI use Python 3.11+ stdlib. PostgreSQL, Redis and SSH use system clients; MySQL uses an optional Python driver. The optional keeper runs in the background. No Electron or Quarry-hosted service is required.

PostgreSQL · system psql MySQL · optional pymysql Redis · redis-cli 6+ Neptune · experimental openCypher SSH tunnels · system ssh SQLite · planned DuckDB · planned

Neptune is experimental: the openCypher endpoint integration is available, but real AWS/IAM behavior has not completed release acceptance. The local empty endpoint does not execute or store graph data. See the support and interface contract for tested environments, persistence limits and error codes.

A real library, importable

from quarry import run_query — the same kernel the CLI, GUI and MCP server use is three lines away in your own tooling, with shared query policies and a structured QueryResult; CLI JSON renders row arrays.

Local app, your databases

Quarry does not upload connection credentials, queries or results to a Quarry service. Queries go to your configured databases. The GUI binds to localhost by default and checks local origins; PyPI update checks can be disabled with QUARRY_UPDATE_CHECK=0.

Roadmap

Where this is going

SQLite & DuckDB engines zero-setup local experience
Column types in the result contract for all engines
Cross-env diff compare schema & data across environments
Write audit log who ran what, where, when
Single binary distribution beyond pip/pipx
$pipx install quarry-db
View source on GitHub