agentleFS
rhawk117rhawk117/cc-terraform-harness/skills/explain-plan/SKILL.md

explain-plan

Skill1 starsChanged 26 days agoApache-2.0View on GitHub

Explain a Terraform plan in plain language that cuts straight to what matters - verdict first, then what changes, then what could hurt. Use this whenever the user pastes or points at plan output (`terraform show -json plan.out`, a plan JSON export, or a plan file that can be rendered that way) and wants to know what it will do, whether it is safe to apply, what will be destroyed or replaced, or a summary for a reviewer or non-Terraform stakeholder. Trigger even when they just say "what does this do", "is this safe", "summarize this plan", or "tl;dr this" with a plan in front of them. Do not use for writing or refactoring Terraform code, state surgery, or provider errors that are not plan output.

4 other projects use a version of this.

Adopted by

Most recently taken up by

The file

We split this skill into the rules it gives an agent

8 rules. 0 are common, 5 are distinctive, and 3 are very specific to this project.

  • 0

    Common

    Most of the 4 edited versions we read keep these.

  • 5

    Distinctive

    This author's own choices. Worth a look.

  • 3

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Very specific:

    Call the plan_digest tool with path set to the JSON file.

    line 18
  2. Distinctive:

    Write the explanation in the format below.

    line 26
  3. Distinctive:

    Do not narrate every resource.

    line 58
  4. Very specific:

    Do not hedge with "may" and "could" when the plan is definite.

    line 59
  5. Distinctive:

    No praise, no preamble, no "Here's a breakdown of your plan".

    line 60
  6. Distinctive:

    When the plan is clean, the whole explanation can be three lines.

    line 61
  7. Distinctive:

    Never invent values the plan does not contain.

    line 62
  8. Very specific:

    When you tell the reader how to apply, name the saved plan file the JSON came from (terraform apply plan.out).

    line 63

“Common” is measured: kept by at least 6 in 10 of the 4 edited versions of this file we could read. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

Terraform plan explainer

A plan is the only honest preview of what apply will do, and almost nobody reads the whole thing. Reviewers skim for the Plan: line, miss the one # forces replacement buried in 400 lines of tag diffs, and find out about the database rebuild during the maintenance window. This skill exists to make the one paragraph that matters impossible to miss.

The reader might be the SRE approving the apply, the engineer who wrote the change, or a manager who has never seen HCL. Write so the first two lines serve all three and the rest rewards whoever keeps reading.

Workflow

  1. Get the plan as JSON in a file inside the project root. plan_digest reads only terraform show -json output and refuses any path outside the project root, so a file under /tmp cannot be digested. If the user has a binary plan file (plan.out, tfplan), render it with terraform show -json plan.out > plan.json in the module directory. If they pasted JSON, write it to a file in the project. Plan text is not supported: when that is all you have, ask for the plan file or the JSON rendering, and do not guess values from text.
  2. Call the plan_digest tool with path set to the JSON file. It does the counting so you don't miscount by eye.

    The result carries counts per action, every changed resource in resource_changes with its actions, the attributes that forced a replacement (forced_by), the names of its sensitive_attributes and its flags, the output_changes, and the top level moves, imports, drifted addresses and plan_flags (mass-destroy, drift, unsupported-action). The flags are described in references/risk-heuristics.md. Trust its counts over your own reading of the plan. A refused path or an unreadable document is the first line of your explanation, not a footnote.

  3. Read the digest, then read the plan itself for anything it flagged. The tool finds the risk; you explain it. For a large plan, dispatch one terraform-researcher per flagged resource or per module address in parallel, each asked what the plan says about that address and what in the configuration explains it; they are cheap and disposable, and their reports give you the before/after facts and the declaring file without pulling the whole plan into your context.
  4. Check what the plan does besides create, update and destroy. moves are renames in state with no infrastructure change, unless with_change says the resource also changes. For each move, check in the plan that the identifying attributes (name, identifier, ARN) are the same before and after: a move to the wrong object shows no replacement while state now tracks a different resource. imports bring existing resources under management, and drifted lists resources someone changed outside Terraform, which the plan may be reverting. Say each in one line.
  5. Write the explanation in the format below.

Output format

Lead with the worst thing. If the plan is boring, say so in one line and stop early. Length scales with risk, not with the number of resources.

**Verdict:** <one sentence: safe to apply / needs a look / do not apply as-is, plus the counts that matter>

