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.
$ qy exec shop --sql "select …" --format json ✓ exit 0 — auto LIMIT applied $ qy exec shop --sql "delete from orders" ✗ exit 8 — blocked without --write
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.
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.
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.
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.
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.
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.
connections · execution · introspection · safety rails · result contract
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.
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.
[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
-- @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.
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.
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.
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.
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.