avm-tf-telemetry
Skill1 starsChanged 2 months agoMITView on GitHub
Use this skill whenever an Azure Verified Module (AVM) for Terraform needs to wire up, debug, or explain telemetry — the `main.telemetry.tf` file with `modtm_telemetry` + `random_uuid.telemetry` + `data.azapi_client_config.telemetry` + `data.modtm_module_source.telemetry`, the `enable_telemetry` consumer-facing variable (which MUST default to `true` per SFR4), the `modtm` provider's role in shipping anonymous deployment counts to Application Insights, and the AzAPI request-header telemetry that flows alongside it. Also covers the fork-detection logic (whether the module source comes from an `Azure/*` registry/repo vs a fork), and what to do when consumers ask "how do I turn telemetry off". Trigger on phrases like "modtm", "main.telemetry.tf", "enable_telemetry", "AVM telemetry", "turn off telemetry", "telemetry provider", "SFR3", "SFR4", "Data Collection notice", "avm_module_source", "fork_avm".
232 other projects use a version of this.
Adopted by
Most recently taken up by
- Azure/terraform-azurerm-avm-ptn-commercial-marketplaceword for word, first seen Oct 25, 2026
- Azure/terraform-azurerm-avm-ptn-aca-lza-hosting-environmentword for word, first seen Oct 15, 2026
- Azure/terraform-azurerm-avm-res-dataprotection-backupvaultword for word, first seen Oct 10, 2026
- Azure/terraform-azure-avm-res-signalrservice-webpubsubword for word, first seen Oct 1, 2026
- Azure/terraform-azure-avm-res-insights-privatelinkscopeword for word, first seen Sep 30, 2026
- Azure/terraform-azure-avm-res-app-agentword for word, first seen Sep 28, 2026
Other versions232 projects use a version of this.
Word for word · 232
- Azure/terraform-azurerm-avm-ptn-alz★ 135100% same
- Azure/terraform-azurerm-avm-res-keyvault-vault★ 50100% same
- Azure/terraform-azurerm-avm-ptn-aks-production★ 44100% same
- Azure/terraform-azurerm-avm-ptn-aiml-landing-zone★ 42100% same
- Azure/terraform-azurerm-avm-ptn-cicd-agents-and-runners★ 42100% same
- Azure/terraform-azurerm-avm-res-compute-virtualmachine★ 42100% same
- Azure/terraform-azurerm-avm-res-containerservice-managedcluster★ 42100% same
- Azure/terraform-azurerm-avm-res-storage-storageaccount★ 39100% same
- Azure/terraform-azurerm-avm-res-web-site★ 34100% same
- Azure/terraform-azurerm-avm-res-network-privatednszone★ 32100% same
222 more not listed
Edited · 0
None found.
Wrote their own version · 0
None found.
How matches are found. Word for word: the exact same text. Edited: shares passages with this file (“99% same” means 99% of its five-word phrases also appear here; 10% or more counts). Their own version: similar meaning, or, weakest, the same name. We can’t tell which project had it first. Projects are counted among the 200 most-starred candidates, and mentions are links to the repository we found, up to 50 per site, so both counts are a floor.
In this repository15 other files it gives its agents.
- terraform/root/AGENTS.mdAGENTS.md
- terraform/root/.github/copilot-instructions.mdCopilot instructions
- avm-tf-azapiSkill
- avm-tf-classificationsSkill
- avm-tf-codestyleSkill
- avm-tf-conftestSkill
- avm-tf-documentationSkill
- avm-tf-interfacesSkill
- avm-tf-lifecycleSkill
- avm-tf-migrationSkill
- avm-tf-pattern-reviewSkill
- avm-tf-processSkill
- avm-tf-submodulesSkill
- avm-tf-testingSkill
- avm-tf-tflintSkill
The file
We split this skill into the rules it gives an agent
4 rules. About 0 are common, 2 are distinctive, and 2 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈2
Distinctive · estimate
This author's own choices. Worth a look.
2
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Very specific: line 8
Every AVM Terraform module that deploys resources collects anonymous deployment/usage telemetry, on by default, with a single opt-out …
- Distinctive: line 108
No resource names, no resource configurations, no consumer code, no Azure resource IDs.
- Very specific: line 144
If your module consumes another AVM module (typical for pattern modules), pass enable_telemetry through so the consumer's opt-out reliably …
- Distinctive: line 190
Editing the modtm logic to add custom tags: Don't — telemetry shape is standardised.
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
AVM Terraform telemetry
Every AVM Terraform module that deploys resources collects anonymous deployment/usage telemetry, on by default, with a single opt-out variable. The wiring lives in main.telemetry.tf and is maintained by the Mapotf transforms bundled with Avm.Authoring.
New resource-deploying module repositories use AzAPI for every control-plane and supported direct Azure operation. Each permitted azurerm_* resource or data-source block must independently implement one specific unsupported data-plane/non-ARM operation, document the exact block and AzAPI gap with an upstream AzAPI issue or pull request, and be replaced when support ships. One valid block does not authorize another. Telemetry's AzAPI client and request headers complement that requirement.
Fetch https://azure.github.io/Azure-Verified-Modules/llms.txt and confirm the current versions of these sources:
- SFR3 — Deployment/Usage Telemetry
- SFR4 — Telemetry Enablement Flexibility
- https://registry.terraform.io/providers/Azure/modtm/latest
- The current
main_telemetry_tf.mptf.hclandavm_headers_for_azapi.mptf.hcltransforms in https://github.com/Azure/azure-verified-modules-tools aka.ms/avm/telemetry(the consumer-facing page)
The headline rule
Telemetry MUST be on/enabled by default. Consumers MUST be able to disable it by setting
enable_telemetry = false. (SFR4)
A module that deploys resources cannot opt out of telemetry; it exposes the opt-out to the consumer. Removing or defaulting enable_telemetry to false fails AVM linting.
What main.telemetry.tf does
data "azapi_client_config" "telemetry" {
count = var.enable_telemetry ? 1 : 0
}
data "modtm_module_source" "telemetry" {
count = var.enable_telemetry ? 1 : 0
module_path = path.module
}
locals {
# If the module deploys to a single location, surface it on the telemetry record.
# If the module has no location concept, set this to "unknown".
main_location = var.location
}
resource "random_uuid" "telemetry" {
count = var.enable_telemetry ? 1 : 0
}
resource "modtm_telemetry" "telemetry" {
count = var.enable_telemetry ? 1 : 0
tags = merge({
subscription_id = one(data.azapi_client_config.telemetry).subscription_id
tenant_id = one(data.azapi_client_config.telemetry).tenant_id
module_source = one(data.modtm_module_source.telemetry).module_source
module_version = one(data.modtm_module_source.telemetry).module_version
random_id = one(random_uuid.telemetry).result
}, { location = local.main_location })
}
# Derived headers passed to AzAPI requests so server-side telemetry can correlate
locals {
valid_module_source_regex = [
"registry.terraform.io/[A|a]zure/.+",
"registry.opentofu.io/[A|a]zure/.+",
"git::https://github\\.com/[A|a]zure/.+",
"git::ssh:://git@github\\.com/[A|a]zure/.+",
]
fork_avm = !anytrue([
for r in local.valid_module_source_regex :
can(regex(r, one(data.modtm_module_source.telemetry).module_source))
])
avm_azapi_headers = !var.enable_telemetry ? {} : (local.fork_avm ? {
fork_avm = "true"
random_id = one(random_uuid.telemetry).result
} : {
avm = "true"
random_id = one(random_uuid.telemetry).result
avm_module_source = one(data.modtm_module_source.telemetry).module_source
avm_module_version = one(data.modtm_module_source.telemetry).module_version
})
# tflint-ignore: terraform_unused_declarations
avm_azapi_header = join(" ", [for k, v in local.avm_azapi_headers : "${k}=${v}"])
}The moving parts
| Symbol | Role |
data.azapi_client_config.telemetry | Reads the current subscription + tenant ID for the telemetry record. Same data source other places in the module use; the telemetry instance is independent so you can read it even if no AzAPI resource is created. |
data.modtm_module_source.telemetry | Inspects path.module and figures out where the module was loaded from (Registry, GitHub, OpenTofu Registry, etc.) and what version. |
random_uuid.telemetry | Generates a random ID retained with the module instance's Terraform state so telemetry can be correlated without identifying a person. |
modtm_telemetry.telemetry | The actual telemetry "resource" — its lifecycle hooks send a HTTP POST to the AVM telemetry collector with the tags map. |
local.fork_avm | True if the module wasn't loaded from an official Azure/* source — i.e. someone forked the module. Telemetry still flows but is tagged differently. |
local.avm_azapi_headers / avm_azapi_header | Builds the User-Agent value that avm transform merges into the applicable AzAPI create, read, update, and delete header attributes. |
What gets sent
The telemetry record contains:
subscription_id,tenant_id(from the current ARM client context — not consumer's identity)module_source,module_version(so AVM team knows which module + version)location(so we know regional adoption)random_id(correlation; not personally identifying)
No resource names, no resource configurations, no consumer code, no Azure resource IDs. The telemetry is genuinely lightweight — it answers "how often is this module used and at what version" and nothing else.
Required terraform.tf entry
The modtm provider MUST appear in required_providers:
modtm = {
source = "Azure/modtm"
version = "~> 0.3"
}AVM linting checks for this.
The consumer-facing variable
In variables.tf:
variable "enable_telemetry" {
type = bool
default = true
nullable = false
description = <<DESCRIPTION
This variable controls whether or not telemetry is enabled for the module.
For more information see <https://aka.ms/avm/telemetryinfo>.
If it is set to false, then no telemetry will be collected.
DESCRIPTION
}Convention: put enable_telemetry last in variables.tf, after all interface variables (see avm-tf-codestyle).
When a module references other AVM modules (cross-references)
If your module consumes another AVM module (typical for pattern modules), pass enable_telemetry through so the consumer's opt-out reliably disables telemetry across the whole module graph:
module "kv" {
source = "Azure/avm-res-keyvault-vault/azurerm"
version = "~> 0.10"
enable_telemetry = var.enable_telemetry # pass through
# ...
}This is called out in SFR4: "the telemetry parameter value MUST be passed through to these modules".
The /azurerm suffix above is the Registry namespace of an existing legacy module, not an AzureRM provider declaration and not permission to generate hashicorp/azurerm or azurerm_* outside the narrow unsupported data-plane/non-ARM exception. New Registry namespaces use /azure.
The Data Collection notice
Per SFR3 the README MUST include a Data Collection notice with the canonical wording (drawn from Microsoft's open-source guidance). For Terraform, this notice lives in _footer.md (NOT in README.md directly — README.md is auto-generated, see avm-tf-documentation):
<!-- _footer.md -->
## Data Collection
The software may collect information about you and your use of the software and send it to Microsoft. Microsoft may use this information to provide services and improve our products and services. You may turn off the telemetry as described in the [repository](https://aka.ms/avm/telemetry). There are also some features in the software that may enable you and Microsoft to collect data from users of your applications. If you use these features, you must comply with applicable law, including providing appropriate notices to users of your applications together with a copy of Microsoft's privacy statement. Our privacy statement is located at <https://go.microsoft.com/fwlink/?LinkID=824704>. You can learn more about data collection and use in the help documentation and our privacy statement. Your use of the software operates as your consent to these practices.The template ships _footer.md with this notice — don't delete it.
When do you edit main.telemetry.tf?
Almost never. The file is governance-managed and meant to stay identical across modules. Run avm sync and avm transform rather than copying a potentially stale template. The only normal module-specific edit is to local.main_location if your module:
- Doesn't accept a
locationvariable (e.g. a global resource) — setmain_location = "unknown". - Sources its location from a collection or computed value — set
main_location = <the right expression>.
Everything else is part of the standard, validated wiring. If you find yourself wanting to modify how telemetry is collected, that's a conversation for the AVM core team, not a per-module change.
Utility modules
Per SFR3, utility modules that deploy no resources MUST NOT include telemetry. The modtm_telemetry resource itself counts as a "resource that gets deployed", so adding it to a pure-logic utility module triggers a no-op resource in consumer plans for no benefit.
Common pitfalls
- Defaulting
enable_telemetry = false. SFR4 violation. Defaults totrue, period. - Removing
main.telemetry.tfbecause "I don't see why my module needs it". SFR3 violation; CI fails. The whole point is that telemetry is uniform across the AVM ecosystem. - Editing the modtm logic to add custom tags. Don't — telemetry shape is standardised. If you genuinely need richer telemetry (e.g. for a new module class), raise it with the AVM core team.
- Not passing
enable_telemetrythrough to child AVM modules. A consumer who setsenable_telemetry = falseon the pattern module expects telemetry off for the whole graph; if you don't pass it through, child resource modules still emit telemetry. - Forgetting the Data Collection notice in
_footer.md. Required by SFR3. The template includes it; deletions will fail review. - Putting the Data Collection notice in
README.mddirectly. It gets overwritten on the nextavm pre-commitrun. Put it in_footer.md. - Using a
modtmversion other than~> 0.3. Pinned by spec and validated by lint.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

