KQL CLI — query Azure Data Explorer (Kusto) from the command line.
Like jq for JSON, but for Kusto/KQL. Run raw KQL, keep a git-versioned library
of parameterized queries, and pipe results straight into your shell.
pip install kql-cli # or: uv tool install kql-cliThe command you run is
kq. The PyPI package is namedkql-clibecausekqwas already taken on PyPI by an unrelated project.
Or from source:
git clone https://github.com/cptfinch/kq.git
cd kq
pip install -e .# Configure your cluster
kq config set default_cluster https://mycluster.westeurope.kusto.windows.net
kq config set default_database mydb
# Authenticate
kq auth login
# Run queries
kq "MyTable | take 5" # Raw KQL
kq list # List saved queries
kq run examples.sample MyTable 10 # Run saved queryConfig is stored in ~/.config/kq/config.yaml:
default_cluster: https://mycluster.westeurope.kusto.windows.net
default_database: mydb
clusters:
prod:
url: https://prod.westeurope.kusto.windows.net
database: proddb
dev:
url: https://dev.westeurope.kusto.windows.net
database: devdbConfigure via CLI:
kq config show # Show current config
kq config set default_cluster <url> # Set default cluster
kq config set default_database <db> # Set default database
kq config add-cluster prod <url> --database proddb # Add named cluster| Command | Description |
|---|---|
kq auth login |
Authenticate to ADX |
kq auth status |
Check authentication status |
kq config show |
Show configuration |
kq config set <key> <value> |
Set config value |
kq list [category] |
List saved queries |
kq show <query> |
Show query details |
kq run <query> [params...] |
Run a saved query |
kq "<kql>" |
Run raw KQL |
Queries are loaded from (in priority order):
./.kq/- Project-local queries~/.config/kq/queries/- User queries- Bundled examples
Create YAML files in ~/.config/kq/queries/:
# ~/.config/kq/queries/myqueries.yaml
name: myqueries
description: My custom queries
queries:
- name: recent
description: Get recent records
safety: safe
parameters:
- name: table
description: Table name
required: true
- name: hours
description: Hours to look back
default: "24"
query: |
{table}
| where Timestamp > ago({hours}h)
| order by Timestamp desc
| take 100
example: "MyTable 24"Then run:
kq list # Shows myqueries.recent
kq show myqueries.recent # Show details
kq run myqueries.recent Events # Run with parameterskq "MyTable | take 5" -f table # Default - human readable
kq "MyTable | take 5" -f json # JSON array
kq "MyTable | take 5" -f csv # CSVSupports (in priority order):
- Service Principal - Set
AZURE_CLIENT_ID,AZURE_CLIENT_SECRET,AZURE_TENANT_ID - Azure CLI - Run
az loginfirst - Device Code - Interactive browser login (tokens cached ~90 days)
Queries have a safety level:
safe- Queries with proper time/scope filteringcaution- May scan significant data, use carefullydangerous- Can scan entire tables, requires explicit filtering
Always filter by time first:
// Good - filters first, cheap
MyTable | where Timestamp > ago(1d) | where Category == 'Error'
// Bad - scans everything, expensive
MyTable | where Category == 'Error'- LLM-native - Works seamlessly with Claude Code, Copilot, etc.
- Portable - Same queries work across clusters
- Versionable - Git-controlled query libraries
- Unix-friendly - Pipes, scripts, automation
- Personal queries - User queries never overwritten by updates
git clone https://github.com/cptfinch/kq.git
cd kq
python -m venv .venv && . .venv/bin/activate
pip install -e ".[dev]"
pytest # run tests
ruff check . # lint
python -m build # build sdist + wheelCI runs lint + tests across Python 3.9–3.13 on every push and pull request.
Releases publish to PyPI automatically via Trusted Publishing (OIDC — no tokens stored in the repo). To cut a release:
- Bump
__version__insrc/kq/__init__.pyand updateCHANGELOG.md. - Tag and push:
git tag v1.2.3 && git push origin v1.2.3.
The release.yml workflow builds the artifacts and publishes them. This
requires a one-time PyPI setup: configure kql-cli's trusted publisher to point
at this repository, workflow release.yml, environment pypi.
MIT — see LICENSE.