quarry-db 0.2.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. quarry_db-0.2.0/.claude/launch.json +11 -0
  2. quarry_db-0.2.0/.github/ISSUE_TEMPLATE/bug_report.md +21 -0
  3. quarry_db-0.2.0/.github/ISSUE_TEMPLATE/feature_request.md +15 -0
  4. quarry_db-0.2.0/.github/PULL_REQUEST_TEMPLATE.md +7 -0
  5. quarry_db-0.2.0/.github/dependabot.yml +6 -0
  6. quarry_db-0.2.0/.github/workflows/ci.yml +63 -0
  7. quarry_db-0.2.0/.github/workflows/pages.yml +31 -0
  8. quarry_db-0.2.0/.github/workflows/release.yml +21 -0
  9. quarry_db-0.2.0/.gitignore +22 -0
  10. quarry_db-0.2.0/CHANGELOG.md +59 -0
  11. quarry_db-0.2.0/CODE_OF_CONDUCT.md +7 -0
  12. quarry_db-0.2.0/CONTRIBUTING.md +56 -0
  13. quarry_db-0.2.0/LICENSE +21 -0
  14. quarry_db-0.2.0/PKG-INFO +240 -0
  15. quarry_db-0.2.0/README.md +207 -0
  16. quarry_db-0.2.0/README.zh-CN.md +197 -0
  17. quarry_db-0.2.0/SECURITY.md +26 -0
  18. quarry_db-0.2.0/examples/workspace/connections.toml +44 -0
  19. quarry_db-0.2.0/examples/workspace/queries/shop/recent_orders.sql +9 -0
  20. quarry_db-0.2.0/pyproject.toml +47 -0
  21. quarry_db-0.2.0/site/assets/demo.svg +84 -0
  22. quarry_db-0.2.0/site/assets/gui-dark.png +0 -0
  23. quarry_db-0.2.0/site/assets/gui-light.png +0 -0
  24. quarry_db-0.2.0/site/assets/social-card.png +0 -0
  25. quarry_db-0.2.0/site/index.html +411 -0
  26. quarry_db-0.2.0/site/zh.html +411 -0
  27. quarry_db-0.2.0/src/quarry/__init__.py +50 -0
  28. quarry_db-0.2.0/src/quarry/cli.py +810 -0
  29. quarry_db-0.2.0/src/quarry/core.py +1149 -0
  30. quarry_db-0.2.0/src/quarry/gui.py +1183 -0
  31. quarry_db-0.2.0/src/quarry/mcp.py +296 -0
  32. quarry_db-0.2.0/src/quarry/redis_engine.py +135 -0
  33. quarry_db-0.2.0/src/quarry/tunnel.py +147 -0
  34. quarry_db-0.2.0/src/quarry/workspace.py +151 -0
  35. quarry_db-0.2.0/tests/conftest.py +64 -0
  36. quarry_db-0.2.0/tests/seed.sql +21 -0
  37. quarry_db-0.2.0/tests/test_cli.py +80 -0
  38. quarry_db-0.2.0/tests/test_core.py +113 -0
  39. quarry_db-0.2.0/tests/test_groups.py +91 -0
  40. quarry_db-0.2.0/tests/test_mcp.py +168 -0
  41. quarry_db-0.2.0/tests/test_v2.py +54 -0
