{
 "id": "iac-ansible-terraform-puppet",
 "kind": "skill",
 "name": "IaC overview: Ansible, Terraform, Puppet",
 "description": "Infrastructure as code with Ansible, Terraform (and providers) and Puppet: writing, validating and safely applying changes. Use for playbooks, roles, modules, manifests, HCL.",
 "version": "1.0.0",
 "author": "Hexa Hub",
 "files": {
  "SKILL.md": "---\nname: iac-ansible-terraform-puppet\ndescription: Infrastructure as code with Ansible, Terraform (and providers) and Puppet: writing, validating and safely applying changes. Use for playbooks, roles, modules, manifests, HCL.\ntitle: IaC overview: Ansible, Terraform, Puppet\nicon: tabler:server-cog\ncategory: Infrastructure as code\n---\n\n# Infrastructure as code\n\nUniversal rules: idempotent changes, version-controlled, secrets never in plain text, **validate and preview before\napplying**, and never apply to production without showing the user the preview first. Versions matter: ask which\nversion/provider/OS if the answer depends on it, and check the official docs (`devtools__web_search` topic `ansible`,\n`terraform`, `puppet`).\n\n## Ansible\n- Use modules, not `shell`/`command`, so tasks are idempotent. If you must use `command`, add `creates:`/`changed_when:`.\n- Use fully qualified names (`ansible.builtin.copy`, `ansible.posix.firewalld`). Check module args in docs.ansible.com.\n- Preview: `ansible-playbook site.yml --syntax-check`, then `--check --diff`, then the real run (with `--limit` first).\n- Secrets with `ansible-vault`; never log them (`no_log: true`). Handlers for restarts. Quote YAML values that could parse\n  as booleans or numbers (`\"yes\"`, `\"0644\"` as a string mode). Prefer `become` at task/play level, not root SSH.\n- Layout: roles with `defaults/` (overridable) vs `vars/` (fixed). Lint with `ansible-lint`.\n\n## Terraform\n- Always `terraform fmt`, `terraform validate`, then `terraform plan -out=plan.tfplan`; show the plan summary\n  (adds/changes/destroys) and highlight any destroy or replace before `apply`.\n- Pin provider and Terraform versions (`required_providers`, `required_version`) and commit `.terraform.lock.hcl`.\n- State holds secrets: remote backend with locking and encryption; never commit state or `*.tfvars` with secrets.\n- `for_each` over `count` for things with identity; use `moved` blocks to refactor without recreating; avoid\n  `terraform taint`/manual state edits unless asked. `lifecycle { prevent_destroy = true }` for critical resources.\n- Check resource arguments in the provider docs on registry.terraform.io for the pinned version; don't guess attributes.\n\n## Puppet\n- `puppet parser validate`, `puppet-lint`, then `puppet agent -t --noop` to preview, then apply.\n- Data in Hiera, logic in profiles, roles compose profiles (roles/profiles pattern). Keep modules small.\n- Resources must be idempotent. `exec` needs `creates`, `unless` or `onlyif`; prefer native types.\n- Mind resource ordering (`require`, `before`, `notify`, `->`); avoid duplicate declarations; test in a separate environment.\n"
 }
}
