tfc-plan-json

Terraform Cloud Plan JSON

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "tfc-plan-json" with this command: npx skills add laurigates/claude-plugins/laurigates-claude-plugins-tfc-plan-json

Terraform Cloud Plan JSON

Download and analyze structured plan JSON output from Terraform Cloud runs for detailed resource change analysis.

Prerequisites

export TFE_TOKEN="your-api-token" # User or team token with admin workspace access export TFE_ADDRESS="app.terraform.io" # Optional

Core Commands

Download Plan JSON

#!/bin/bash set -euo pipefail

TOKEN="${TFE_TOKEN:?TFE_TOKEN not set}" BASE_URL="https://${TFE_ADDRESS:-app.terraform.io}/api/v2" RUN_ID="${1:?Usage: $0 <run-id> [output-file]}" OUTPUT="${2:-plan.json}"

Download with redirect following (API returns 307)

curl -Lsf --header "Authorization: Bearer $TOKEN"
-o "$OUTPUT"
"$BASE_URL/runs/$RUN_ID/plan/json-output"

echo "Plan JSON saved to: $OUTPUT"

Download via Plan ID

TOKEN="${TFE_TOKEN:?TFE_TOKEN not set}" PLAN_ID="plan-xyz789"

curl -Lsf --header "Authorization: Bearer $TOKEN"
-o plan.json
"https://app.terraform.io/api/v2/plans/$PLAN_ID/json-output"

Analysis Commands

Resource Change Summary

curl -Lsf --header "Authorization: Bearer $TFE_TOKEN"
"https://app.terraform.io/api/v2/runs/$RUN_ID/plan/json-output" |
jq '{ terraform_version: .terraform_version, format_version: .format_version, summary: { create: [.resource_changes[] | select(.change.actions | contains(["create"]))] | length, update: [.resource_changes[] | select(.change.actions | contains(["update"]))] | length, delete: [.resource_changes[] | select(.change.actions | contains(["delete"]))] | length, replace: [.resource_changes[] | select(.change.actions | contains(["delete", "create"]))] | length, read: [.resource_changes[] | select(.change.actions | contains(["read"]))] | length, no_op: [.resource_changes[] | select(.change.actions == ["no-op"])] | length } }'

List Resources Being Created

curl -Lsf --header "Authorization: Bearer $TFE_TOKEN"
"https://app.terraform.io/api/v2/runs/$RUN_ID/plan/json-output" |
jq -r '.resource_changes[] | select(.change.actions | contains(["create"])) | .address'

List Resources Being Destroyed

curl -Lsf --header "Authorization: Bearer $TFE_TOKEN"
"https://app.terraform.io/api/v2/runs/$RUN_ID/plan/json-output" |
jq -r '.resource_changes[] | select(.change.actions | contains(["delete"])) | .address'

List Resources Being Updated

curl -Lsf --header "Authorization: Bearer $TFE_TOKEN"
"https://app.terraform.io/api/v2/runs/$RUN_ID/plan/json-output" |
jq -r '.resource_changes[] | select(.change.actions | contains(["update"])) | .address'

Resources Being Replaced

curl -Lsf --header "Authorization: Bearer $TFE_TOKEN"
"https://app.terraform.io/api/v2/runs/$RUN_ID/plan/json-output" |
jq -r '.resource_changes[] | select(.change.actions | contains(["delete", "create"])) | "(.address) (replace due to: (.action_reason // "unknown"))"'

Detailed Resource Changes

curl -Lsf --header "Authorization: Bearer $TFE_TOKEN"
"https://app.terraform.io/api/v2/runs/$RUN_ID/plan/json-output" |
jq '.resource_changes[] | select(.change.actions != ["no-op"]) | { address: .address, actions: .change.actions, before: .change.before, after: .change.after }'

Show What's Changing in a Specific Resource

RESOURCE="aws_instance.web"

curl -Lsf --header "Authorization: Bearer $TFE_TOKEN"
"https://app.terraform.io/api/v2/runs/$RUN_ID/plan/json-output" |
jq --arg addr "$RESOURCE" ' .resource_changes[] | select(.address == $addr) | { address: .address, actions: .change.actions, before: .change.before, after: .change.after, after_unknown: .change.after_unknown }'

Provider Versions Used

