The dedicated book walks this assembly in depth; here is the whole
system in one sitting — the sequence the dataverse-e2e and
lakehouse commands automate, each step naming the component that owns
it:
SAIL_SQL expressions; metrics get
per-dialect SQL; ontology terms link shared meaning.did:oyd documents from seeds; the same seed
yields the same identity in both languages.CanReadDatasetCompartment,
CanDeriveRedactedSummary,
CanAggregateSummaries, … — proofs, not flags.# The compressed version of all ten:
cargo run -- dataverse-e2e --live-sail --call-ollama \
--question "Which governed datasets are relevant?"The full path, using only released commands:
# 1. Start the platform.
cargo run -- serve --port 8080 --require-auth
# 2. Import semantics — from a Croissant document (or LakeCat's
# bootstrap projection, Chapter 6, or an OSI YAML).
python - <<'PY'
from querygraph.api_auth import governed_post
from querygraph.typedid import TypeDidAgent
agent = TypeDidAgent.new("ApiClient")
croissant = {
"name": "Energy Burden",
"recordSet": [{"field": [
{"name": "monthly_cost", "description": "Monthly energy cost"}]}],
}
print(governed_post("http://127.0.0.1:8080",
"/v1/models/import/croissant", croissant, agent))
# {'imported': 'energy_burden_semantic_model', 'datasets': 1, …}
PY
# 3. Search it — open route, no auth needed for reads.
curl -s 'http://127.0.0.1:8080/v1/search?q=monthly'
# {"matches": [{"kind": "field", "name": "monthly_cost", …}]}
# 4. Ask — governed route, signed envelope required.
python - <<'PY'
from querygraph.api_auth import governed_post
from querygraph.typedid import TypeDidAgent
result = governed_post("http://127.0.0.1:8080", "/v1/answer",
{"question": "What drives monthly energy burden?"},
TypeDidAgent.new("ApiClient"))
print(result["answer"]) # planned over sail.qg_lakehouse.energy_burden
print(result["envelope"]["payload_sha256"][:16]) # …and it's signed
PY
# 5. Verify the answer's envelope — anyone can, with no shared state.
curl -s -X POST http://127.0.0.1:8080/v1/audit/verify-envelope \
-H 'content-type: application/json' -d @answer-envelope.jsonEvery hop leaves evidence: the import is authorized by a path-bound envelope, the answer carries its plans and receipts, and the verification endpoint lets a third party check the signature.
The second integration walkthrough runs the whole chain over live research data: Harvard Dataverse, the largest public Dataverse instance. One command — every step of Chapter 23, against data QueryGraph has never seen:
cargo run -- dataverse-e2e \
--dataverse-url https://dataverse.harvard.edu \
--query "municipal finance" --limit 2 \
--question "Which governed datasets describe municipal fiscal capacity?" \
--openlineage-file lineage.jsonl --did-ledger-file did-ledger.jsonlWhat happened, from a real run:
1. Live search and staging. The Dataverse Search API
returned two real datasets — Graduate School Rankings for Public
Administration Programs (doi:10.7910/DVN/YTAB7V) and
Data Files for Criminal Municipal Courts
(doi:10.7910/DVN/AXNUVP) — whose metadata and file listings
were staged into Sail as typed views
(dataverse_7424459_metadata,
dataverse_7424459_files, …).
2. Semantics, derived not hand-written. Each dataset
projected to Croissant; an OSI model
(querygraph_dataverse_navigator) was built over both, with
ontology terms from their subjects and keywords; the four-layer bundle
was generated for the first dataset.
3. The dual gate, with a receipt. The agent’s
answer action passed RBAC (role navigator
matched) and ODRL, and the receipt says so:
{
"action": "answer",
"allowed": true,
"principal": "did:oyd:zQmX7Cm5eikMzwMavBT4zoTUAsWxK3zGwqSbFHu729gb41r",
"rbac": {"allowed": true, "matched_roles": ["navigator"]},
"odrl_allowed": true,
"reason": "TypeSec capabilities, RBAC role assignment, and ODRL
policy allow the answer path"
}4. The signed request. The governed prompt —
question plus the staged metadata, nothing else — traveled in a
typedid/a2a envelope (signature: a16f2cba…),
ready for --call-ollama to carry it, DID-encrypted and
prompt-bound, to a local model.
5. Lineage over DOIs. The OpenLineage event lists
the DOIs as inputs (doi:10.7910/DVN/YTAB7V,
doi:10.7910/DVN/AXNUVP), carries the semantic bundle hash
as a job facet, gets a spec-conformant run id
(f0539cd9-853f-589b-a70f-a9371f532c20 — UUIDv5, derived
from the envelope signature), lands in lineage.jsonl, and
is anchored by an Ed25519 attestation whose issuer is a resolvable
did:key.
Add --live-sail --sail-endpoint http://127.0.0.1:50051
to execute against a running Sail server (views become queryable from
PySpark), --call-ollama --ollama-model llama3.2 for live
synthesis through the TypeDID gateway, --anchor-codata to
anchor the bundle DID with the CODATA ODRL service, and
--openlineage-url http://localhost:5000 to emit straight
into Marquez.
The point of this walkthrough: nothing above was fixture data. The evidence chain — receipts, envelopes, DOI-level lineage, attestation — assembled itself around unfamiliar, live research data with one command.
Claude Code / Desktop (MCP, stdio). Point the client at either server:
{"mcpServers": {"querygraph": {
"command": "querygraph", "args": ["mcp-serve", "--osi", "model.yaml"]}}}LangChain. Either consume the MCP server via
langchain-mcp-adapters, or wrap governed agents
natively:
from querygraph.agents import TypeDidLangChainToolAdapter, deterministic_specialist
from querygraph.typedid import TypeDidAgent
finance = TypeDidAgent.new("FinanceAgent")
adapter = TypeDidLangChainToolAdapter(
finance, deterministic_specialist(finance, summary="Fiscal summary…"))
tool = adapter.as_async_tool() # a StructuredTool; results carry envelopesPydanticAI / OpenAI Agents SDK / LlamaIndex /
CrewAI. All speak MCP — querygraph mcp-serve is
the one integration. For direct function-calling, export schemas with
to_tool_schema() (Chapter 20).
Local and hosted LLMs. The navigator loop binds any
OpenAI-compatible endpoint
(openai_compatible_llm(base_url, model)); the Rust Ollama
path wraps calls in DID-encrypted, prompt-bound envelopes so even the
inference call is attributable.
Your own governance. Both the MCP server and the
loop accept your OSI model (--osi) and your RBAC+ODRL
policy (--rights governance.json —
{"rbac": {...}, "odrl": {...}}); the demo policies are
defaults, not assumptions.
Build and test.
cd qg-rust && cargo test # 40 tests; clippy -D warnings in CI
cd qg-python && uv sync --extra all && uv run pytest # 49 tests,
# including the live cross-language contractRun. serve (with
--require-auth in anything shared), mcp-serve,
qglake-story, answer, navigator,
verify-envelope, lakecat-import,
dataverse-e2e --live-sail --call-ollama for the full
kitchen sink.
CI. GitHub Actions in every repo; qg-rust’s workflow
assembles the sibling grust/lakecat layout to
satisfy the path dependencies; qg-python builds the wheel and
twine checks it on a 3.11/3.13 matrix.
Release discipline. SemVer with codename pools per
repo (birds of prey, Venetian landmarks, wild cats); coordinated stack
waves; CHANGELOGs and RELEASES logs; versioned book artifacts
(stem (version-hash).{epub,pdf}) published per release;
GitHub releases with attached wheels.
Documentation. Two books in
qg-rust/docs — the dedicated QueryGraph book
(book/) and this guide (guide/) — plus the
review deck (slides/) and the one-pager in HTML, typst, and
troff (onepager/), all rebuilt at each release hash.
qg-rust (cargo run -- <command> or
the querygraph binary):
| Command | What |
|---|---|
navigator |
build the four-layer bundle |
anchor-url |
CODATA ODRL URL→DID anchoring |
dataverse-e2e |
the live chain (Chapter 25); --live-sail,
--call-ollama, --anchor-codata,
--openlineage-{file,url,sail} |
lakehouse-load / lakehouse-verify /
lakehouse-validate |
stream files into typed Sail Parquet; verify and validate |
lakecat-verify / lakecat-import |
bootstrap-bundle verification and import planning |
qglake-story [--json] |
the Resilience Desk |
verify-envelope --file |
envelope verification (exit 1 on failure) |
serve [--port] [--require-auth] |
the /v1 API + agent card |
agent-card [--base-url] |
print the A2A card |
mcp-serve |
MCP over stdio |
qg-python (querygraph <command>):
navigator, anchor-url,
qglake-story, lakehouse-register,
audit-register, pyspark-examples,
answer (--osi, --rights,
--llm-base-url, --llm-model),
agent-card, mcp-serve (--osi,
--rights, --transport).