Announcing Fihrist
Fihrist brings versioned enterprise table contracts and governed agent reads to the QueryGraph stack.
An AI assistant can discover a table and still misunderstand what it is allowed to do with it. A column name does not establish its business meaning. A classification label does not grant access. A query plan does not guarantee that the policy and snapshot will remain valid until the rows return.
Fihrist is the enterprise registry for QueryGraph. It gives tables an explicit, versioned contract: stable field IDs, types, semantic terms, ownership, stewardship, retention declarations, classification and an exact policy binding. The implementation is Rust, using edition 2024 across the work we are adding to the stack.
The contract above the catalog
Fihrist sits above the physical lakehouse catalog. It describes what an enterprise table means and checks whether a proposed revision preserves that meaning. LakeCat owns the physical table and governed operations. Sail plans and executes reads. TypeSec evaluates policy and supplies identity primitives. Grust and Marciana contribute the graph and semantic workflow infrastructure, with QueryGraph composing the agent-facing service.
That separation matters. The requesting agent supplies a bounded intent. The trusted deployment supplies the registry, authenticated identity, policy engine, warehouse, catalog origin and backend credentials. An intent cannot replace those choices with its own metadata URL or storage path.
{
"table": "customers",
"columns": ["customer_id"],
"purpose": "analytics",
"limit": 100
}The service checks the purpose and every projected column before catalog work. It then checks that the physical schema and registry pins match the reviewed contract. Planning selects the exact current snapshot. Execution has its own authorization boundary and revalidates before releasing buffered rows.
A proposal is not a publication
Fihrist accepts mutable authoring documents and constructs an immutable registry only after validation. Unknown fields, invalid type alternatives, duplicate identities and incomplete protection declarations fail closed.
Its successor rules are deliberately conservative. Existing fields retain their IDs, names, types, nullability and meaning. A compatible revision can append optional fields with fresh IDs. Changing an existing table advances its revision exactly once. A revision number cannot excuse a breaking change.
The CLI and validate_fihrist MCP tool let an assistant propose and check a document. They do not silently publish it or confer permission to query its tables. Publication remains an explicit deployment operation with a reviewed digest and catalog reconciliation.
Real rows through the whole boundary
We built QueryGraph and the prepared LakeCat/Sail integration on the grust EC2 machine and ran the Fihrist acceptance path there. The test creates real Iceberg metadata and Parquet data. It stores records for different tenants and a private email column, then asks for the allowed customer ID.
Both the direct Rust MCP session and the Python CLI handoff to Rust passed. The result contained the permitted row and projection. The test independently verified the row and evidence digests. Forbidden columns, forbidden purposes, stale catalog state and missing backend data returned no protected row set.
The most useful tests change the world after the engine has already read the data. We revoked the purpose, changed the registry binding and advanced the snapshot in separate runs. The owner discarded the buffered result in each case. A check only at the beginning of the request would not demonstrate that property.
The final phase closed the old consumers, applied a reviewed registry successor, reconciled the catalog and restarted consumers for the new digest. They read real rows under revision two.
These are correctness results on small fixtures. The execution extension uses prepared sources and is not yet a claim that every dependency has a published release. Nor is this a throughput benchmark or a distributed transaction across catalog, source control and process deployment.
A registry with limits
Fihrist declares primary keys and retention requirements; ingestion and lifecycle systems must enforce them against stored rows. Classification is a sensitivity declaration, while TypeSec and the execution boundary enforce access. The current protocol keeps nested schemas and relationship constraints outside its supported vocabulary.
This makes unsupported requirements visible. A consumer should reject a constraint it cannot enforce, rather than carry the words forward while losing their effect.
The MCP implementation follows the same approach. It bounds messages and in-flight governed requests, supports cancellation and applies request deadlines. A signed planning intent cannot substitute for a signed execution intent. Catalog requests use fresh TypeSec envelopes instead of replaying one static credential.
The book and executable demo

The Fihrist book explains the table contract, Rust validation boundary, compatible revisions, catalog projection, governed execution and operational recovery. It includes concrete JSON and command examples and distinguishes the properties enforced by each component.
Read it through the First Pair library, with stable PDF and EPUB links and the web reader.
The source is in querygraph/fihrist. The executable stack demonstration and integration fixtures live in querygraph/querygraph, under demo/fihrist/ and integration/fihrist/.
Fihrist gives an agent a reviewed inventory to consult, while preserving the authority of the systems that own the data. The next step is to carry that contract through every operation that depends on it, with evidence that the actual rows obeyed the actual boundary.
published with omnighost · Git b2d323ce425e · SHA-256 0d459e0197e45f361197c1864fd2b8ed91329dfde356936e67d955691db26a47