Kustology
Not affiliated with Microsoft. This is an independent open-source project that wraps Microsoft's publicly distributed Apache 2.0–licensed library.
Kustology gives Python programs Microsoft's own KQL parser, the one behind
Azure Data Explorer, Azure Monitor, and Microsoft Sentinel. It loads the
official Kusto.Language library through pythonnet, so queries parse exactly
as the service parses them.
The library comes in two tiers. Either one works on its own.
The two tiers
Tier 1: thin wrapper
Tier 1 exposes Microsoft's parser, formatter, and validator, and adds analyzers for the questions a KQL author asks most: which tables a query reads, which columns it touches, which operators it chains, where its time filters sit, and how to rename a table everywhere it appears. You work with Microsoft's syntax tree directly.
Tier 2: semantic IR
Tier 2 builds a typed Pydantic model of the parsed query, with classes like
FilterOp, BinOp, and ColumnRef. It suits the questions an analyzer asks:
which source table a column came from after joins, renames, and let aliases;
what schema the pipeline produces; whether two queries mean the same thing
despite formatting; how much two queries overlap or where two versions of a
rule diverge; and how to serialize the whole graph for a UI, a service, or a
language model.
Choosing a tier
Both tiers use the same parser. Pick based on the shape of data your code wants.
| Tier 1 — thin wrapper | Tier 2 — semantic IR | |
|---|---|---|
| Install | pip install kustology |
pip install 'kustology[ir]' |
| Dependencies | pythonnet + .NET 8 runtime |
adds pydantic |
| Returns | KustoQuery wrapping Microsoft's syntax tree |
QueryIR — Pydantic models |
| Traversal | Microsoft AST, dispatching on node.Kind |
Typed pipeline, dispatching on isinstance |
| Serialization | to_dict() / to_json() |
model_dump_json(), which round-trips, plus to_llm_dict() for language models |
| Schema binding | parse(query, schema=...) runs Microsoft's binder for semantic diagnostics and symbol resolution |
to_ir() on a bound parse carries per-operator schemas and column types; without a schema it still types literals and built-in calls |
| Best for | Formatting, linting, IDE integrations, extracting tables and columns, surgical table renames | Lineage and anti-pattern analyzers, JSON for APIs and UIs, schema-aware column flow, query graphs for language models |
Prerequisites
- Python 3.10 or later
- .NET 8.0+ runtime
If you installed dotnet through Homebrew, its runtime layout differs from
Microsoft's installer and libhostfxr.dylib sits under libexec/ instead of
bin/. Kustology detects this. If detection fails, set DOTNET_ROOT yourself:
export DOTNET_ROOT=/opt/homebrew/opt/dotnet/libexec # Apple Silicon
export DOTNET_ROOT=/usr/local/opt/dotnet/libexec # Intel
Installation
pip install kustology # Tier 1: thin .NET wrapper
pip install 'kustology[ir]' # Tier 1 + Tier 2: semantic IR (adds pydantic)
pip install 'kustology[examples]' # Colour output in examples/ (adds rich)
Quick start
from kustology import parse, format_query
query = (
"StormEvents | where StartTime > ago(7d) and DeathsDirect > 0 "
"| project StartTime, State, EventType"
)
print(format_query(query))
result = parse(query)
result.get_referenced_tables() # {'StormEvents'}
result.get_referenced_columns() # {'StartTime', 'DeathsDirect', 'State', 'EventType'}
result.get_referenced_functions() # {'ago'}
# Pass a schema to bind the query and get semantic diagnostics.
schema = {"StormEvents": {"StartTime": "datetime", "DeathsDirect": "int",
"State": "string", "EventType": "string"}}
bound = parse(query, schema=schema)
bound.has_semantics # True
bound.diagnostics # []
With the [ir] extra installed, the same parse builds a Pydantic IR:
from kustology import parse
from kustology.ir import FilterOp
schema = {"StormEvents": {"DeathsDirect": "int", "State": "string"}}
ir = parse("StormEvents | where DeathsDirect > 0", schema=schema).to_ir()
for op in ir.main_pipeline.operators:
if isinstance(op, FilterOp):
op.predicate.canonical_form # StormEvents.DeathsDirect > 0
op.predicate.left.table # StormEvents
op.predicate.left.result_type # int (KustoType.INT)
CLI
The kustology console script ships with the base install:
kustology format query.kql # reformat to canonical form
kustology validate query.kql # print parser diagnostics
kustology parse --ir query.kql # print the Pydantic IR (needs [ir])
Every subcommand, the --schema and --json flags, and the exit codes CI
branches on are in the
CLI reference.
Examples
Each script runs standalone and explains its own output as it goes, and
tests/test_examples.py runs all of them, so none can drift away from the
library without CI noticing.
| examples/walk_tree.py | Direct AST traversal |
| examples/query_analysis.py | End-to-end analysis of a non-trivial query |
| examples/binding_comparison.py | What passing a schema adds |
| examples/walk_ir.py | The same walk over the typed IR |
| examples/find_all_demo.py | Generic IR traversal with find_all |
| examples/analyzer_demo.py | Composing analyzers and reading Findings |
| examples/linter.py | A working KQL linter built on the IR |
| examples/llm_view.py | IR serialization for language models |
| examples/semantic_hash_demo.py | What semantic_hash merges and what it splits |
| examples/query_similarity.py | Graded similarity, containment, and diffing between related queries |
| examples/lookback_window.py | Outer lookback via result_type, prune and span_of |
The IR examples need the [ir] extra. The rest run on the base install. Add
the [examples] extra for colour and syntax highlighting; without it the same
output prints as plain text.
Documentation
| Working with the syntax tree | Tier 1 in depth, and the pythonnet behavior that catches people off guard |
| The Tier 2 IR | How let names, operators, and function bodies lower into IR nodes |
| CLI reference | Subcommands, flags, JSON output, exit codes |
Versioning and semantic_hash |
Compatibility tags, and what the digest ignores |
| Graded similarity | Comparing queries by degree: subtree overlap, containment, and diffing |
| Architecture | Code layout, for contributors |
| Contributing | Setup and the development loop |
Versioning
This is a 0.y release, so the public API can still change at a minor version
(SemVer §4). Tier 1 is on a stabilization track and reaches 1.0 once it survives
external use without correctness breaks. Tier 2 keeps evolving at minor cadence.
Three numbers describe compatibility: kustology.__version__ tags the library,
kustology.ir.IR_SCHEMA_VERSION tags the IR's field shape, and
kustology.ir.SEMANTIC_HASH_SCHEME tags the hash canonicalization rules. Tag
any IR JSON or hash you store with the value that produced it, and refuse a
payload whose tag you do not recognize. See
Versioning and semantic_hash
for the full contract.
Development
git clone https://github.com/k4otix/kustology.git
cd kustology
pip install -e ".[dev]"
pytest
ruff check src tests scripts examples
mypy src
See CONTRIBUTING.md for the full workflow.
License
Apache License 2.0. See
LICENSE,
NOTICE.md, and
THIRD-PARTY-NOTICES.md.
The bundled Kusto.Language.dll is owned by Microsoft Corporation and
redistributed unmodified under Apache 2.0. It is pinned by SHA-256 and verified
in CI. See SECURITY.md.
Trademark notice
"Kusto", "KQL", "Microsoft", "Azure Data Explorer", "Azure Monitor", and "Microsoft Sentinel" are trademarks of Microsoft Corporation. References to those trademarks are nominative and used only to identify the upstream library this package wraps. Apache License 2.0 §6 does not grant trademark rights; nothing in this distribution should be construed as a trademark license.
Metadata
Release files for kustology 0.3.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| kustology-0.3.0.tar.gz | 1.1 MB | With provenance | Details for kustology-0.3.0.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| kustology-0.3.0-py3-none-any.whl | Python 3 | none | any | Details for kustology-0.3.0-py3-none-any.whl |
Total release size: 1.8 MB
Release files / kustology-0.3.0.tar.gz
| Download URL | kustology-0.3.0.tar.gz |
|---|---|
| Size | 1.1 MB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
9521c999c657830c2baacd69f5d43b7f3d8d43d09d4bf7e01e2f380fbf97ad3d
|
|
BLAKE2b-256 checksum How to use checksums |
852cf91be0f6591eb6b587a4be28878968cc7156a4dcdb5cbbbe979773ae004e
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Aug 30, 2026.
Transparency logRelease files / kustology-0.3.0-py3-none-any.whl
| Download URL | kustology-0.3.0-py3-none-any.whl |
|---|---|
| Size | 750.0 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
1159c9e1699208d7eaa8a3e70d310ba8a03b7aa676af7867862ce84d2fe9f507
|
|
BLAKE2b-256 checksum How to use checksums |
3a72e68464b2b3b99e2d5aff9522379a0723980a9d90082cb21996443108a79d
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Aug 30, 2026.
Transparency logSecurity for kustology 0.3.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
Full provenance
Both files in this release have been uploaded with provenance metadata.
Attestation for kustology-0.3.0.tar.gz
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Aug 30, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.