QMDC parser — convert QMD.md to a queryable object graph (JSON) and back
Project description
QMDC Parser (Python)
QMDC ↔ JSON parser for Markdown with lossless round-trip support.
Installation
cd qmdc-py
uv pip install -e .
CLI Usage
Parse (QMD.md → JSON)
# File → stdout
qmdc parse -i doc.qmd.md
# Stdin → stdout
echo "## Test [[test]]" | qmdc parse
# File → file
qmdc parse -i doc.qmd.md -o output.json
# Without metadata
qmdc parse -i doc.qmd.md --no-comments --no-syntax
# Compact JSON
qmdc parse -i doc.qmd.md --no-pretty
Rebuild (JSON → QMD.md)
# File → stdout
qmdc rebuild -i data.json
# Stdin → stdout
echo '[{"__id":"test","name":"Test"}]' | qmdc rebuild
# File → file
qmdc rebuild -i data.json -o doc.qmd.md
Formatting (parse → rebuild)
There is no separate lint command. Canonical formatting (like ruff/prettier)
is the lossless round-trip through parse → rebuild:
# Canonical formatting
qmdc parse -i doc.qmd.md | qmdc rebuild
Programmatic API
from qmdc.parser import parse, rebuild
# Parse QMD.md → JSON
markdown = """
## User [[user]]
- name: Alice
- age: 30
"""
result = parse(markdown)
# [{"__id": "user", "__label": "User", "name": "Alice", "age": 30, ...}]
# Rebuild JSON → QMD.md
qmdc = rebuild(result)
# "## User [[user]]\n\n- name: Alice\n- age: 30\n"
Testing
# From the project root
make test
# Python tests only
make py-test
# pytest directly
cd qmdc-py
uv run pytest tests/ -v
Workspace (multi-file parsing)
QMDC Parser supports workspaces — a set of related QMD.md files with cross-file reference validation.
Workspace CLI
# Parse a workspace into JSON
qmdc workspace parse ./my-project -o workspace.json
# Validate a workspace
qmdc workspace validate ./my-project
# Rebuild files from JSON
qmdc workspace rebuild workspace.json -o ./output
Query (SQL queries against a workspace)
# SQL query against a workspace (loads all workspaces recursively)
qmdc query ./my-project "SELECT __id, __kind, __label FROM objects WHERE __kind = 'Service'"
# With JSON output
qmdc query ./my-project "SELECT * FROM objects LIMIT 10" --format json
# Query via a Query object (reference to a [[id:Query]] object in the workspace)
qmdc query ./my-project "#all_services"
# Count objects and edges
qmdc query ./my-project "SELECT COUNT(*) as total FROM objects"
qmdc query ./my-project "SELECT COUNT(*) as edges FROM edges"
The query command automatically:
- Recursively finds every QMDC workspace under the given folder
- Parses all files and loads objects into SQLite
- Extracts graph edges from references between objects
- Runs the SQL query against the database
Available tables:
objects— all objects with__id,__kind,__label,__file,__line,data(JSON)edges— all graph edges withsource_id,target_id,field_name
Workspace API
from qmdc.workspace import (
scan_workspace,
parse_workspace,
validate_workspace,
query_workspace,
get_refs_to,
)
# Scan files
files = scan_workspace("/path/to/workspace")
# ['readme.qmd.md', 'users.qmd.md', 'database/tables.qmd.md']
# Parse the whole workspace
result = parse_workspace("/path/to/workspace")
# WorkspaceResult with objects, index, errors
# Query objects
tables = query_workspace(result, kind="Table")
users = query_workspace(result, object_id="users")
# Find references to an object
refs = get_refs_to(result, "database/tables.qmd.md#users")
# [("api.qmd.md", "get_users", "returns"), ...]
See the format specification for the full spec.
Status
✅ Fully implemented:
- Tokenizer (markdown-it-py)
- Header parser (all variants:
[[id]],[[id:Kind]],[[:Kind]]) - Field parser (primitives: string, number, boolean, null)
- Nested objects (H1–H6)
- Arrays (YAML notation, Markdown lists, object arrays)
- Tables
- Comments (
__comments) - Syntax metadata (
__syntax) - Types metadata (
__types) - YAML multiline syntax (
|) - Rebuild (canonical form)
- YAML blocks
- JSON blocks
- Document title (H1 without
[[id]]) - Lossless round-trip (
__level,__has_explicit_id) - CLI:
parse,rebuild - Workspace: multi-file parsing with reference validation
License
AGPL-3.0-or-later © mikilabs
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distributions
Built Distributions
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file qmdc-1.0.5-py3-none-win_arm64.whl.
File metadata
- Download URL: qmdc-1.0.5-py3-none-win_arm64.whl
- Upload date:
- Size: 4.1 MB
- Tags: Python 3, Windows ARM64
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.10
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
42364a8c65fb65ec8b5639ebd6702e8fc3fd4be35f057f07e8c505192bbff068
|
|
| MD5 |
589fa7c9a372b3f5ad10d776c0a0a37e
|
|
| BLAKE2b-256 |
2c17751acb52a83dddbccc3a046ebc4ffc2d78937a64aafdf35fa5b42ff48ec3
|
File details
Details for the file qmdc-1.0.5-py3-none-win_amd64.whl.
File metadata
- Download URL: qmdc-1.0.5-py3-none-win_amd64.whl
- Upload date:
- Size: 4.5 MB
- Tags: Python 3, Windows x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.10
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c7b2348a9f15313abd28f5c8d61782130835c1c01ee8f8d85139dced4d860c86
|
|
| MD5 |
3cd84358830ee5cb60b41960f3ba95cc
|
|
| BLAKE2b-256 |
60ffe27681f97f899e0f0753ffa230a061f72f11bd17649cecb62f5d0678d772
|
File details
Details for the file qmdc-1.0.5-py3-none-musllinux_1_1_x86_64.whl.
File metadata
- Download URL: qmdc-1.0.5-py3-none-musllinux_1_1_x86_64.whl
- Upload date:
- Size: 4.6 MB
- Tags: Python 3, musllinux: musl 1.1+ x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.10
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
055f9bc1757003719b8f53ada2c67e3278c1801d8d8f006fab8461e830cf8522
|
|
| MD5 |
e9344f1a3dab67dfe6a7c0ce68640463
|
|
| BLAKE2b-256 |
bd9e95a35626ae3298d8296db7d97e1105c181b6bbac497582d38104ab8a8f38
|
File details
Details for the file qmdc-1.0.5-py3-none-manylinux_2_28_aarch64.whl.
File metadata
- Download URL: qmdc-1.0.5-py3-none-manylinux_2_28_aarch64.whl
- Upload date:
- Size: 4.3 MB
- Tags: Python 3, manylinux: glibc 2.28+ ARM64
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.10
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f404258daebf62a4a1697a2f93367f5ec07fc72d61a854cf1ead367ef1fb41fe
|
|
| MD5 |
f99f15100eb13072f46cc5b0fc622fb6
|
|
| BLAKE2b-256 |
5b3e1e0e88715694572d65d6a7da34570574615a19e2c9162dd8c8bb05871e5f
|
File details
Details for the file qmdc-1.0.5-py3-none-manylinux_2_17_x86_64.whl.
File metadata
- Download URL: qmdc-1.0.5-py3-none-manylinux_2_17_x86_64.whl
- Upload date:
- Size: 4.6 MB
- Tags: Python 3, manylinux: glibc 2.17+ x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.10
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e97353b15071bcadf024003234643ca727f022c2544df0d9dd5298f047dbd935
|
|
| MD5 |
19f0778d72ec4e76f1a0bed3de2471c1
|
|
| BLAKE2b-256 |
ae8ad3a2133722d83753b402d320be30f19905aefd7010bb22b5805d9ce1a52a
|
File details
Details for the file qmdc-1.0.5-py3-none-macosx_11_0_arm64.whl.
File metadata
- Download URL: qmdc-1.0.5-py3-none-macosx_11_0_arm64.whl
- Upload date:
- Size: 4.4 MB
- Tags: Python 3, macOS 11.0+ ARM64
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.10
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
a1125d434c9ee01bba36865b152c2e2cfe727b08e4ecb4e76120b9a121d9aba3
|
|
| MD5 |
0dac8e06f5723138a73a6cf3f0a3bf6b
|
|
| BLAKE2b-256 |
067e96fb2ba4f6f655465659ad9a77230c5721ff9e8c2079771430529faa95fe
|
File details
Details for the file qmdc-1.0.5-py3-none-macosx_10_12_x86_64.whl.
File metadata
- Download URL: qmdc-1.0.5-py3-none-macosx_10_12_x86_64.whl
- Upload date:
- Size: 4.8 MB
- Tags: Python 3, macOS 10.12+ x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.10
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
2682d0945a992ed30b70b2d8d5aef4aed1df358062d8c85817d58fa9c74e1fa7
|
|
| MD5 |
90d45542e29827e74f096d0f45e2161a
|
|
| BLAKE2b-256 |
5dc2b2504644691d743db5ee0de4466c4023da8b3b1d8a3f0a076a9a20ac6a59
|