Tool
query
Everything is a table, and tables compose: joins, CTEs, window functions, recursive traversals. Reach for query when the question is a count, a list, a join, or a traversal — the shapes that explore and read are not for.
You ask your agent “how big is this codebase, broken down by language?” — this is the SQL it writes. The same statement is a shell command, which is the form you script against.
Your agent calls — mcp
You call — cli
What comes back — the same on both surfaces
The size and shape of a codebase in 57 tokens. The same join reaches git history, lint findings, and
parsed spreadsheets, because they are all tables in the same database. --json emits the rows
structured, ready for jq.
Parameters
| Parameter | What it does | |
|---|---|---|
| sql | required | DuckDB SQL. DESCRIBE SELECT * FROM <view> LIMIT 0 introspects any view or macro's columns. |
| tokenBudget | optional | Results summarise themselves past this — set it to the most the answer is worth. |
| timeoutMs | optional | A hard deadline. Five minutes by default. |
The views
| View | What is in it |
|---|---|
| Files | Every indexed file: uri, path, extension, media type, size, headline, summary, structure, token count, mtime. |
| Functions | Every function and method: qualified name, declaring type, visibility, signature, return type, parameters, language, span. |
| Types | Every type: qualified name, kind, namespace, signature, what it extends and implements, span. |
| Annotations | Lint and SARIF findings, joinable straight onto the files and symbols they point at. |
| Language views | Per-language detail — csharp_types, python_imports, markdown_headings and their siblings. |
The functions
Table functions and macros that do the work you would otherwise write by hand.
| Function | What it gives you |
|---|---|
| search_pipeline(...) | Hybrid semantic and lexical search, returning scored rows you can join against anything. |
| glob_files(...) · matches_glob(...) | The address grammar, as SQL. |
| grep_matches(...) · regex_matches(...) | Streaming line-level search — no need to write your own scan. |
| git_status() · git_diff() · git_blame() | Live git, read on demand rather than indexed. |
| git_hotspots() · git_patches() | Change frequency and patch content, as tables. |
| parse(text) · xlsx(uri, sheet) | CSV, JSON, YAML, and spreadsheets, turned into rows. |
| ask(rows, intent, maxTokens) | Language-model synthesis over a result set, inside the query. |
A failed query is cheap
Guessing at a shape costs one round trip, and errors name the columns that do exist. Run
SUMMARIZE <view> or DESCRIBE first when you are unsure, and iterate.
This page names what exists. The depth behind every name ships inside the binary at help:///: the bounds, the failure modes, how they compose. It answers to explore and read exactly like your code does. Install it, and your agent has the manual.