curl -Lsf --header "Authorization: Bearer $TFE_TOKEN"
"https://app.terraform.io/api/v2/runs/$RUN_ID/plan/json-output" |
jq '.configuration.provider_config | to_entries | map({ provider: .key, version: .value.version_constraint })'

Output Values

curl -Lsf --header "Authorization: Bearer $TFE_TOKEN"
"https://app.terraform.io/api/v2/runs/$RUN_ID/plan/json-output" |
jq '.output_changes | to_entries | map({ name: .key, actions: .value.actions, sensitive: .value.after_sensitive })'

Variables Used

curl -Lsf --header "Authorization: Bearer $TFE_TOKEN"
"https://app.terraform.io/api/v2/runs/$RUN_ID/plan/json-output" |
jq '.variables | keys'

Complete Analysis Script

#!/bin/bash set -euo pipefail

TOKEN="${TFE_TOKEN:?TFE_TOKEN not set}" RUN_ID="${1:?Usage: $0 <run-id>}"

PLAN=$(curl -Lsf --header "Authorization: Bearer $TOKEN"
"https://app.terraform.io/api/v2/runs/$RUN_ID/plan/json-output")

echo "=== Plan Analysis for $RUN_ID ===" echo "" echo "Terraform Version: $(echo "$PLAN" | jq -r '.terraform_version')" echo ""

echo "Resource Changes:" echo " Create: $(echo "$PLAN" | jq '[.resource_changes[] | select(.change.actions | contains(["create"]))] | length')" echo " Update: $(echo "$PLAN" | jq '[.resource_changes[] | select(.change.actions | contains(["update"]))] | length')" echo " Delete: $(echo "$PLAN" | jq '[.resource_changes[] | select(.change.actions | contains(["delete"]))] | length')" echo " Replace: $(echo "$PLAN" | jq '[.resource_changes[] | select(.change.actions | contains(["delete", "create"]))] | length')" echo ""

echo "Resources to Create:" echo "$PLAN" | jq -r '.resource_changes[] | select(.change.actions | contains(["create"])) | " - " + .address'

echo "" echo "Resources to Destroy:" echo "$PLAN" | jq -r '.resource_changes[] | select(.change.actions | contains(["delete"])) | " - " + .address'

echo "" echo "Resources to Update:" echo "$PLAN" | jq -r '.resource_changes[] | select(.change.actions | contains(["update"])) | " - " + .address'

Plan JSON Structure

The plan JSON output follows Terraform's JSON plan format:

{ "format_version": "1.2", "terraform_version": "1.5.0", "planned_values": { ... }, "resource_changes": [ { "address": "aws_instance.web", "mode": "managed", "type": "aws_instance", "name": "web", "provider_name": "registry.terraform.io/hashicorp/aws", "change": { "actions": ["create"], "before": null, "after": { ... }, "after_unknown": { ... }, "before_sensitive": false, "after_sensitive": { ... } } } ], "output_changes": { ... }, "configuration": { ... }, "variables": { ... } }

Change Actions

  • ["create"]

  • Resource will be created

  • ["delete"]

  • Resource will be destroyed

  • ["update"]

  • Resource will be updated in-place

  • ["delete", "create"]

  • Resource will be replaced

  • ["read"]

  • Data source will be read

  • ["no-op"]

  • No changes

Important Notes

  • Requires Terraform 0.12+ for JSON output support

  • Returns 204 No Content if plan hasn't completed yet

  • Follow redirects - API returns HTTP 307 to temporary download URL

  • Temporary URL - Download URL is valid for ~1 minute

  • Admin access required - Need admin permissions on the workspace

Error Handling

204 No Content

Plan hasn't completed yet. Check run status first.

401 Unauthorized

Token lacks admin workspace access or is invalid.

404 Not Found

Run doesn't exist or you don't have permission.

See Also

  • tfc-run-logs : Get plan/apply logs (human-readable)

  • tfc-run-status : Quick status check for a run

  • tfc-list-runs : List recent runs in a workspace

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

General

ruff linting

No summary provided by upstream source.

Repository SourceNeeds Review
General

imagemagick-conversion

No summary provided by upstream source.

Repository SourceNeeds Review
General

jq json processing

No summary provided by upstream source.

Repository SourceNeeds Review
General

api-testing

No summary provided by upstream source.

Repository SourceNeeds Review