Install
openclaw skills install tf-plan-reviewAnalyze Terraform plans for risk before you apply. Classifies every change as safe, moderate, dangerous, or critical. Detects destroys, IAM changes, data-los...
openclaw skills install tf-plan-reviewAnalyze terraform plan output and produce an AI-powered risk assessment of every infrastructure change — before you press apply.
This skill is STRICTLY READ-ONLY. It runs terraform plan and terraform validate to analyze changes, but it NEVER runs terraform apply, terraform destroy, terraform import, terraform taint, or any command that modifies infrastructure or state.
This skill activates when the user mentions:
permissions:
exec: true # Required to run terraform/tofu CLI
read: true # Read .tf files and plan output
write: false # NEVER writes — strictly read-only analysis
network: true # terraform plan needs provider API access
Understanding Terraform change types is critical for accurate risk assessment:
| Action | Meaning | Risk Profile |
|---|---|---|
create | New resource being added | Generally safe (unless IAM/security) |
update | Existing resource modified in-place | Moderate (depends on what's changing) |
delete | Resource being permanently destroyed | DANGEROUS — data loss risk |
replace (delete + create) | Resource must be destroyed and recreated | DANGEROUS — downtime + data loss |
read | Data source being refreshed | Safe (read-only) |
no-op | No changes needed | Safe |
Critical (🔴 CRITICAL):
Dangerous (🟠 DANGEROUS):
Moderate (🟡 MODERATE):
Safe (🟢 SAFE):
When Terraform says it must "replace" a resource, it means:
This is triggered when an immutable attribute changes (e.g., changing RDS engine_version, EC2 ami, changing a subnet's AZ). The agent should always flag replaces prominently because:
Follow this sequence exactly based on user intent:
bash <skill_dir>/scripts/tf-plan-review.sh plan <directory>
If no directory specified, use the current working directory.
The script outputs:
Parse the JSON output. Key fields:
{
"overall_risk": "🔴 CRITICAL | 🔴 HIGH | 🟡 MODERATE | 🟢 LOW",
"summary": {
"create": 5,
"update": 3,
"destroy": 1,
"replace": 0
},
"risk_breakdown": {
"critical": 1,
"dangerous": 0,
"moderate": 2,
"safe": 5
},
"resources": [
{
"address": "aws_iam_role.admin",
"action": "delete",
"risk": "🔴 CRITICAL"
}
]
}
Show the Markdown report from stderr. Then add your own AI analysis:
Tone guidance for critical plans:
prod-db. All data will be lost. Do you have a backup?"bash <skill_dir>/scripts/tf-plan-review.sh state "<filter>" <directory>
The filter is optional — it greps resource addresses. Examples:
bash <skill_dir>/scripts/tf-plan-review.sh state "iam" . → all IAM resourcesbash <skill_dir>/scripts/tf-plan-review.sh state "aws_instance" . → all EC2 instancesbash <skill_dir>/scripts/tf-plan-review.sh state "" . → all resourcesbash <skill_dir>/scripts/tf-plan-review.sh validate <directory>
Reports configuration errors and warnings without running a plan.
| Variable | Default | Description |
|---|---|---|
TF_BINARY | auto-detect | Override binary: terraform, tofu, or a path |
TF_PLAN_TIMEOUT | 600 | Timeout for terraform plan in seconds |
The script auto-detects terraform first, then tofu. Set TF_BINARY=tofu to force OpenTofu.
| Situation | Behavior |
|---|---|
| terraform/tofu not found | JSON error with install links for both |
| jq not found | JSON error with install link |
| No .tf files in directory | JSON error: "No Terraform configuration files found" |
| Not initialized | Auto-runs terraform init (for plan) or terraform init -backend=false (for validate) |
| Plan fails (provider errors) | Extracts error from plan JSON diagnostics, reports it |
| Plan timeout | Process killed after TF_PLAN_TIMEOUT seconds |
| State not found | JSON error explaining no state exists |
| Empty state | Reports "State is empty — no managed resources" |
terraform apply — not even with -auto-approve, not even with -target, not even "just this one resource". NEVER.terraform destroy — not under any circumstances.terraform import — this modifies state.terraform taint or terraform untaint — these modify state.terraform state mv, terraform state rm, or terraform state push — these modify state.(sensitive). Never try to reveal them.plan, show, state list, state show, validate, init, providers.If the user asks you to apply a plan, respond:
"I can analyze and assess Terraform plans, but I cannot apply them. Applying infrastructure changes requires human review and explicit execution. Based on my analysis, here's what you should verify before running
terraform apply..."
Run the plan analysis. If overall_risk is 🟢 LOW:
"This plan looks safe. It creates X new resources with no destroys or security changes. The pre-apply checklist is straightforward."
If overall_risk is 🔴 CRITICAL:
"⚠️ This plan has CRITICAL risk. [Explain specific dangers]. I strongly recommend review by another team member before applying."
Run plan, then filter for action == "delete" or action == "replace". Present each with:
Run plan, then filter resources matching IAM patterns. For each:
Action: *)Run plan, identify all destroys/replaces, then explain:
When the conversation is happening in a Discord channel:
Show Critical ChangesShow Destroyed ResourcesShow Pre-Apply ChecklistTerraform plan JSON may contain sensitive values. The script does NOT extract resource attribute values — it only extracts resource addresses, types, and actions. However, when presenting results:
(sensitive) by Terraform