Find the real shape
catalog finds tables. context returns schema, useful statistics, sample values, and existing knowledge in one call.
Persistent memory for data exploration
qdo is a deterministic CLI for discovering un-modeled data, recording what an investigation learns, and feeding that knowledge into every investigation that follows—for you, your team, and your coding agent.
The product is the loop
The commands look familiar. Their combined effect is not: a fact discovered today becomes context, a quality rule, and a portable team artifact tomorrow.
catalog finds tables. context returns schema, useful statistics, sample values, and existing knowledge in one call.
values --write-metadata can turn the observed values of a status column into provenance-tracked YAML.
Later context calls surface the values automatically. quality treats inferred values as observations until a human approves them as a constraint.
report table creates human-readable HTML. bundle export carries metadata and column sets to another project.
Why another data tool?
Imagine asking an agent for monthly revenue. A sample shows four order statuses, so the agent excludes cancelled. The query is valid, plausible—and silently includes rare test orders that the sample missed.
unit_price represents.valid_values includes test, even when a row sample does not.unit_price is the purchase-time price.This is the mechanism qdo is built to provide, not a claim that the benchmark is already won. The project plan explicitly calls for a comparative hallucination benchmark before claiming qdo outperforms prose notes.
Start small: one table, one fact
The goal is not to learn qdo. The goal is to feel the compounding loop once. Use a SQLite file, focus on one useful table, and record one string column with 1–19 distinct values.
Find a table connected to a real question.
Read one combined context response before writing SQL.
Choose one enum-like column such as status, region, or type.
Run quality and context again. Notice that the file is now part of the tool's behavior.
Only now write the query that motivated the exploration.
From a source checkout (0.2.0 is prepared but not yet on PyPI)
git clone https://github.com/curtisalexander/querido.git ~/src/querido
uv tool install ~/src/querido
cd /path/to/your/data-project
# Substitute your database, table, column, and question
qdo catalog -c ./data.db
qdo context -c ./data.db -t orders
qdo values -c ./data.db -t orders -C status --write-metadata
qdo quality -c ./data.db -t orders
qdo context -c ./data.db -t orders
qdo query -c ./data.db --sql \
"select status, count(*) from orders group by status"
The durable fact is ordinary YAML
columns:
- name: status
valid_values:
value: [cancelled, delivered, pending, shipped]
source: values
confidence: 0.8
written_at: 2026-07-25T12:00:00+00:00
author: your-name
qdo writes under .qdo/metadata/. Automated writes keep provenance, do not replace human-authored fields by default, and can be reviewed or reversed with qdo metadata undo. If the command writes zero fields, choose a smaller string enum: qdo deliberately does not infer an allowed set from truncated, non-string, or 20+-value results.
Working with a coding agent
Humans and agents use the same CLI. JSON output makes results parseable; deterministic next_steps provide a map; plain files make every captured fact reviewable in Git.
Run qdo agent install skill in the project where the agent works. The provider-neutral skill teaches the preferred routes and output contract.
Ask the agent to investigate one table or business question, use qdo before inventing identifiers, and avoid metadata writes until it has evidence.
For agents, add -f json. The response separates command-specific data from provenance and suggested next actions.
Let deterministic scans write machine-derived facts. Ask before adding business descriptions, ownership, PII labels, or interpretive notes.
Use assert for the assumptions behind an answer and quality for constraints that should remain true.
Review the YAML diff, create a report for people, or export a bundle so another project can begin with the same knowledge.
A useful first prompt
Use qdo to investigate the orders table before writing SQL.
Start with structured context, follow only next steps that answer the question,
and verify every table, column, join, and filter value rather than guessing.
Do not write business metadata without asking me. If you discover a deterministic
fact worth preserving, propose the metadata change and show me the diff.
Finish with the answer, the assumptions you checked, and what the next session
will inherit.
The external API
qdo is CLI-first. It ships type annotations for contributors, but querido.core, querido.connectors, and querido.output are internal modules—not a supported Python embedding API.
Command-specific data stays inside a stable agent-facing envelope. Results go to stdout; progress goes to stderr.
{
"command": "context",
"data": { "table": "orders", "columns": [] },
"next_steps": [
{ "cmd": "qdo values ...", "why": "..." }
],
"meta": {
"connection": "./data.db",
"table": "orders",
"generated_at": "...",
"qdo_version": "0.2.0"
}
}
Failures use a distinct object. Documented or contract-tested codes and try_next records receive compatibility treatment; message wording does not.
{
"error": true,
"code": "TABLE_NOT_FOUND",
"message": "...",
"try_next": [
{ "cmd": "qdo catalog ...", "why": "..." }
]
}
.qdo/metadata/; merged into later scans and quality checks..qdo/sessions/; useful for review, replay, and SQL reuse.Where functionality lives
The source tree follows the journey from argv to a database engine and back to a human or machine result. The boundaries matter more than the number of commands.
cli/Typer commands, option resolution, friendly errors, connector lifecycles, progress, and output selection. This is the application composition boundary.
core/Backend-neutral operations and product policy: context, quality, query safety, metadata rules, sessions, bundles, and experimental workflows.
connectors/The context-managed connector protocol plus SQLite, DuckDB, and Snowflake adapters. Driver errors are translated at this boundary.
sql/Jinja rendering and dialect-specific .sql templates. Identifiers are validated before interpolation; values use driver parameters.
output/The JSON envelope and human renderers for rich terminal output, CSV, YAML, Markdown, HTML, and single-file reports.
integrations/The provider-neutral coding-agent skill and workflow guidance, packaged into the wheel so agents can learn qdo outside this repository.
config.py / cache.pyVersioned connection, column-set, and local-cache persistence. This infrastructure does not own exploration policy or presentation.
Stable core command names and documented options; JSON success envelopes; documented or contract-tested error codes and recovery records; versioned metadata, config, and bundle formats; querido.__version__. Experimental session and workflow contracts have no compatibility promise.
Importable core functions, connector implementations, renderer registries, module names, and signatures. If embedding demand appears, the intended answer is a small explicit querido.api facade.
Reveal more only when needed
After the one-table loop feels natural, expand by outcome. Workflows and the TUI can wait.
Trust boundaries and sharp edges
These constraints keep qdo understandable, deterministic, and cheap to adopt—but contributors and agents should know where the edges are.
QDO_EXPERIMENTAL=1 and carry no compatibility promise.A good first milestone
Pick one table. Capture one verified fact. Read it back. Use it in an answer. Then decide whether the next useful move is deeper analysis, a check, a report, or a bundle—not another tour of features.