| name | azure |
| description | MANDATORY parallel execution patterns (30x speedup), monitor metrics aggregation, --output tsv formatting, and common pitfalls |
| connection_type | azure |
| preload | false |
Azure CLI Skill
Execute Azure CLI commands with proper credential injection.
CLI Tips
Parallel Execution Requirement (CRITICAL)
ALL independent operations MUST run in parallel using background jobs (&) and wait
ENFORCEMENT RULES:
- FORBIDDEN: Sequential loops like
for item in $items; do cmd $item; done (causes O(n) runtime)
- MANDATORY: Every independent operation spawns a background job:
{ cmd1 } & { cmd2 } & { cmd3 } & wait
- DETECTION: If your script processes N resources/metrics/regions and N > 1, the script MUST contain at least N background jobs
- TIME IMPACT: Sequential execution with 30 VMs × 2 seconds per call = 60 seconds. Parallel = 2 seconds (30x faster)
- VALIDATION CHECKLIST (agent must mentally verify before output):
- Count independent operations: ___
- Count background jobs (&): ___
- These numbers MUST match, or script will be REJECTED
- Do all operations depend on each other? (Only valid exception to parallel requirement)
PARALLEL PATTERN (CORRECT):
for vm in $vms; do
operation "$vm" &
done
wait
SEQUENTIAL PATTERN (FORBIDDEN - ONLY if operations have data dependencies):
result=$(operation1)
operation2 "$result"
Agent Output Rules
- The script output is for the agent itself to read and process, NOT for human reading
- Do NOT add visual formatting, icons, or decorative elements (no emojis, borders, or separators)
- NEVER USE echo statements for section breaks, headers, or formatting (no "--------", "====", or similar)
- Focus on raw data extraction and minimal, parseable output
- Use plain text format with consistent delimiters for easy parsing
- Prioritize machine-readability over human presentation
- NEVER run commands or scripts that print, log, or expose environment variables, credentials, or Azure keys (e.g., AZURE_USERNAME, AZURE_PASSWORD, AZURE_TENANT)
Execution Guidelines
- PARALLEL EXECUTION IS MANDATORY: Always use background jobs (
&) and wait for independent operations
- Process multiple VMs/resources in parallel:
{ ... } & with wait at the end
- Fetch multiple metrics for the same resource in parallel, then
wait before processing
- Sequential loops are FORBIDDEN unless operations have strict dependencies
- Parallel execution reduces runtime from O(n * time_per_operation) to O(max_operation_time) - use it always
- Always consolidate related steps into single CLI Bash script if possible
- Only use read-only commands (e.g., list, show, get) - never modify resources
- Always format CLI output as plain text (never JSON or table) so that it's easy for the agent to parse. For Azure use --output tsv for text output. Also use filtering/query flags to limit output to what is needed. These practices are crucial for efficiency and accuracy.
Efficient CLI Script Example
ANTI-PATTERN EXAMPLE (SEQUENTIAL - SLOW - UNACCEPTABLE)
#!/bin/bash
END_TIME=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
START_TIME=$(date -u -d "30 days ago" +"%Y-%m-%dT%H:%M:%SZ")
echo "Azure VM Metrics Summary ($START_TIME to $END_TIME)"
az group list --output tsv --query "[*].[name]" | while read rg_name; do
vms=$(az vm list -g "$rg_name" --output tsv --query "[*].[name]")
if [ -n "$vms" ]; then
echo "Resource Group: $rg_name"
echo "$vms" | while read vm_name; do
echo " VM: $vm_name"
az monitor metrics list \
--resource "/subscriptions/$(az account show --query id -o tsv)/resourceGroups/$rg_name/providers/Microsoft.Compute/virtualMachines/$vm_name" \
--metric "Percentage CPU" \
--start-time "$START_TIME" \
--end-time "$END_TIME" \
--interval PT1H \
--aggregation Average \
--output tsv
az monitor metrics list \
--resource \
--metric \
--start-time \
--end-time \
--interval PT1H \
--aggregation Total \
--output tsv
CORRECT EXAMPLE (PARALLEL - FAST - REQUIRED)
#!/bin/bash
END_TIME=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
START_TIME=$(date -u -d "30 days ago" +"%Y-%m-%dT%H:%M:%SZ")
echo "Azure VM Metrics Summary ($START_TIME to $END_TIME)"
get_vm_metrics() {
local resource_group=$1
local vm_name=$2
local metric_name=$3
local aggregation=$4
local unit=$5
result=$(az monitor metrics list \
--resource "/subscriptions/$(az account show --query id -o tsv)/resourceGroups/$resource_group/providers/Microsoft.Compute/virtualMachines/$vm_name" \
--metric "$metric_name" \
--start-time "$START_TIME" \
--end-time "$END_TIME" \
--interval PT1H \
--aggregation "$aggregation" \
--output tsv \
--query "value[0].timeseries[0].data[*].[timeStamp,${aggregation,,}]")
if [ -n "$result" ]; then
echo "$metric_name ($aggregation):"
echo | IFS=$ timestamp value;
[ -n ] && [ != ];
date_only=$( | -d -f1)
[ = ];
value_rounded=$( )
[ = ];
value_gb=$( | bc -l)
value_rounded=$( )
[ = ];
avg=$( | awk -F )
max=$( | awk -F )
avg=$( | awk -F )
max=$( | awk -F )
}
() {
rg_name=
vm_name=
get_vm_metrics &
get_vm_metrics &
get_vm_metrics &
}
az group list --output tsv --query | rg_name;
vms=$(az vm list -g --output tsv --query )
[ -n ];
| vm_name;
process_vm &
PERFORMANCE COMPARISON TABLE
| Pattern | VMs | Time/Call | Total Time | Speed |
|---|
| Sequential (❌) | 30 | 2 sec | ~60 sec | Baseline |
| Parallel (✅) | 30 | 2 sec | ~2 sec | 30x faster |
| Sequential (❌) | 100 | 2 sec | ~200 sec | Baseline |
| Parallel (✅) | 100 | 2 sec | ~2 sec | 100x faster |
KEY DIFFERENCES IN THIS SCRIPT (What Makes It Parallel)
✅ Line 111: process_vm "$rg_name" "$vm_name" & - spawns as background job
✅ Lines 114-115: wait - waits for all background jobs before continuing
✅ Lines 93-98: Inside process_vm, metrics fetch runs in parallel (with &)
VALIDATION CHECKLIST FOR AGENT
Before outputting ANY script, check every item:
Common Azure CLI Patterns
- List all resource groups:
az group list --output tsv --query "[*].[name,location]"
- List VMs in a resource group:
az vm list -g myResourceGroup --output tsv --query "[*].[name,hardwareProfile.vmSize,provisioningState]"
- Get VM details:
az vm show -g myResourceGroup -n myVM --output tsv --query "[name,hardwareProfile.vmSize,storageProfile.osDisk.diskSizeGb]"
- List storage accounts:
az storage account list --output tsv --query "[*].[name,resourceGroup,location,sku.name]"
- List SQL databases:
az sql db list -g myResourceGroup -s myServer --output tsv --query "[*].[name,status,edition,serviceLevelObjective]"
- Get subscription info:
az account show --output tsv --query "[subscriptionId,name,state]"
- List App Service plans:
az appservice plan list --output tsv --query "[*].[name,resourceGroup,sku.name,numberOfSites]"
- List Key Vaults:
az keyvault list --output tsv --query "[*].[name,resourceGroup,location]"
- Get cost data:
az consumption usage list --start-date 2024-01-01 --end-date 2024-01-31 --output tsv --query "[*].[usageStart,usageEnd,instanceName,pretaxCost]"
Azure Service Naming Patterns
- Virtual Machines: Standard naming like Standard_D2s_v3, Standard_B1ms
- Storage: Standard_LRS, Premium_LRS, Standard_GRS
- SQL Database: Basic, Standard (S0-S12), Premium (P1-P15)
- App Service: Free, Shared, Basic (B1-B3), Standard (S1-S3), Premium (P1-P3)
Parallel vs Sequential Rules
- ALWAYS PARALLEL: Multiple VMs, multiple metrics, multiple resource groups, multiple subscriptions
- ONLY SEQUENTIAL: Operations that depend on previous results (e.g., create then modify, query then filter)
- PARALLEL PATTERN:
{ operation1 & operation2 & operation3 & }; wait
- SEQUENTIAL PATTERN: Only when operation B requires result from operation A
- NEVER: Sequential loops for independent operations - this wastes time and tokens
FORBIDDEN ANTI-PATTERNS (will cause script rejection):
- ❌
for vm in $vms; do az ... ; done (causes O(n) delays; use for vm in $vms; do az ... & done; wait)
- ❌
while read line; do az ... ; done < file (sequential processing; parallelize with background jobs)
- ❌ Nested loops without background jobs:
for rg in $rgs; do for vm in $vms; do cmd; done; done
- ❌ One call at a time when batch API is available (e.g., az vm show for each VM instead of az vm list)
- ❌ Processing outputs sequentially when they could be fetched in parallel:
result1=$(cmd1); result2=$(cmd2) → should be cmd1 & cmd2 & wait
REQUIRED ANTI-PATTERN FIXES:
- ✅ BEFORE:
for vm in $vms; do az vm show -g $rg -n $vm; done
- ✅ AFTER:
for vm in $vms; do az vm show -g $rg -n $vm & done; wait
- ✅ BEFORE:
az vm list -g $rg1; az vm list -g $rg2
- ✅ AFTER:
az vm list -g $rg1 & az vm list -g $rg2 & wait
Output Format
Present results as a structured report:
Azure Report
════════════
Resources discovered: [count]
Resource Status Key Metric Issues
──────────────────────────────────────────────
[name] [ok/warn] [value] [findings]
Summary: [total] resources | [ok] healthy | [warn] warnings | [crit] critical
Action Items: [list of prioritized findings]
Target ≤50 lines of output. Use tables for multi-resource comparisons.
Anti-Hallucination Rules
- NEVER assume resource names — always discover via CLI/API in Phase 1 before referencing in Phase 2.
- NEVER fabricate metric names or dimensions — verify against the service documentation or
--help output.
- NEVER mix CLI commands between service versions — confirm which version/API you are targeting.
- ALWAYS use the discovery → verify → analyze chain — every resource referenced must have been discovered first.
- ALWAYS handle empty results gracefully — an empty response is valid data, not an error to retry.
Counter-Rationalizations
| Shortcut | Counter | Why |
|---|
| "I'll skip discovery and check known resources" | Always run Phase 1 discovery first | Resource names change, new resources appear — assumed names cause errors |
| "The user only asked for a quick check" | Follow the full discovery → analysis flow | Quick checks miss critical issues; structured analysis catches silent failures |
| "Default configuration is probably fine" | Audit configuration explicitly | Defaults often leave logging, security, and optimization features disabled |
| "Metrics aren't needed for this" | Always check relevant metrics when available | API/CLI responses show current state; metrics reveal trends and intermittent issues |
| "I don't have access to that" | Try the command and report the actual error | Assumed permission failures prevent useful investigation; actual errors are informative |