Getting started¶
Scan the bundled demo database: a retail schema with cryptic column names, undocumented status codes, a table without a primary key and near-duplicate tables.
Requirements¶
- Python 3.11 or newer
- uv
- Docker, for the demo database
Run the demo¶
git clone https://github.com/Quorlo/quorlo.git
cd quorlo
uv sync
docker compose up -d # Postgres with the demo schema on localhost:15432
export QUORLO_DSN=postgresql://quorlo:quorlo@localhost:15432/quorlo_demo
uv run quorlo scan
AI readiness: quorlo_demo.retail_raw (postgres)
Table Score Meaning Certified Trust Governed Findings
────────────────────────────────────────────────────────────────────────────────
daily_revenue_v2 25% 20% 0% 0% 100% 9
stg_imp_01 25% 0% 100% 0% 100% 11
cust_mstr 28% 24% 100% 0% 0% 23
ord_ln 30% 8% 100% 0% 100% 11
revenue_daily 38% 40% 0% 0% 100% 5
v_ord_summary (view) 40% 10% 100% n/a 100% 9
ord_hdr 68% 68% 100% 0% 100% 9
dim_product 100% 100% 100% 100% 100% 0
Overall: 44% across 8 tables, 77 findings
What is it? 34%
Is it the right one? 75%
Can I trust it? 14%
Am I allowed to use it? 88%
Not scored yet (no checks): lineage
Scanned 2 schemas, 8 tables, 39 columns in 0.03s
fetch 0.02s (7 queries) · checks 0.00s · scoring 0.00s · persistence 0.00s
Saved as run 20261003T174608Z-b2a84e.
Next: quorlo findings what to fix, worst table first
quorlo findings --table stg_imp_01 start with the lowest-scoring table
Each problem shows up under the question it gets in the way of. stg_imp_01 has columns named c1, c2, f1 and f2 and no documentation, so it scores 0% on Meaning. cust_mstr holds names, emails and phone numbers nobody marked as personal data, so it fails Governed. revenue_daily and daily_revenue_v2 look like the same data and neither says which to use, so both fail Certified. Almost nothing records when it was last loaded, so Trust is low everywhere. dim_product gets everything right and scores 100%.
Track progress¶
Every scan is saved. Fix something, scan again, and Quorlo tells you what changed:
Since last run (2 days ago): 44% → 48% (+4 pts), 3 resolved, 1 new
quorlo diff shows exactly which findings were resolved and which are new. See run history.
See what to fix¶
uv run quorlo findings --table cust_mstr
Findings in run 20261003T192854Z-08798e · postgres://localhost:15432/quorlo_demo (table: cust_mstr)
retail_raw.cust_mstr (28%, 23 findings)
What is it?
table.description.missing Table has no description.
fix: COMMENT ON TABLE retail_raw.cust_mstr IS '<what one row represents>';
column.description.missing nm, eml, phn, addr1, pc, cntry_cd, st, crt_dt · no column description
fix: COMMENT ON COLUMN retail_raw.cust_mstr.<column> IS '<meaning, units,
codes>';
column.name.cryptic nm, eml, phn, addr1, pc, cntry_cd, st, crt_dt · cryptic column name
fix: rename it, or explain the abbreviation in the column description
Can I trust it?
table.freshness.untracked No column shows when rows were last loaded or updated.
fix: ALTER TABLE retail_raw.cust_mstr ADD COLUMN updated_at timestamp; --
kept current by the load
Am I allowed to use it?
column.pii.unclassified nm, eml, phn, addr1, pc · looks like personal data, not marked as PII
fix: tag it as PII, or end its description with 'PII.'
Without --table, every table is listed, worst first. Each check gets one line listing the columns it applies to, and a fix: line you can adapt. Narrow the list with --dimension governance or --check column.pii.unclassified, or add --format json for scripts. All checks are explained in the checks reference.
Scan your own database¶
Point QUORLO_DSN at any Postgres database. Quorlo only needs a role that can read the system catalogs, which every role can do by default; it never selects from your tables.
export QUORLO_DSN=postgresql://readonly_user@db.internal:5432/warehouse
uv run quorlo scan --schema sales --schema finance
Keep passwords out of shell history
Pass the DSN through QUORLO_DSN rather than --dsn, or use a .pgpass file and leave the password out of the DSN entirely.
Clean up¶
docker compose down -v # stop the demo database and delete its data