mdxquery
why
grepping text for structural questions about a Markdown corpus is approximate: it misses frontmatter semantics, heading hierarchy, and component usage, and silently returns stale results after files change. a parsed, rebuildable index makes the same questions deterministic and current; source documents stay the only canonical authority — the index owns nothing and can be discarded at any time.
rule
treat Markdown and MDX as a queryable interface. mdxquery parses source once into a derived local SQLite index, then answers deterministic read-only SQL questions about frontmatter, headings, components, links, and content blocks. source is canonical; the index is disposable and rebuildable.
one query language
sqlite syntax only. one local query model is easier for agents, joins with project sqlite ledgers, and needs no mongodb server, credentials, or alternate predicate semantics.
installation and first use
npm install -g mdxquerymdxquery index ./datamdxquery query "SELECT path, frontmatter_json FROM documents"
the CLI finds the nearest git root and writes the index to <git-root>/.agents/db/mdxquery.sqlite. it is a derived cache: rebuild when MDX changes, never hand-edit, never treat it as the authority for a document's meaning.
query model
in-process sqlite with normalized tables:
| table | one row means | key fields |
|---|---|---|
documents | one Markdown or MDX file. | id, path, hash, kind, frontmatter_json, body, indexed_at |
frontmatter | one declared metadata field. | document_id, key, value_json |
headings | one ordered heading. | document_id, ordinal, depth, text |
components | one parsed MDX component. | document_id, ordinal, name, props_json |
links | one link or anchor. | document_id, ordinal, href, text |
blocks | one semantic AST block. | document_id, kind, ordinal, text |
document_search | one FTS5 record per document. | document_id, path, text |
frontmatter is normalized so agents write simple SQL instead of repeated JSON extraction; documents.frontmatter_json stays only as a lossless derived record.
-- Find approved standards.SELECT document.path, title.value_json AS titleFROM documents AS documentJOIN frontmatter AS kind ON kind.document_id = document.idJOIN frontmatter AS status ON status.document_id = document.idJOIN frontmatter AS title ON title.document_id = document.idWHERE kind.key = 'kind'AND kind.value_json = '"standard"'AND status.key = 'status'AND status.value_json = '"approved"'AND title.key = 'title';-- Find every document that needs Accordion support.SELECT DISTINCT document.pathFROM documents AS documentJOIN components ON components.document_id = document.idWHERE components.name = 'Accordion';
parser contract
- parse with an MDX-aware parser: record AST node type, component name and props, heading depth, link target.
- never query rendered HTML, regex-match components, or derive frontmatter from headings.
- a parse failure returns a typed diagnostic with path and source location; never insert a partial document.
CLI contract
mdxquery index <path> parses Markdown/MDX and atomically refreshes the repository-owned index. mdxquery query <read-only-sql> executes read-only SQL against it. output is always JSON.freshness
index rebuilds from source and stores each source SHA-256 in documents.hash. always run it after a document change before treating a query result as current.procedure-ledger integration
an MDX procedure and its execution ledger use two complementary sqlite stores:
mdxquery .agents/db/mdxquery.sqlite -> What knowledge and procedure documents sayledger .agents/db/procedure.sqlite -> What work is planned, applying, blocked, or verified
query standards and procedure structure with mdxquery first, then join that knowledge with the ledger's open findings. select one smallest vertical slice, record the run, update MDX contracts first, apply the refactor, append verification evidence. neither database replaces the other.
do not
- offer mongodb syntax as a second query language for the same document index.
- query MDX with string scans, regex component matching, or rendered HTML.
- allow mutating SQL against the derived MDX index through the normal CLI.
- hand-edit index rows or let a stale index masquerade as source truth.
- conflate MDX knowledge facts with the mutable execution ledger.
- query a stale index without rebuilding; always run
mdxquery indexafter document changes.
good and bad
bad
# grep-based discovery with stale sourcerg -n "status: approved" gurus | sed -n 's/.*title: //p'
guesses at YAML structure, cannot join headings or components, silently produces stale answers. an agent auditing readiness from this reads outdated results: selects the wrong slice, misses real blockers in approved files, skips standards that became unapproved. the stale answer compounds — wrong work routed, wrong audit report, resources wasted on misdirected investigation.
good
# parsed index rebuilt from current sourcemdxquery index ./datamdxquery query "SELECT path FROM documents WHERE kind = 'standard' AND status = 'approved'"
the index is rebuilt from parsed source before every query: an agent querying approved standards gets the current decision state, a status change flows into the next result immediately, and no decision rests on an outdated fact.