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.
- quarry_db-0.2.0/.claude/launch.json +11 -0
- quarry_db-0.2.0/.github/ISSUE_TEMPLATE/bug_report.md +21 -0
- quarry_db-0.2.0/.github/ISSUE_TEMPLATE/feature_request.md +15 -0
- quarry_db-0.2.0/.github/PULL_REQUEST_TEMPLATE.md +7 -0
- quarry_db-0.2.0/.github/dependabot.yml +6 -0
- quarry_db-0.2.0/.github/workflows/ci.yml +63 -0
- quarry_db-0.2.0/.github/workflows/pages.yml +31 -0
- quarry_db-0.2.0/.github/workflows/release.yml +21 -0
- quarry_db-0.2.0/.gitignore +22 -0
- quarry_db-0.2.0/CHANGELOG.md +59 -0
- quarry_db-0.2.0/CODE_OF_CONDUCT.md +7 -0
- quarry_db-0.2.0/CONTRIBUTING.md +56 -0
- quarry_db-0.2.0/LICENSE +21 -0
- quarry_db-0.2.0/PKG-INFO +240 -0
- quarry_db-0.2.0/README.md +207 -0
- quarry_db-0.2.0/README.zh-CN.md +197 -0
- quarry_db-0.2.0/SECURITY.md +26 -0
- quarry_db-0.2.0/examples/workspace/connections.toml +44 -0
- quarry_db-0.2.0/examples/workspace/queries/shop/recent_orders.sql +9 -0
- quarry_db-0.2.0/pyproject.toml +47 -0
- quarry_db-0.2.0/site/assets/demo.svg +84 -0
- quarry_db-0.2.0/site/assets/gui-dark.png +0 -0
- quarry_db-0.2.0/site/assets/gui-light.png +0 -0
- quarry_db-0.2.0/site/assets/social-card.png +0 -0
- quarry_db-0.2.0/site/index.html +411 -0
- quarry_db-0.2.0/site/zh.html +411 -0
- quarry_db-0.2.0/src/quarry/__init__.py +50 -0
- quarry_db-0.2.0/src/quarry/cli.py +810 -0
- quarry_db-0.2.0/src/quarry/core.py +1149 -0
- quarry_db-0.2.0/src/quarry/gui.py +1183 -0
- quarry_db-0.2.0/src/quarry/mcp.py +296 -0
- quarry_db-0.2.0/src/quarry/redis_engine.py +135 -0
- quarry_db-0.2.0/src/quarry/tunnel.py +147 -0
- quarry_db-0.2.0/src/quarry/workspace.py +151 -0
- quarry_db-0.2.0/tests/conftest.py +64 -0
- quarry_db-0.2.0/tests/seed.sql +21 -0
- quarry_db-0.2.0/tests/test_cli.py +80 -0
- quarry_db-0.2.0/tests/test_core.py +113 -0
- quarry_db-0.2.0/tests/test_groups.py +91 -0
- quarry_db-0.2.0/tests/test_mcp.py +168 -0
- quarry_db-0.2.0/tests/test_v2.py +54 -0
|
@@ -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,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.
|
quarry_db-0.2.0/LICENSE
ADDED
|
@@ -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.
|
quarry_db-0.2.0/PKG-INFO
ADDED
|
@@ -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
|
+
[](https://github.com/Wangggym/quarry/actions/workflows/ci.yml)
|
|
39
|
+
[](https://pypi.org/project/quarry-db/)
|
|
40
|
+
[](https://pypi.org/project/quarry-db/)
|
|
41
|
+
[](LICENSE)
|
|
42
|
+
|
|
43
|
+
[中文文档 →](README.zh-CN.md) · [Website →](https://quarry.yiminlab.site)
|
|
44
|
+
|
|
45
|
+

|
|
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
|
+

|
|
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)
|