@@ -0,0 +1,11 @@
1
+ {
2
+ "version": "0.0.1",
3
+ "configurations": [
4
+ {
5
+ "name": "quarry-gui",
6
+ "runtimeExecutable": "python",
7
+ "runtimeArgs": ["-c", "from quarry import gui; gui.serve(port=8792, open_browser=False)"],
8
+ "port": 8792
9
+ }
10
+ ]
11
+ }
@@ -0,0 +1,21 @@
1
+ ---
2
+ name: Bug report
3
+ about: Something broke
4
+ labels: bug
5
+ ---
6
+
7
+ **What happened**
8
+
9
+ **What you expected**
10
+
11
+ **Reproduce**
12
+
13
+ ```bash
14
+ # minimal commands / SQL / connections.toml (redact credentials!)
15
+ ```
16
+
17
+ **Environment**
18
+ - Quarry version (`qy --version` or `pip show quarry-db`):
19
+ - Engine (postgres/mysql/redis) + server version:
20
+ - OS / Python version:
21
+ - Exit code, if using the CLI:
@@ -0,0 +1,15 @@
1
+ ---
2
+ name: Feature request
3
+ about: An idea for Quarry
4
+ labels: enhancement
5
+ ---
6
+
7
+ **The problem**
8
+ <!-- What are you trying to do that Quarry can't (or makes painful)? -->
9
+
10
+ **Proposed solution**
11
+
12
+ **Which face(s) does it touch?**
13
+ <!-- kernel / CLI / GUI / agent-skill / MCP -->
14
+
15
+ **Does it interact with the safety rails or the result/exit-code contract?**
@@ -0,0 +1,7 @@
1
+ **What & why**
2
+
3
+ **Checklist**
4
+ - [ ] Tests added/updated, `python3 -m pytest -q` passes
5
+ - [ ] Kernel stays stdlib-only (new deps are optional extras)
6
+ - [ ] Safety rails unaffected, or the change is discussed in an issue
7
+ - [ ] Result shape / exit codes unchanged (or additive only)
@@ -0,0 +1,6 @@
1
+ version: 2
2
+ updates:
3
+ - package-ecosystem: github-actions
4
+ directory: /
5
+ schedule:
6
+ interval: monthly
@@ -0,0 +1,63 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+
8
+ jobs:
9
+ test:
10
+ runs-on: ubuntu-latest
11
+ strategy:
12
+ fail-fast: false
13
+ matrix:
14
+ python-version: ["3.11", "3.12", "3.13"]
15
+
16
+ services:
17
+ postgres:
18
+ image: postgres:16
19
+ env:
20
+ POSTGRES_USER: quarry
21
+ POSTGRES_PASSWORD: quarry
22
+ POSTGRES_DB: quarry_test
23
+ ports:
24
+ - 5432:5432
25
+ options: >-
26
+ --health-cmd "pg_isready -U quarry"
27
+ --health-interval 5s
28
+ --health-timeout 5s
29
+ --health-retries 10
30
+
31
+ env:
32
+ QUARRY_TEST_DB_URL: postgresql://quarry:quarry@localhost:5432/quarry_test
33
+
34
+ steps:
35
+ - uses: actions/checkout@v4
36
+
37
+ - uses: actions/setup-python@v5
38
+ with:
39
+ python-version: ${{ matrix.python-version }}
40
+
41
+ - name: Install psql client
42
+ run: sudo apt-get update && sudo apt-get install -y --no-install-recommends postgresql-client
43
+
44
+ - name: Install package
45
+ run: pip install -e ".[dev]"
46
+
47
+ - name: Seed test database
48
+ run: psql "$QUARRY_TEST_DB_URL" -f tests/seed.sql
49
+
50
+ - name: Run tests
51
+ run: python3 -m pytest -q
52
+
53
+ build:
54
+ runs-on: ubuntu-latest
55
+ steps:
56
+ - uses: actions/checkout@v4
57
+ - uses: actions/setup-python@v5
58
+ with:
59
+ python-version: "3.12"
60
+ - name: Build sdist + wheel
61
+ run: pipx run build
62
+ - name: Check metadata
63
+ run: pipx run twine check dist/*
@@ -0,0 +1,31 @@
1
+ name: Deploy site to GitHub Pages
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ paths: ["site/**"]
7
+ workflow_dispatch:
8
+
9
+ permissions:
10
+ contents: read
11
+ pages: write
12
+ id-token: write
13
+
14
+ concurrency:
15
+ group: pages
16
+ cancel-in-progress: true
17
+
18
+ jobs:
19
+ deploy:
20
+ runs-on: ubuntu-latest
21
+ environment:
22
+ name: github-pages
23
+ url: ${{ steps.deployment.outputs.page_url }}
24
+ steps:
25
+ - uses: actions/checkout@v4
26
+ - uses: actions/configure-pages@v5
27
+ - uses: actions/upload-pages-artifact@v3
28
+ with:
29
+ path: site
30
+ - id: deployment
31
+ uses: actions/deploy-pages@v4
@@ -0,0 +1,21 @@
1
+ name: Release to PyPI
2
+
3
+ on:
4
+ release:
5
+ types: [published]
6
+
7
+ jobs:
8
+ publish:
9
+ runs-on: ubuntu-latest
10
+ environment: pypi
11
+ permissions:
12
+ id-token: write # PyPI Trusted Publishing (no API token needed)
13
+ steps:
14
+ - uses: actions/checkout@v4
15
+ - uses: actions/setup-python@v5
16
+ with:
17
+ python-version: "3.12"
18
+ - name: Build
19
+ run: pipx run build
20
+ - name: Publish to PyPI
21
+ uses: pypa/gh-action-pypi-publish@release/v1
@@ -0,0 +1,22 @@
1
+ # Python
2
+ __pycache__/
3
+ *.py[cod]
4
+ *.egg-info/
5
+ .pytest_cache/
6
+ build/
7
+ dist/
8
+ .venv/
9
+ venv/
10
+
11
+ # Quarry — never commit a workspace with real connection secrets
12
+ connections.toml
13
+ workspace/
14
+ *.local.toml
15
+ # ...but the credential-free example workspace ships with the repo
16
+ !examples/workspace/
17
+ !examples/workspace/connections.toml
18
+
19
+ # OS / editor
20
+ .DS_Store
21
+ .idea/
22
+ .vscode/
@@ -0,0 +1,59 @@
1
+ # Changelog
2
+
3
+ All notable changes to Quarry are documented here. The format follows
4
+ [Keep a Changelog](https://keepachangelog.com/en/1.1.0/); versions follow
5
+ [SemVer](https://semver.org/) (pre-1.0: minor bumps may break).
6
+
7
+ ## [Unreleased]
8
+
9
+ ## [0.2.0] — 2026-07-02
10
+
11
+ ### Added
12
+ - **MCP face** (`qy mcp`): a Model Context Protocol server over stdio, pure
13
+ stdlib. Six tools: `list_connections`, `list_tables`, `describe_table`,
14
+ `exec_sql`, `list_saved_queries`, `run_saved_query`. Graduated write policy:
15
+ server `--write` flag + per-call `write: true` + `confirm_prod: true` for prod.
16
+ - GUI: multi-tab editor (per-tab SQL + connection, persisted across restarts)
17
+ - GUI: EXPLAIN button (plan modal for postgres, grid for tabular plans)
18
+ - GUI: searchable query history with connection name and relative time
19
+ - GUI: grid keyboard navigation (arrow keys + Enter to inspect)
20
+ - GUI: collapsible JSON tree in the cell inspector
21
+
22
+ ### Fixed
23
+ - SQL errors were silently swallowed into empty results (psql now runs with
24
+ `ON_ERROR_STOP`; failed statements correctly exit with code 3)
25
+ - `EXPLAIN` / `SHOW` statements now work through `run_query` (previously broken
26
+ by the JSON subquery wrapper) and are exempt from the auto-LIMIT injection
27
+
28
+ ## [0.1.0] — 2026-07-02
29
+
30
+ First public release.
31
+
32
+ ### Core
33
+ - Multi-engine query kernel (`quarry.core`): PostgreSQL (via system `psql`),
34
+ MySQL (optional `pymysql`), Redis (via `redis-cli`)
35
+ - Structured result contract: `{columns, rows, rowCount, truncated, elapsedMs, engine, sql}`
36
+ - Safety rails in the kernel: read-only by default (`--write` to allow),
37
+ automatic `LIMIT 500` row cap, graduated prod confirmation
38
+ - Stable exit-code contract: `0` ok / `2` connection / `3` SQL / `8` safety block
39
+ - Workspace-as-code: `connections.toml` + named queries (`queries/**/*.sql`
40
+ with `-- @meta` headers); multi-workspace aggregation via
41
+ `~/.config/quarry/config.toml`
42
+ - Connection groups and env-sets (same logical db across dev/prod/…,
43
+ `--env` switch, dev default)
44
+ - SSH tunnels via system `ssh` (`ssh_*` connection fields)
45
+
46
+ ### CLI (`qy`)
47
+ - `connections` (list/add/set/remove/test), `exec`, `run`, `save`, `list`,
48
+ `describe`, `schema`, `validate`, `fingerprint`, `audit`, `remove`, `edit`,
49
+ `workspace` (list/add/remove), `gui`
50
+ - Output formats: table / json / ndjson / csv
51
+
52
+ ### GUI (`qy gui`)
53
+ - Local zero-build web GUI, light/dark theme
54
+ - Grouped sidebar tree with environment switcher (prod highlighted red)
55
+ - SQL editor with syntax highlighting and local autocomplete (keywords/tables/columns)
56
+ - Data grid: type-aware coloring, sorting, column resize, cell/row inspection
57
+ - CSV/JSON export, query history, saved-query library
58
+ - TYPE-aware Redis key browsing
59
+ - State persists across restarts (selected connection, SQL, results cache)
@@ -0,0 +1,7 @@
1
+ # Code of Conduct
2
+
3
+ This project follows the [Contributor Covenant, version 2.1](https://www.contributor-covenant.org/version/2/1/code_of_conduct/).
4
+
5
+ In short: be respectful, be constructive, assume good faith. Harassment, personal attacks, and discriminatory language are not tolerated in issues, PRs, discussions, or any other project space.
6
+
7
+ To report unacceptable behavior, contact the maintainer through GitHub.
@@ -0,0 +1,56 @@
1
+ # Contributing to Quarry
2
+
3
+ Thanks for your interest! Quarry is young and contributions of all sizes are welcome — bug reports, docs, new engine backends, GUI polish.
4
+
5
+ ## Ground rules (design invariants)
6
+
7
+ Quarry has a few invariants that PRs must not break. If your change needs to bend one, open an issue first so we can discuss.
8
+
9
+ 1. **The kernel stays dependency-free.** `quarry.core` is pure stdlib. Engine backends may shell out to system binaries (`psql`, `redis-cli`, `ssh`) or use an *optional* extra (like `pymysql`), but nothing gets added to the required dependencies.
10
+ 2. **Safety rails live in the kernel, not in the faces.** Read-only enforcement, row caps, and prod confirmation must work identically through the CLI, the GUI, and library calls. Never implement a safety check only in one face.
11
+ 3. **The result and exit-code contracts are stable API.** `{columns, rows, rowCount, truncated, elapsedMs, engine, sql}` and exit codes `0/2/3/8` — additive changes only.
12
+ 4. **Faces stay thin.** If logic could be useful to more than one face, it belongs in `quarry.core` (or a sibling kernel module), not in `cli.py`/`gui.py`.
13
+ 5. **The kernel carries no secrets and no business logic.** Connections and queries always come from a user workspace.
14
+
15
+ ## Development setup
16
+
17
+ ```bash
18
+ git clone https://github.com/Wangggym/quarry && cd quarry
19
+ python3 -m venv .venv && source .venv/bin/activate
20
+ pip install -e ".[dev]"
21
+ ```
22
+
23
+ ### Running tests
24
+
25
+ Unit tests run with no setup:
26
+
27
+ ```bash
28
+ python3 -m pytest -q
29
+ ```
30
+
31
+ DB-backed tests need a local PostgreSQL with a seeded `quarry_test` database (they skip automatically if it's unreachable):
32
+
33
+ ```bash
34
+ createdb quarry_test
35
+ psql quarry_test -f tests/seed.sql
36
+ python3 -m pytest -q # QUARRY_TEST_DB_URL overrides the default URL
37
+ ```
38
+
39
+ ## Adding an engine backend
40
+
41
+ An engine implements: URL parsing, query execution returning the standard result shape, read-only classification for its command/statement set, and (optionally) schema introspection. Look at `redis_engine.py` for the smallest complete example, and how `core.py` dispatches on `engine`. Requirements:
42
+
43
+ - Prefer shelling out to the engine's standard client binary over adding a Python driver; if a driver is unavoidable, make it an optional extra.
44
+ - Define the read-only command set conservatively — when in doubt, a command is a write.
45
+ - Add unit tests that don't require a live server (parsing, safety classification) plus live tests guarded by a reachability skip.
46
+
47
+ ## Pull requests
48
+
49
+ - Keep PRs focused; separate refactors from behavior changes.
50
+ - Add or update tests for what you change.
51
+ - `python3 -m pytest -q` must pass.
52
+ - Describe *why*, not just *what*, in the PR body.
53
+
54
+ ## Reporting bugs / proposing features
55
+
56
+ Use the issue templates. For safety-rail bypasses (a way to execute a write without `--write`), please follow [SECURITY.md](SECURITY.md) instead of opening a public issue.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Wangggym
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,240 @@
1
+ Metadata-Version: 2.4
2
+ Name: quarry-db
3
+ Version: 0.2.0
4
+ Summary: AI-native database workbench: one safety-railed query kernel, many faces (CLI / GUI / agent skill / MCP)
5
+ Project-URL: Homepage, https://github.com/Wangggym/quarry
6
+ Project-URL: Repository, https://github.com/Wangggym/quarry
7
+ Project-URL: Changelog, https://github.com/Wangggym/quarry/blob/main/CHANGELOG.md
8
+ Project-URL: Issues, https://github.com/Wangggym/quarry/issues
9
+ Author: Wangggym
10
+ License: MIT
11
+ License-File: LICENSE
12
+ Keywords: agent,ai,cli,database,mcp,mysql,postgres,redis,sql,workbench
13
+ Classifier: Development Status :: 4 - Beta
14
+ Classifier: Environment :: Console
15
+ Classifier: Environment :: Web Environment
16
+ Classifier: Intended Audience :: Developers
17
+ Classifier: License :: OSI Approved :: MIT License
18
+ Classifier: Programming Language :: Python :: 3.11
19
+ Classifier: Programming Language :: Python :: 3.12
20
+ Classifier: Programming Language :: Python :: 3.13
21
+ Classifier: Topic :: Database
22
+ Classifier: Topic :: Database :: Front-Ends
23
+ Requires-Python: >=3.11
24
+ Provides-Extra: dev
25
+ Requires-Dist: flask>=3.0; extra == 'dev'
26
+ Requires-Dist: pymysql>=1.1; extra == 'dev'
27
+ Requires-Dist: pytest>=8.0; extra == 'dev'
28
+ Provides-Extra: gui
29
+ Requires-Dist: flask>=3.0; extra == 'gui'
30
+ Provides-Extra: mysql
31
+ Requires-Dist: pymysql>=1.1; extra == 'mysql'
32
+ Description-Content-Type: text/markdown
33
+
34
+ # Quarry
35
+
36
+ > **The database workbench built for the AI era** — one kernel, many faces (CLI / GUI / MCP / agent skill).
37
+
38
+ [![CI](https://github.com/Wangggym/quarry/actions/workflows/ci.yml/badge.svg)](https://github.com/Wangggym/quarry/actions/workflows/ci.yml)
39
+ [![PyPI](https://img.shields.io/pypi/v/quarry-db)](https://pypi.org/project/quarry-db/)
40
+ [![Python 3.11+](https://img.shields.io/badge/python-3.11%2B-blue)](https://pypi.org/project/quarry-db/)
41
+ [![License: MIT](https://img.shields.io/badge/license-MIT-green)](LICENSE)
42
+
43
+ [中文文档 →](README.zh-CN.md) · [Website →](https://quarry.yiminlab.site)
44
+
45
+ ![Quarry demo](site/assets/demo.svg)
46
+
47
+ Every database tool you know — DBeaver, TablePlus, pgAdmin — assumes a *human* at the keyboard. But increasingly, the entity running your queries is an **AI agent**, and agents need different guarantees:
48
+
49
+ - **Results a machine can parse**, not a screen a human can read
50
+ - **Safety rails that live in the kernel**, so no client can forget them
51
+ - **Deterministic error contracts** (stable exit codes), not stack traces to scrape
52
+ - **Configuration as files**, not clicks — so it can be versioned, diffed, and shared with agents
53
+
54
+ Quarry inverts the traditional design: it is a **query kernel with an agent-safe contract first**, and the human faces (CLI, GUI) are thin shells grown from the same kernel. Whether a query comes from a person in the browser, a script in CI, or Claude running a skill, it passes through the exact same safety rails and returns the exact same structured result.
55
+
56
+ ## Philosophy
57
+
58
+ 1. **One core, many faces.** Connection management, query execution, schema introspection, and safety rails live in an importable kernel (`quarry.core`). The CLI (`qy`), the GUI, the MCP server, and agent skills are thin shells. Fix a bug once, every face gets it.
59
+
60
+ 2. **Read-only by default; escalation is explicit and graduated.** Writes and DDL are blocked (exit code `8`) unless you pass `--write`. Production connections require an *additional* confirmation on top of `--write`. Every query gets an automatic `LIMIT 500` unless you opt out. Because the rails are in the kernel, an agent cannot bypass them by picking a different entry point.
61
+
62
+ 3. **A contract machines can trust.** Every query returns `{columns, rows, rowCount, truncated, elapsedMs, engine, sql}`. Exit codes are stable API: `0` ok, `2` connection error, `3` SQL error, `8` safety block. An agent can branch on outcomes without parsing prose.
63
+
64
+ 4. **Workspace as code.** A workspace is just a directory: `connections.toml` + `queries/**/*.sql` (named queries with `-- @meta` headers). It lives in *your* repo, versioned by git, shared between teammates and agents alike. The kernel itself carries zero business logic and zero secrets.
65
+
66
+ 5. **Nearly zero dependencies.** Pure stdlib. PostgreSQL goes through your system `psql`, Redis through `redis-cli`, SSH tunnels through system `ssh`. MySQL is one optional `pymysql`. No Electron, no daemon, no cloud.
67
+
68
+ ## Install
69
+
70
+ ```bash
71
+ pipx install quarry-db # or: pip install quarry-db
72
+ qy --help
73
+ ```
74
+
75
+ PostgreSQL uses the system `psql` binary; MySQL needs `pip install "quarry-db[mysql]"`.
76
+
77
+ ## Quickstart
78
+
79
+ ```bash
80
+ mkdir my-workspace && cd my-workspace
81
+ cat > connections.toml <<'EOF'
82
+ [shop]
83
+ url = "postgresql://user:pass@localhost:5432/shop"
84
+ engine = "postgres"
85
+ env = "dev"
86
+ EOF
87
+
88
+ qy connections # list connections
89
+ qy exec shop --sql "select * from customers"
90
+ qy schema shop customers # table structure (\d+)
91
+ qy gui # browser data grid
92
+ ```
93
+
94
+ ## Workspace
95
+
96
+ A workspace directory is the source of connections + queries:
97
+
98
+ ```
99
+ my-workspace/
100
+ ├── connections.toml # [key] url / engine / env / group / notes
101
+ └── queries/<db>/*.sql # named queries (with -- @meta headers)
102
+ ```
103
+
104
+ Resolution order: `--workspace PATH` → `~/.config/quarry/config.toml` → current directory.
105
+
106
+ ## CLI reference
107
+
108
+ | Command | Purpose |
109
+ |---------|---------|
110
+ | `qy connections [list\|add\|set\|remove\|test]` | Manage connections |
111
+ | `qy exec <db> --sql "..." [--format json\|ndjson\|csv\|table]` | Run ad-hoc SQL |
112
+ | `qy schema <db> <table>` | Live table structure |
113
+ | `qy run <name> [k=v ...]` | Run a saved named query |
114
+ | `qy save <name> --db X --sql "..."` | Save a named query |
115
+ | `qy list / describe / validate / fingerprint / audit` | Manage named queries |
116
+ | `qy workspace list/add/remove` | Manage aggregated workspaces |
117
+ | `qy gui` | Launch the local GUI |
118
+ | `qy mcp [--write]` | Serve the MCP face over stdio (for AI agents) |
119
+
120
+ ## MCP (the agent-native face)
121
+
122
+ `qy mcp` speaks the Model Context Protocol over stdio — pure stdlib, no SDK dependency. Agents get six tools (`list_connections`, `list_tables`, `describe_table`, `exec_sql`, `list_saved_queries`, `run_saved_query`) with the exact same kernel rails: read-only unless the server was started with `--write` *and* the call passes `write: true`; a prod env additionally requires `confirm_prod: true`.
123
+
124
+ ```bash
125
+ # Claude Code
126
+ claude mcp add quarry -- qy mcp --workspace ~/my-workspace
127
+ ```
128
+
129
+ ```json
130
+ // or any MCP client (.mcp.json)
131
+ { "mcpServers": { "quarry": { "command": "qy", "args": ["mcp", "--workspace", "/path/to/workspace"] } } }
132
+ ```
133
+
134
+ ## Safety rails (the AI-native moat)
135
+
136
+ - **Read-only by default**: writes/DDL blocked with exit code `8`; `--write` to allow
137
+ - **Automatic row cap**: `run_query()` injects `LIMIT 500`; raise with `--max-rows N`
138
+ - **Graduated prod protection**: all envs default read-only → dev needs `--write` → prod needs `--write` *plus* an interactive confirmation (`--yes` for automation)
139
+ - **Stable exit-code contract**: `0` ok / `2` connection / `3` SQL / `8` safety block
140
+
141
+ ## As a library (what the GUI and agents use)
142
+
143
+ ```python
144
+ from quarry import configure_workspace, get_connection, run_query
145
+
146
+ configure_workspace("~/my-workspace")
147
+ res = run_query(get_connection("shop"), "select * from customers")
148
+ print(res.to_dict()) # {columns, rows, rowCount, truncated, elapsedMs, engine, sql}
149
+ ```
150
+
151
+ ## SSH tunnels
152
+
153
+ For databases only reachable via a bastion, add `ssh_*` fields and `qy` opens the tunnel automatically (system `ssh`, zero dependencies):
154
+
155
+ ```toml
156
+ [internal_db]
157
+ url = "postgresql://user:pass@127.0.0.1:5432/appdb"
158
+ engine = "postgres"
159
+ ssh_host = "bastion.example.com"
160
+ ssh_user = "ubuntu"
161
+ ssh_key = "~/.ssh/id_ed25519"
162
+ ```
163
+
164
+ ## Redis
165
+
166
+ `engine = "redis"` (uses system `redis-cli`). Queries are redis commands:
167
+
168
+ ```bash
169
+ qy exec cache --sql "SCAN 0 COUNT 100"
170
+ qy exec cache --sql "HGETALL user:42"
171
+ ```
172
+
173
+ Read-only rail applies here too: `GET/SCAN/TYPE/TTL/HGETALL` pass; `SET/DEL/FLUSHALL` are blocked without `--write`. In the GUI, redis keys are clickable with TYPE-aware value display.
174
+
175
+ ## Groups & env-sets
176
+
177
+ Connections can be organized into **project folders** (`group`) and **env-sets** (same `db`, different `env`, shared schema):
178
+
179
+ ```toml
180
+ [shop_dev]
181
+ url = "postgresql://…dev…/shop"; group = "shop"; db = "shop"; env = "dev"
182
+ [shop_prod]
183
+ url = "postgresql://…prod…/shop"; group = "shop"; db = "shop"; env = "prod"
184
+ ```
185
+
186
+ - Connections with the same `db` fold into one env-set — one saved query runs against any environment: `qy exec shop --env prod`
187
+ - Unspecified env defaults to `dev` (the safest)
188
+ - The GUI shows an environment switcher (prod turns red)
189
+
190
+ ## Multiple workspaces
191
+
192
+ `qy` aggregates all workspaces listed in `~/.config/quarry/config.toml` — one GUI/CLI over all your projects:
193
+
194
+ ```bash
195
+ qy workspace add ~/projects/acme/db-workspace
196
+ qy workspace add ~/projects/side-project/db
197
+ qy connections # both projects, grouped
198
+ qy gui # sidebar shows both groups side by side
199
+ ```
200
+
201
+ `--workspace a:b` (os.pathsep-separated) works as a temporary override; the first directory is primary for writes.
202
+
203
+ ## GUI
204
+
205
+ ![Quarry GUI](site/assets/gui-dark.png)
206
+
207
+ `qy gui` — a local, zero-build web GUI (Slate & Copper theme, light/dark):
208
+
209
+ - Grouped sidebar tree with env switcher (prod turns red), connection health dots
210
+ - **Multi-tab editor** — each tab remembers its SQL + connection, across restarts
211
+ - SQL highlighting + local autocomplete (keywords / tables / columns)
212
+ - **EXPLAIN button** — one click to the query plan
213
+ - Type-aware data grid: sorting, column resize, **keyboard navigation** (arrows + Enter), cell inspection with a **collapsible JSON tree**
214
+ - CSV/JSON export, **searchable query history** (with connection + time)
215
+ - TYPE-aware Redis key browsing
216
+
217
+ ## Roadmap
218
+
219
+ - Column types in the result contract for all engines
220
+ - SQLite & DuckDB engines (zero-setup local demo)
221
+ - Redis key-namespace folding tree
222
+ - Cross-environment schema/data diff
223
+ - Write audit log (who ran what, where, when)
224
+ - Single-binary distribution
225
+
226
+ ## Development
227
+
228
+ ```bash
229
+ pip install -e ".[dev]"
230
+ createdb quarry_test && psql quarry_test -f tests/seed.sql
231
+ python3 -m pytest -q
232
+ ```
233
+
234
+ DB-backed tests skip automatically when Postgres is unreachable; unit tests always run. See [CONTRIBUTING.md](CONTRIBUTING.md).
235
+
236
+ Quarry is developed and tested on macOS and Linux. Windows is currently untested (the psql/ssh integration and port takeover are Unix-flavored) — PRs welcome.
237
+
238
+ ## License
239
+
240
+ [MIT](LICENSE)