{
 "id": "terraform",
 "kind": "skill",
 "name": "Terraform and OpenTofu",
 "description": "Write, check, plan and change Terraform or OpenTofu infrastructure code (HCL), including Azure (azurerm) resources, modules, state and providers.",
 "version": "1.0.0",
 "author": "Hexa Hub",
 "files": {
  "SKILL.md": "---\nname: terraform\ndescription: Write, check, plan and change Terraform or OpenTofu infrastructure code (HCL), including Azure (azurerm) resources, modules, state and providers.\ntitle: Terraform and OpenTofu\nicon: tabler:brand-terraform\ncategory: Infrastructure as code\ntriggers: terraform, tofu, opentofu, hcl, tfvars, tfstate, azurerm, provider, module, plan, apply\nmarkers: terraform, tofu, tflint\nrecipes: terraform.init, terraform.fmt-check, terraform.fmt, terraform.validate, terraform.tflint, terraform.plan, terraform.apply, terraform.state-list, terraform.state-show, help.terraform, help.terraform-schema\nrelated: azure-admin\ncheck: *.tf => terraform.fmt-check dir=$dir\n---\n\n# Terraform\n\nUse recipes, not run_command. Terraform is `terraform.*`; on a Windows PC without it, `toolchain` shows how to install it.\n\n**Check or review request** (\"check the code\", \"what is wrong\"): read the files, run `terraform.fmt-check` and `terraform.validate` (and `terraform.tflint` if installed), then answer with what they report plus what you saw in the code. Do not run init, plan or apply for a review. If a tool is not installed, say so and carry on with the others.\n\n## Workflow for a change\n1. **Look first.** `list_dir` / `find_code` for where it belongs. Read `versions.tf` (or the `terraform {}` block) and `.terraform.lock.hcl` for the Terraform and provider versions. Follow the existing file layout and naming.\n2. `terraform.init` once per folder (needs your cloud login for the backend).\n3. Edit with `edit_file`. Keep the change small; one concern per change.\n4. `terraform.fmt-check`, then `terraform.validate`, then `terraform.tflint` when installed. Fix every error before going on.\n5. `terraform.plan`. **Read the summary to the user in plain words**: adds, changes, destroys. Call out every line with `destroy`, `must be replaced` or `forces replacement` and say which resource and why.\n6. Only if the user asks to apply: `terraform.apply`. It asks the user, works only right after an unchanged plan, and is blocked on prod workspaces.\n\nNever: edit state or `*.tfstate` by hand, run destroy, put secrets in `.tf` or `.tfvars` files, change the backend without being asked.\n\n## Do not guess arguments\nResource arguments change between provider versions. Look them up for the installed version:\n- `help.terraform-schema` saves the full schema; then `read_output` with `grep` on the resource name, for example `azurerm_mssql_managed_instance`.\n- `help.terraform` with `command` for CLI options.\n\nExample: `run_recipe {\"recipe\":\"terraform.plan\",\"args\":{\"dir\":\"infra/prod-network\"}}`\n\n## Style that avoids trouble\n- Pin versions: `required_version` and `required_providers` with `~>`; commit `.terraform.lock.hcl`.\n- `for_each` (a map or set of stable keys) instead of `count` for things with identity, so removing one item does not renumber and recreate the others. Use `moved {}` blocks to rename or move resources without recreating them.\n- Variables get a `type` and `description`; secret ones get `sensitive = true`. Pass secrets with environment variables (`TF_VAR_name`) or a Key Vault data source, never in files.\n- Modules: `main.tf`, `variables.tf`, `outputs.tf`, `versions.tf`. A module takes inputs and returns outputs; it does not read global state.\n- `lifecycle { prevent_destroy = true }` on databases and other data stores; `ignore_changes` only with a comment saying why.\n- Prefer `depends_on` rarely; reference attributes so Terraform sees the dependency.\n\n## Azure (azurerm) notes\n- The provider needs `features {}`. From provider 4.x a `subscription_id` is required in the provider block or `ARM_SUBSCRIPTION_ID`. Check the version in the lock file before advising.\n- Authenticate with the Azure CLI login (`az.account-show` shows who and which subscription). Check the subscription before any plan.\n- Names are global for storage accounts, key vaults and web apps; add a suffix. Tag resources the way the existing code does.\n- Many resources recreate when a \"ForceNew\" argument changes (location, name, SKU family): the plan shows `forces replacement`; stop and ask before accepting it for stateful resources.\n\n## OpenTofu\nSame language and commands. The recipes call `terraform`; if only `tofu` is installed say so and tell the user it needs the `terraform` name or a shim.\n\n## Report\nEnd with: what changed, the plan summary, what you verified (validate/plan results) and anything you could not check.\n"
 }
}