**What it does**
- 2-6 bullets, grouped by intent, not by resource. "Adds a read replica for the orders database in us-west-2", not "creates aws_db_instance.orders_replica".
- Collapse noise into one bullet: "Tag and description updates on 14 resources, no behavior change."

**Watch out**  (omit the section entirely when there is nothing here)
- Destroys, replacements and what forced them, downtime, data loss, public exposure, IAM widening, cost jumps. One bullet each, concrete: "`aws_db_instance.main` is replaced because `engine_version` changed 14 -> 16. Replacement is delete-then-create: the database is gone until the new one is up, and the data goes with it unless a snapshot exists."

**Details**  (only when the reader wants them, or the plan has more than ~10 changes; wrap in <details> for PR comments)
| Resource | Action | Why |

Verdict wording:

  • Safe to apply - creates and in-place updates only, nothing in the watch-out list.
  • Needs a look - replacements, destroys of stateless things, security-adjacent changes, or anything the digest flagged.
  • Do not apply as-is - destroys or replaces a stateful resource without evidence of a backup, opens something to the internet, grants wildcard IAM (* actions, resources or principals), strips deletion protection, or the plan destroys a large share of the workspace.

Writing rules and why

  • Translate resource types into what they are. aws_db_instance is a database, google_compute_firewall is a firewall rule, kubernetes_deployment is a running workload. The manager does not know the type names and the SRE does not need them repeated.
  • Name the attribute that forced a replacement and the direction of the change. "Replaced" alone is useless; "replaced because subnet_id changed" tells the engineer whether that was intended.
  • Distinguish delete-then-create from create-before-destroy. One is an outage window, the other usually is not. The digest tells you which (replace-delete-first or replace-create-first).
  • Say what is lost. Destroying a bucket, database, queue, disk, KMS key or secret loses data or the ability to decrypt it. Say that plainly instead of "resource will be destroyed".
  • Do not narrate every resource. If 30 security group rules are being recreated because a module was refactored, that is one bullet: "The module refactor recreates all 30 ingress rules; brief window where rules are absent."
  • Do not hedge with "may" and "could" when the plan is definite. The plan says what will happen. Uncertainty only belongs where Terraform itself says (known after apply).
  • No praise, no preamble, no "Here's a breakdown of your plan". Start with the verdict.
  • When the plan is clean, the whole explanation can be three lines. Padding a safe plan to look thorough trains readers to skim, which is the problem this skill exists to fix.
  • Never invent values the plan does not contain. Sensitive attributes appear in the digest by name only; say that they changed, not what they changed to.
  • When you tell the reader how to apply, name the saved plan file the JSON came from (terraform apply plan.out). Never suggest terraform apply -auto-approve: it plans again and can apply something other than what you explained.

Reading the digest

references/risk-heuristics.md lists the resource-type patterns and attribute patterns plan_digest flags and explains why each matters. Read it when a flag fires that you don't immediately understand, or when a plan contains a provider the heuristics don't cover and you need to judge stateful-vs-stateless yourself.

The heuristics are deliberately conservative: a flag means "look here", not "this is wrong". Downgrade a flag in your explanation when the plan itself shows it is fine (for example a destroy of an aws_s3_bucket whose force_destroy is false will fail rather than lose data, and a create_before_destroy replacement of a stateless resource is routine).

Examples

Boring plan, engineer asked "what does this do":

Verdict: Safe to apply. 3 in-place updates, nothing destroyed or replaced.

What it does

  • Bumps the api ECS service from 2 to 4 tasks and raises its CPU reservation.
  • Tag updates on the ALB and target group, no behavior change.

Dangerous plan, SRE asked "is this safe":

Verdict: Do not apply as-is. 1 replacement of a production database and 1 security group opened to the internet, alongside 6 routine updates.

What it does

  • Upgrades the main Postgres database from engine 14 to 16 and moves it to the new private subnets.
  • Opens port 5432 on the database security group to 0.0.0.0/0.
  • Adjusts autoscaling limits and tags on the app tier.

Watch out

  • aws_db_instance.main is replaced because subnet_group_name changed; the engine bump alone would have been in-place. Replacement is delete-then-create, so the database and its data are gone until the new instance finishes, and the plan shows no snapshot. Confirm a snapshot exists or set skip_final_snapshot = false first.
  • Ingress rule on aws_security_group.db changes from the app subnet CIDR to 0.0.0.0/0 on 5432. That exposes the database to the internet. Almost certainly a mistake.

Download now (ZIP)

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
What did you use it for? e.g. Reviewing pull requests in a Rails app

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.