Update Check — ONCE PER SESSION (mandatory)
The first time this skill is used in a session, run the check-updates skill before proceeding.
- GitHub Copilot CLI / VS Code: invoke the
check-updates skill.
- Claude Code / Cowork / Cursor / Windsurf / Codex: compare local vs remote package.json version.
- Skip if the check was already performed earlier in this session.
CRITICAL NOTES
- To find the workspace details (including its ID) from workspace name: list all workspaces and, then, use JMESPath filtering
- To find the item details (including its ID) from workspace ID, item type, and item name: list all items of that type in that workspace and, then, use JMESPath filtering
eventhouse-consumption-cli — Read-Only KQL Queries via CLI
Table of Contents
| Task |
Reference |
Notes |
| Finding Workspaces and Items in Fabric |
COMMON-CLI.md § Finding Workspaces and Items in Fabric |
Mandatory — READ link first [needed for finding workspace id by its name or item id by its name, item type, and workspace id] |
| Fabric Topology & Key Concepts |
COMMON-CORE.md § Fabric Topology & Key Concepts |
|
| Environment URLs |
COMMON-CORE.md § Environment URLs |
KQL Cluster URI is per-item |
| Authentication & Token Acquisition |
COMMON-CORE.md § Authentication & Token Acquisition |
Wrong audience = 401; read before any auth issue |
| Core Control-Plane REST APIs |
COMMON-CORE.md § Core Control-Plane REST APIs |
|
| Pagination |
COMMON-CORE.md § Pagination |
|
| Long-Running Operations (LRO) |
COMMON-CORE.md § Long-Running Operations (LRO) |
|
| Rate Limiting & Throttling |
COMMON-CORE.md § Rate Limiting & Throttling |
|
| OneLake Data Access |
COMMON-CORE.md § OneLake Data Access |
Requires storage.azure.com token, not Fabric token |
| Job Execution |
COMMON-CORE.md § Job Execution |
|
| Capacity Management |
COMMON-CORE.md § Capacity Management |
|
| Gotchas & Troubleshooting |
COMMON-CORE.md § Gotchas & Troubleshooting |
|
| Best Practices |
COMMON-CORE.md § Best Practices |
|
| Tool Selection Rationale |
COMMON-CLI.md § Tool Selection Rationale |
|
| Authentication Recipes |
COMMON-CLI.md § Authentication Recipes |
az login flows and token acquisition |
Fabric Control-Plane API via az rest |
COMMON-CLI.md § Fabric Control-Plane API via az rest |
Always pass --resource https://api.fabric.microsoft.com or az rest fails |
| Pagination Pattern |
COMMON-CLI.md § Pagination Pattern |
|
| Long-Running Operations (LRO) Pattern |
COMMON-CLI.md § Long-Running Operations (LRO) Pattern |
|
OneLake Data Access via curl |
COMMON-CLI.md § OneLake Data Access via curl |
Use curl not az rest (different token audience) |
| Job Execution (CLI) |
COMMON-CLI.md § Job Execution |
|
| OneLake Shortcuts |
COMMON-CLI.md § OneLake Shortcuts |
|
| Capacity Management (CLI) |
COMMON-CLI.md § Capacity Management |
|
| Composite Recipes |
COMMON-CLI.md § Composite Recipes |
|
| Gotchas & Troubleshooting (CLI-Specific) |
COMMON-CLI.md § Gotchas & Troubleshooting (CLI-Specific) |
az rest audience, shell escaping, token expiry |
Quick Reference: az rest Template |
COMMON-CLI.md § Quick Reference: az rest Template |
|
| Quick Reference: Token Audience / CLI Tool Matrix |
COMMON-CLI.md § Quick Reference: Token Audience ↔ CLI Tool Matrix |
Which --resource + tool for each service |
| Connection Fundamentals |
EVENTHOUSE-CONSUMPTION-CORE.md § Connection Fundamentals |
Cluster URI discovery, az rest, REST API |
| Schema Discovery and Security |
EVENTHOUSE-CONSUMPTION-CORE.md § Schema Discovery and Security |
Schema Discovery, Security — workspace roles + KQL DB roles |
| Monitoring and Diagnostics |
EVENTHOUSE-CONSUMPTION-CORE.md § Monitoring and Diagnostics |
|
| Performance Best Practices |
EVENTHOUSE-CONSUMPTION-CORE.md § Performance Best Practices |
Read before writing KQL — time filters, has vs contains |
| Common Consumption Patterns |
EVENTHOUSE-CONSUMPTION-CORE.md § Common Consumption Patterns |
Time-series, Top-N, percentile, dynamic fields |
| Gotchas, Troubleshooting, and Quick Reference |
EVENTHOUSE-CONSUMPTION-CORE.md § Gotchas, Troubleshooting, and Quick Reference |
Gotchas and Troubleshooting (12 issues), Quick Reference: Consumption Capabilities by Scenario |
| Table and Column Discovery |
discovery-queries.md § Table and Column Discovery |
Table Discovery, Column Statistics |
| Function and View Discovery |
discovery-queries.md § Function and View Discovery |
Function Discovery, Materialized View Discovery |
| Policy Discovery |
discovery-queries.md § Policy Discovery |
|
| External Tables and Ingestion Mappings |
discovery-queries.md § External Tables and Ingestion Mappings |
External Table Discovery, Ingestion Mapping Discovery |
| Security Discovery |
discovery-queries.md § Security Discovery |
|
| Database Overview Script |
discovery-queries.md § Database Overview Script |
|
| Tool Stack |
SKILL.md § Tool Stack |
|
| Connection |
SKILL.md § Connection |
eventhouse-specific az rest connection steps |
| Agentic Exploration ("Chat With My Data") |
SKILL.md § Agentic Exploration |
Start here for data exploration |
| Running Queries |
SKILL.md § Running Queries |
az rest, output formatting, export |
| Monitoring |
SKILL.md § Monitoring |
|
| Must / Prefer / Avoid / Troubleshooting |
SKILL.md § Must / Prefer / Avoid / Troubleshooting |
MUST DO / AVOID / PREFER checklists |
| Examples |
SKILL.md § Examples |
|
| Agent Integration Notes |
SKILL.md § Agent Integration Notes |
|
Tool Stack
| Tool |
Purpose |
Install |
| az cli |
KQL queries and management commands via Kusto REST API; Fabric control-plane discovery |
winget install Microsoft.AzureCLI |
| jq |
JSON processing and output formatting |
winget install jqlang.jq |
Connection
Step 1 — Discover KQL Database Query URI
# Get workspace ID (if not known)
WS_ID=$(az rest --method GET \
--url "https://api.fabric.microsoft.com/v1/workspaces" \
--resource "https://api.fabric.microsoft.com" \
| jq -r '.value[] | select(.displayName=="MyWorkspace") | .id')
# List KQL Databases and get connection properties
az rest --method GET \
--url "https://api.fabric.microsoft.com/v1/workspaces/${WS_ID}/kqlDatabases" \
--resource "https://api.fabric.microsoft.com" \
| jq '.value[] | {name: .displayName, id: .id, queryUri: .properties.queryServiceUri, dbName: .properties.databaseName}'
Step 2 — Set Connection Variables
CLUSTER_URI="https://<cluster>.kusto.fabric.microsoft.com"
DB_NAME="MyKqlDatabase"
Step 3 — Verify Connection
Important — body file pattern: KQL queries contain | (pipe) characters which break shell
escaping in both bash and PowerShell. Always write the JSON body to a temp file and reference
it with --body @<file>. This is the recommended approach for all az rest KQL calls.
On PowerShell, use @{db="X";csl="..."} | ConvertTo-Json -Compress | Out-File $env:TEMP\kql_body.json -Encoding utf8NoBOM then --body "@$env:TEMP\kql_body.json".
# Write body to temp file (avoids pipe escaping issues)
cat > /tmp/kql_body.json << 'EOF'
{"db":"MyKqlDatabase","csl":"print Message = 'Connected successfully', Cluster = current_cluster_endpoint(), Timestamp = now()"}
EOF
az rest --method POST \
--url "${CLUSTER_URI}/v1/rest/query" \
--resource "https://kusto.kusto.windows.net" \
--headers "Content-Type=application/json" \
--body @/tmp/kql_body.json \
| jq '.Tables[0].Rows'
Agentic Exploration
"Chat With My Data" — Discovery Sequence
When the user asks to explore or query an Eventhouse without specifying tables:
Step 1 → .show tables // discover tables
Step 2 → .show table <TABLE> schema as json // understand columns + types
Step 3 → <TABLE> | take 10 // see sample data
Step 4 → <TABLE> | summarize count() by bin(Timestamp, 1h) | render timechart // shape of data
Step 5 → Formulate targeted query based on user's question
Schema-Aware Query Generation
After schema discovery, generate queries using actual column names and types:
// Example: user asks "show me errors in the last hour"
// After discovering table "AppEvents" with columns: Timestamp, Level, Message, Source
AppEvents
| where Timestamp > ago(1h)
| where Level == "Error"
| summarize ErrorCount = count() by Source, bin(Timestamp, 5m)
| order by ErrorCount desc
Running Queries
Via az rest
Always use the temp-file pattern for --body — KQL pipes (|) break inline shell escaping.
# Run a KQL query
cat > /tmp/kql_body.json << 'EOF'
{"db":"MyDB","csl":"Events | where Timestamp > ago(1h) | count"}
EOF
az rest --method POST \
--url "${CLUSTER_URI}/v1/rest/query" \
--resource "https://kusto.kusto.windows.net" \
--headers "Content-Type=application/json" \
--body @/tmp/kql_body.json \
| jq '.Tables[0].Rows'
Output Formatting
# Pretty-print results as a table with jq
cat > /tmp/kql_body.json << 'EOF'
{"db":"MyDB","csl":".show tables"}
EOF
az rest --method POST \
--url "${CLUSTER_URI}/v1/rest/query" \
--resource "https://kusto.kusto.windows.net" \
--headers "Content-Type=application/json" \
--body @/tmp/kql_body.json \
| jq '.Tables[0] | [.Columns[].ColumnName] as $cols | .Rows[] | [$cols, .] | transpose | map({(.[0]): .[1]}) | add'
# Save results to file
cat > /tmp/kql_body.json << 'EOF'
{"db":"MyDB","csl":"Events | where Timestamp > ago(1h) | summarize count() by EventType"}
EOF
az rest --method POST \
--url "${CLUSTER_URI}/v1/rest/query" \
--resource "https://kusto.kusto.windows.net" \
--headers "Content-Type=application/json" \
--body @/tmp/kql_body.json \
--output-file results.json
Monitoring
// Active queries
.show queries
// Recent commands (last hour)
.show commands
| where StartedOn > ago(1h)
| project StartedOn, CommandType, Text = substring(Text, 0, 80), Duration, State
| order by StartedOn desc
// Ingestion failures (for context when data seems stale)
.show ingestion failures
| where FailedOn > ago(24h)
| summarize count() by ErrorCode
| top 5 by count_
Must / Prefer / Avoid / Troubleshooting
Must
- Always include time filters —
where Timestamp > ago(...) must be present on time-series tables.
- Discover schema before querying — run
.show tables and .show table T schema as json first.
- Use
has for term search — indexed and fast; only fall back to contains for substring needs.
- Verify cluster URI — KQL Database URIs are per-item; always resolve via Fabric REST API.
Prefer
az rest for CLI query sessions; Fabric KQL MCP server for agent-integrated workflows.
project early to drop unneeded columns before aggregation.
materialize() when a sub-expression is used multiple times.
take 100 for initial exploration; avoid full table scans.
render timechart for time-series; render piechart for distribution.
Avoid
contains on large tables — full scan, not indexed. Use has or has_cs.
join without filtering both sides first — causes memory explosion.
SELECT * equivalent (project all columns) on wide tables.
- Missing
bin() in time-series summarize — produces one row per unique timestamp.
- Hardcoded cluster URIs — always resolve from Fabric REST API or environment variables.
Troubleshooting
| Symptom |
Fix |
az rest auth fails |
Run az login first; ensure --resource "https://kusto.kusto.windows.net" is set |
| Empty results on valid table |
Check database context; may need database("name").table |
| Query timeout |
Add tighter time filter; check .show queries for competing queries |
Forbidden (403) |
Request viewer role on the KQL Database |
| Results truncated |
Default limit is 500K rows; add set truncationmaxrecords = N; before query |
KQL pipe | breaks PowerShell or bash |
Never inline KQL in --body. Write JSON to a temp file and use --body @file.json (see Running Queries) |
Examples
Example 1: Discover and Query
# 1. Set connection variables (after discovering URI via Step 1)
CLUSTER_URI="https://<your-cluster>.kusto.fabric.microsoft.com"
DB_NAME="SalesDB"
# 2. Discover tables
cat > /tmp/kql_body.json << EOF
{"db":"${DB_NAME}","csl":".show tables"}
EOF
az rest --method POST \
--url "${CLUSTER_URI}/v1/rest/query" \
--resource "https://kusto.kusto.windows.net" \
--headers "Content-Type=application/json" \
--body @/tmp/kql_body.json \
| jq '.Tables[0].Rows'
# 3. Explore schema
cat > /tmp/kql_body.json << EOF
{"db":"${DB_NAME}","csl":".show table Orders schema as json"}
EOF
az rest --method POST \
--url "${CLUSTER_URI}/v1/rest/query" \
--resource "https://kusto.kusto.windows.net" \
--headers "Content-Type=application/json" \
--body @/tmp/kql_body.json \
| jq '.Tables[0].Rows'
# 4. Sample data
cat > /tmp/kql_body.json << EOF
{"db":"${DB_NAME}","csl":"Orders | take 10"}
EOF
az rest --method POST \
--url "${CLUSTER_URI}/v1/rest/query" \
--resource "https://kusto.kusto.windows.net" \
--headers "Content-Type=application/json" \
--body @/tmp/kql_body.json \
| jq '.Tables[0].Rows'
// 5. Analytical query (via az rest --body @file)
Orders
| where OrderDate > ago(30d)
| summarize
TotalOrders = count(),
TotalRevenue = sum(Amount)
by bin(OrderDate, 1d)
| render timechart
Example 2: Cross-Database Query
// Query across KQL databases in the same Eventhouse
let orders = database("SalesDB").Orders | where OrderDate > ago(7d);
let products = database("CatalogDB").Products;
orders
| join kind=inner (products) on ProductId
| summarize Revenue = sum(Amount) by ProductName
| top 10 by Revenue desc
Example 3: Export Results to File
# Run query and save results to JSON
cat > /tmp/kql_body.json << 'EOF'
{"db":"MyDB","csl":"Events | where Timestamp > ago(1d) | summarize count() by EventType"}
EOF
az rest --method POST \
--url "${CLUSTER_URI}/v1/rest/query" \
--resource "https://kusto.kusto.windows.net" \
--headers "Content-Type=application/json" \
--body @/tmp/kql_body.json \
--output-file results.json
# Convert to CSV with jq
cat results.json \
| jq -r '.Tables[0] | (.Columns | map(.ColumnName)), (.Rows[]) | @csv' > results.csv
Agent Integration Notes
- This skill is read-only — it does not create, alter, or drop database objects.
- For authoring operations (table management, ingestion, policies), delegate to eventhouse-authoring-cli.
- For cross-workload orchestration (Spark + SQL + KQL), delegate to the FabricDataEngineer agent.
- The Fabric KQL MCP server (
fabric-kql in mcp-setup/mcp-config-template.json) can be used as an alternative to az rest for agent-integrated query execution.
1---2name: eventhouse-consumption-cli3description: Run KQL queries against Fabric Eventhouse for real-time intelligence and time-series analytics using `az rest` against the Kusto REST API. Covers KQL operators (where, summarize, join, render), Eventhouse schema discovery (.show tables), time-series patterns with bin(), and ingestion monitoring. Use when the user wants to: 1. Run read-only KQL queries against an Eventhouse or KQL Database 2. Discover Eventhouse table schema and metadata 3. Analyse real-time or time-series data with KQL operators 4. Monitor ingestion health and active KQL queries 5. Export KQL results to JSON Triggers: "kql query", "kusto query", "eventhouse query", "kql database", "real-time intelligence", "time-series kql", "query eventhouse", "explore eventhouse", "show tables kql"4---56> **Update Check — ONCE PER SESSION (mandatory)**7> The first time this skill is used in a session, run the **check-updates** skill before proceeding.8> - **GitHub Copilot CLI / VS Code**: invoke the `check-updates` skill.9> - **Claude Code / Cowork / Cursor / Windsurf / Codex**: compare local vs remote package.json version.10> - Skip if the check was already performed earlier in this session.1112> **CRITICAL NOTES**13> 1. To find the workspace details (including its ID) from workspace name: list all workspaces and, then, use JMESPath filtering14> 2. To find the item details (including its ID) from workspace ID, item type, and item name: list all items of that type in that workspace and, then, use JMESPath filtering1516# eventhouse-consumption-cli — Read-Only KQL Queries via CLI1718## Table of Contents1920| Task | Reference | Notes |21|---|---|---|22| Finding Workspaces and Items in Fabric | [COMMON-CLI.md § Finding Workspaces and Items in Fabric](../../common/COMMON-CLI.md#finding-workspaces-and-items-in-fabric) | **Mandatory** — *READ link first* [needed for finding workspace id by its name or item id by its name, item type, and workspace id] |23| Fabric Topology & Key Concepts | [COMMON-CORE.md § Fabric Topology & Key Concepts](../../common/COMMON-CORE.md#fabric-topology--key-concepts) | |24| Environment URLs | [COMMON-CORE.md § Environment URLs](../../common/COMMON-CORE.md#environment-urls) | KQL Cluster URI is per-item |25| Authentication & Token Acquisition | [COMMON-CORE.md § Authentication & Token Acquisition](../../common/COMMON-CORE.md#authentication--token-acquisition) | Wrong audience = 401; read before any auth issue |26| Core Control-Plane REST APIs | [COMMON-CORE.md § Core Control-Plane REST APIs](../../common/COMMON-CORE.md#core-control-plane-rest-apis) | |27| Pagination | [COMMON-CORE.md § Pagination](../../common/COMMON-CORE.md#pagination) | |28| Long-Running Operations (LRO) | [COMMON-CORE.md § Long-Running Operations (LRO)](../../common/COMMON-CORE.md#long-running-operations-lro) | |29| Rate Limiting & Throttling | [COMMON-CORE.md § Rate Limiting & Throttling](../../common/COMMON-CORE.md#rate-limiting--throttling) | |30| OneLake Data Access | [COMMON-CORE.md § OneLake Data Access](../../common/COMMON-CORE.md#onelake-data-access) | Requires `storage.azure.com` token, not Fabric token |31| Job Execution | [COMMON-CORE.md § Job Execution](../../common/COMMON-CORE.md#job-execution) | |32| Capacity Management | [COMMON-CORE.md § Capacity Management](../../common/COMMON-CORE.md#capacity-management) | |33| Gotchas & Troubleshooting | [COMMON-CORE.md § Gotchas & Troubleshooting](../../common/COMMON-CORE.md#gotchas--troubleshooting) | |34| Best Practices | [COMMON-CORE.md § Best Practices](../../common/COMMON-CORE.md#best-practices) | |35| Tool Selection Rationale | [COMMON-CLI.md § Tool Selection Rationale](../../common/COMMON-CLI.md#tool-selection-rationale) | |36| Authentication Recipes | [COMMON-CLI.md § Authentication Recipes](../../common/COMMON-CLI.md#authentication-recipes) | `az login` flows and token acquisition |37| Fabric Control-Plane API via `az rest` | [COMMON-CLI.md § Fabric Control-Plane API via az rest](../../common/COMMON-CLI.md#fabric-control-plane-api-via-az-rest) | **Always pass `--resource https://api.fabric.microsoft.com`** or `az rest` fails |38| Pagination Pattern | [COMMON-CLI.md § Pagination Pattern](../../common/COMMON-CLI.md#pagination-pattern) | |39| Long-Running Operations (LRO) Pattern | [COMMON-CLI.md § Long-Running Operations (LRO) Pattern](../../common/COMMON-CLI.md#long-running-operations-lro-pattern) | |40| OneLake Data Access via `curl` | [COMMON-CLI.md § OneLake Data Access via curl](../../common/COMMON-CLI.md#onelake-data-access-via-curl) | Use `curl` not `az rest` (different token audience) |41| Job Execution (CLI) | [COMMON-CLI.md § Job Execution](../../common/COMMON-CLI.md#job-execution) | |42| OneLake Shortcuts | [COMMON-CLI.md § OneLake Shortcuts](../../common/COMMON-CLI.md#onelake-shortcuts) | |43| Capacity Management (CLI) | [COMMON-CLI.md § Capacity Management](../../common/COMMON-CLI.md#capacity-management) | |44| Composite Recipes | [COMMON-CLI.md § Composite Recipes](../../common/COMMON-CLI.md#composite-recipes) | |45| Gotchas & Troubleshooting (CLI-Specific) | [COMMON-CLI.md § Gotchas & Troubleshooting (CLI-Specific)](../../common/COMMON-CLI.md#gotchas--troubleshooting-cli-specific) | `az rest` audience, shell escaping, token expiry |46| Quick Reference: `az rest` Template | [COMMON-CLI.md § Quick Reference: az rest Template](../../common/COMMON-CLI.md#quick-reference-az-rest-template) | |47| Quick Reference: Token Audience / CLI Tool Matrix | [COMMON-CLI.md § Quick Reference: Token Audience ↔ CLI Tool Matrix](../../common/COMMON-CLI.md#quick-reference-token-audience--cli-tool-matrix) | Which `--resource` + tool for each service |48| Connection Fundamentals | [EVENTHOUSE-CONSUMPTION-CORE.md § Connection Fundamentals](../../common/EVENTHOUSE-CONSUMPTION-CORE.md#connection-fundamentals) | Cluster URI discovery, `az rest`, REST API |49| Schema Discovery and Security | [EVENTHOUSE-CONSUMPTION-CORE.md § Schema Discovery and Security](../../common/EVENTHOUSE-CONSUMPTION-CORE.md#schema-discovery-and-security) | Schema Discovery, Security — workspace roles + KQL DB roles |50| Monitoring and Diagnostics | [EVENTHOUSE-CONSUMPTION-CORE.md § Monitoring and Diagnostics](../../common/EVENTHOUSE-CONSUMPTION-CORE.md#monitoring-and-diagnostics) | |51| Performance Best Practices | [EVENTHOUSE-CONSUMPTION-CORE.md § Performance Best Practices](../../common/EVENTHOUSE-CONSUMPTION-CORE.md#performance-best-practices) | **Read before writing KQL** — time filters, `has` vs `contains` |52| Common Consumption Patterns | [EVENTHOUSE-CONSUMPTION-CORE.md § Common Consumption Patterns](../../common/EVENTHOUSE-CONSUMPTION-CORE.md#common-consumption-patterns) | Time-series, Top-N, percentile, dynamic fields |53| Gotchas, Troubleshooting, and Quick Reference | [EVENTHOUSE-CONSUMPTION-CORE.md § Gotchas, Troubleshooting, and Quick Reference](../../common/EVENTHOUSE-CONSUMPTION-CORE.md#gotchas-troubleshooting-and-quick-reference) | Gotchas and Troubleshooting (12 issues), Quick Reference: Consumption Capabilities by Scenario |54| Table and Column Discovery | [discovery-queries.md § Table and Column Discovery](references/discovery-queries.md#table-and-column-discovery) | Table Discovery, Column Statistics |55| Function and View Discovery | [discovery-queries.md § Function and View Discovery](references/discovery-queries.md#function-and-view-discovery) | Function Discovery, Materialized View Discovery |56| Policy Discovery | [discovery-queries.md § Policy Discovery](references/discovery-queries.md#policy-discovery) | |57| External Tables and Ingestion Mappings | [discovery-queries.md § External Tables and Ingestion Mappings](references/discovery-queries.md#external-tables-and-ingestion-mappings) | External Table Discovery, Ingestion Mapping Discovery |58| Security Discovery | [discovery-queries.md § Security Discovery](references/discovery-queries.md#security-discovery) | |59| Database Overview Script | [discovery-queries.md § Database Overview Script](references/discovery-queries.md#database-overview-script) | |60| Tool Stack | [SKILL.md § Tool Stack](#tool-stack) | |61| Connection | [SKILL.md § Connection](#connection) | eventhouse-specific `az rest` connection steps |62| Agentic Exploration ("Chat With My Data") | [SKILL.md § Agentic Exploration](#agentic-exploration) | **Start here** for data exploration |63| Running Queries | [SKILL.md § Running Queries](#running-queries) | `az rest`, output formatting, export |64| Monitoring | [SKILL.md § Monitoring](#monitoring) | |65| Must / Prefer / Avoid / Troubleshooting | [SKILL.md § Must / Prefer / Avoid / Troubleshooting](#must--prefer--avoid--troubleshooting) | **MUST DO / AVOID / PREFER** checklists |66| Examples | [SKILL.md § Examples](#examples) | |67| Agent Integration Notes | [SKILL.md § Agent Integration Notes](#agent-integration-notes) | |6869---7071## Tool Stack7273| Tool | Purpose | Install |74|---|---|---|75| **az cli** | KQL queries and management commands via Kusto REST API; Fabric control-plane discovery | `winget install Microsoft.AzureCLI` |76| **jq** | JSON processing and output formatting | `winget install jqlang.jq` |7778## Connection7980### Step 1 — Discover KQL Database Query URI8182```bash83# Get workspace ID (if not known)84WS_ID=$(az rest --method GET \85 --url "https://api.fabric.microsoft.com/v1/workspaces" \86 --resource "https://api.fabric.microsoft.com" \87 | jq -r '.value[] | select(.displayName=="MyWorkspace") | .id')8889# List KQL Databases and get connection properties90az rest --method GET \91 --url "https://api.fabric.microsoft.com/v1/workspaces/${WS_ID}/kqlDatabases" \92 --resource "https://api.fabric.microsoft.com" \93 | jq '.value[] | {name: .displayName, id: .id, queryUri: .properties.queryServiceUri, dbName: .properties.databaseName}'94```9596### Step 2 — Set Connection Variables9798```bash99CLUSTER_URI="https://<cluster>.kusto.fabric.microsoft.com"100DB_NAME="MyKqlDatabase"101```102103### Step 3 — Verify Connection104105> **Important — body file pattern**: KQL queries contain `|` (pipe) characters which break shell106> escaping in both bash and PowerShell. **Always write the JSON body to a temp file** and reference107> it with `--body @<file>`. This is the recommended approach for all `az rest` KQL calls.108> On PowerShell, use `@{db="X";csl="..."} | ConvertTo-Json -Compress | Out-File $env:TEMP\kql_body.json -Encoding utf8NoBOM` then `--body "@$env:TEMP\kql_body.json"`.109110```bash111# Write body to temp file (avoids pipe escaping issues)112cat > /tmp/kql_body.json << 'EOF'113{"db":"MyKqlDatabase","csl":"print Message = 'Connected successfully', Cluster = current_cluster_endpoint(), Timestamp = now()"}114EOF115116az rest --method POST \117 --url "${CLUSTER_URI}/v1/rest/query" \118 --resource "https://kusto.kusto.windows.net" \119 --headers "Content-Type=application/json" \120 --body @/tmp/kql_body.json \121 | jq '.Tables[0].Rows'122```123124---125126## Agentic Exploration127128### "Chat With My Data" — Discovery Sequence129130When the user asks to explore or query an Eventhouse without specifying tables:131132```kql133Step 1 → .show tables // discover tables134Step 2 → .show table <TABLE> schema as json // understand columns + types135Step 3 → <TABLE> | take 10 // see sample data136Step 4 → <TABLE> | summarize count() by bin(Timestamp, 1h) | render timechart // shape of data137Step 5 → Formulate targeted query based on user's question138```139140### Schema-Aware Query Generation141142After schema discovery, generate queries using actual column names and types:143144```kql145// Example: user asks "show me errors in the last hour"146// After discovering table "AppEvents" with columns: Timestamp, Level, Message, Source147AppEvents148| where Timestamp > ago(1h)149| where Level == "Error"150| summarize ErrorCount = count() by Source, bin(Timestamp, 5m)151| order by ErrorCount desc152```153154---155156## Running Queries157158### Via `az rest`159160> **Always use the temp-file pattern** for `--body` — KQL pipes (`|`) break inline shell escaping.161162```bash163# Run a KQL query164cat > /tmp/kql_body.json << 'EOF'165{"db":"MyDB","csl":"Events | where Timestamp > ago(1h) | count"}166EOF167168az rest --method POST \169 --url "${CLUSTER_URI}/v1/rest/query" \170 --resource "https://kusto.kusto.windows.net" \171 --headers "Content-Type=application/json" \172 --body @/tmp/kql_body.json \173 | jq '.Tables[0].Rows'174```175176### Output Formatting177178```bash179# Pretty-print results as a table with jq180cat > /tmp/kql_body.json << 'EOF'181{"db":"MyDB","csl":".show tables"}182EOF183184az rest --method POST \185 --url "${CLUSTER_URI}/v1/rest/query" \186 --resource "https://kusto.kusto.windows.net" \187 --headers "Content-Type=application/json" \188 --body @/tmp/kql_body.json \189 | jq '.Tables[0] | [.Columns[].ColumnName] as $cols | .Rows[] | [$cols, .] | transpose | map({(.[0]): .[1]}) | add'190191# Save results to file192cat > /tmp/kql_body.json << 'EOF'193{"db":"MyDB","csl":"Events | where Timestamp > ago(1h) | summarize count() by EventType"}194EOF195196az rest --method POST \197 --url "${CLUSTER_URI}/v1/rest/query" \198 --resource "https://kusto.kusto.windows.net" \199 --headers "Content-Type=application/json" \200 --body @/tmp/kql_body.json \201 --output-file results.json202```203204---205206## Monitoring207208```kql209// Active queries210.show queries211212// Recent commands (last hour)213.show commands214| where StartedOn > ago(1h)215| project StartedOn, CommandType, Text = substring(Text, 0, 80), Duration, State216| order by StartedOn desc217218// Ingestion failures (for context when data seems stale)219.show ingestion failures220| where FailedOn > ago(24h)221| summarize count() by ErrorCode222| top 5 by count_223```224225---226227## Must / Prefer / Avoid / Troubleshooting228229### Must230231- **Always include time filters** — `where Timestamp > ago(...)` must be present on time-series tables.232- **Discover schema before querying** — run `.show tables` and `.show table T schema as json` first.233- **Use `has` for term search** — indexed and fast; only fall back to `contains` for substring needs.234- **Verify cluster URI** — KQL Database URIs are per-item; always resolve via Fabric REST API.235236### Prefer237238- **`az rest`** for CLI query sessions; **Fabric KQL MCP server** for agent-integrated workflows.239- **`project` early** to drop unneeded columns before aggregation.240- **`materialize()`** when a sub-expression is used multiple times.241- **`take 100`** for initial exploration; avoid full table scans.242- **`render timechart`** for time-series; `render piechart` for distribution.243244### Avoid245246- **`contains`** on large tables — full scan, not indexed. Use `has` or `has_cs`.247- **`join`** without filtering both sides first — causes memory explosion.248- **`SELECT *`** equivalent (`project` all columns) on wide tables.249- **Missing `bin()`** in time-series `summarize` — produces one row per unique timestamp.250- **Hardcoded cluster URIs** — always resolve from Fabric REST API or environment variables.251252### Troubleshooting253254| Symptom | Fix |255|---|---|256| `az rest` auth fails | Run `az login` first; ensure `--resource "https://kusto.kusto.windows.net"` is set |257| Empty results on valid table | Check database context; may need `database("name").table` |258| Query timeout | Add tighter time filter; check `.show queries` for competing queries |259| `Forbidden (403)` | Request `viewer` role on the KQL Database |260| Results truncated | Default limit is 500K rows; add `set truncationmaxrecords = N;` before query |261| KQL pipe `\|` breaks PowerShell or bash | **Never inline KQL in `--body`**. Write JSON to a temp file and use `--body @file.json` (see [Running Queries](#running-queries)) |262263---264265## Examples266267### Example 1: Discover and Query268269```bash270# 1. Set connection variables (after discovering URI via Step 1)271CLUSTER_URI="https://<your-cluster>.kusto.fabric.microsoft.com"272DB_NAME="SalesDB"273274# 2. Discover tables275cat > /tmp/kql_body.json << EOF276{"db":"${DB_NAME}","csl":".show tables"}277EOF278az rest --method POST \279 --url "${CLUSTER_URI}/v1/rest/query" \280 --resource "https://kusto.kusto.windows.net" \281 --headers "Content-Type=application/json" \282 --body @/tmp/kql_body.json \283 | jq '.Tables[0].Rows'284285# 3. Explore schema286cat > /tmp/kql_body.json << EOF287{"db":"${DB_NAME}","csl":".show table Orders schema as json"}288EOF289az rest --method POST \290 --url "${CLUSTER_URI}/v1/rest/query" \291 --resource "https://kusto.kusto.windows.net" \292 --headers "Content-Type=application/json" \293 --body @/tmp/kql_body.json \294 | jq '.Tables[0].Rows'295296# 4. Sample data297cat > /tmp/kql_body.json << EOF298{"db":"${DB_NAME}","csl":"Orders | take 10"}299EOF300az rest --method POST \301 --url "${CLUSTER_URI}/v1/rest/query" \302 --resource "https://kusto.kusto.windows.net" \303 --headers "Content-Type=application/json" \304 --body @/tmp/kql_body.json \305 | jq '.Tables[0].Rows'306```307308```kql309// 5. Analytical query (via az rest --body @file)310Orders311| where OrderDate > ago(30d)312| summarize313 TotalOrders = count(),314 TotalRevenue = sum(Amount)315 by bin(OrderDate, 1d)316| render timechart317```318319### Example 2: Cross-Database Query320321```kql322// Query across KQL databases in the same Eventhouse323let orders = database("SalesDB").Orders | where OrderDate > ago(7d);324let products = database("CatalogDB").Products;325orders326| join kind=inner (products) on ProductId327| summarize Revenue = sum(Amount) by ProductName328| top 10 by Revenue desc329```330331### Example 3: Export Results to File332333```bash334# Run query and save results to JSON335cat > /tmp/kql_body.json << 'EOF'336{"db":"MyDB","csl":"Events | where Timestamp > ago(1d) | summarize count() by EventType"}337EOF338339az rest --method POST \340 --url "${CLUSTER_URI}/v1/rest/query" \341 --resource "https://kusto.kusto.windows.net" \342 --headers "Content-Type=application/json" \343 --body @/tmp/kql_body.json \344 --output-file results.json345346# Convert to CSV with jq347cat results.json \348 | jq -r '.Tables[0] | (.Columns | map(.ColumnName)), (.Rows[]) | @csv' > results.csv349```350351---352353## Agent Integration Notes354355- This skill is **read-only** — it does not create, alter, or drop database objects.356- For authoring operations (table management, ingestion, policies), delegate to **eventhouse-authoring-cli**.357- For cross-workload orchestration (Spark + SQL + KQL), delegate to the **FabricDataEngineer** agent.358- The **Fabric KQL MCP server** (`fabric-kql` in `mcp-setup/mcp-config-template.json`) can be used as an alternative to `az rest` for agent-integrated query execution.