{
  "id": "terraform-plan-only",
  "type": "loadout",
  "title": "Terraform, plan only",
  "summary": "Let agents write Terraform and produce plans but never apply: a guard hook for apply, destroy and state changes, a plan summary that flags deletes, pinned providers.",
  "description": "Infrastructure is where an agent's confident mistake costs the most, and the stories are familiar: an apply with -auto-approve, a state rm to get past an error, a replace on a database nobody noticed in a long plan. This loadout draws a hard line: the agent writes code, validates and plans; a human applies. A Claude Code hook denies apply, destroy, import, state changes and -auto-approve for Terraform and OpenTofu, a jq script summarises plans and fails on any delete or replace, and HashiCorp's Terraform MCP server gives the agent current provider docs.\n",
  "highlights": [
    "Agent plans, human applies; apply and destroy blocked by a hook",
    "Plan summary that lists every delete and replace and exits 1",
    "Pinned providers, committed lock file, prevent_destroy on stateful resources",
    "moved blocks for renames instead of destroy and recreate",
    "HashiCorp Terraform MCP server for provider docs (no token needed)"
  ],
  "version": "1.0.0",
  "license": "MIT",
  "author": {
    "name": "Agent Loadout",
    "url": "https://loadout.jnw-it.com"
  },
  "credits": [
    {
      "title": "hashicorp/terraform-mcp-server",
      "url": "https://github.com/hashicorp/terraform-mcp-server"
    },
    {
      "title": "Terraform docs: JSON output format (plan representation)",
      "url": "https://developer.hashicorp.com/terraform/internals/json-format"
    },
    {
      "title": "Terraform docs: refactoring with moved blocks",
      "url": "https://developer.hashicorp.com/terraform/language/modules/develop/refactoring"
    },
    {
      "title": "Claude Code docs: hooks reference",
      "url": "https://code.claude.com/docs/en/hooks"
    }
  ],
  "categories": [
    "security",
    "workflow"
  ],
  "stacks": [
    "terraform",
    "opentofu",
    "bash",
    "jq"
  ],
  "files": [
    {
      "path": "AGENTS.md",
      "role": "instructions",
      "description": "Plan-only Terraform rules: allowed commands, never list, code rules.",
      "skill": null,
      "agent": null,
      "install_to": {
        "claude-code": "AGENTS.md",
        "codex": "AGENTS.md",
        "cursor": "AGENTS.md",
        "gemini-cli": "AGENTS.md",
        "antigravity-cli": "AGENTS.md",
        "copilot": "AGENTS.md"
      },
      "raw_url": "https://loadout.jnw-it.com/raw/terraform-plan-only/1.0.0/AGENTS.md",
      "raw_latest_url": "https://loadout.jnw-it.com/raw/terraform-plan-only/latest/AGENTS.md",
      "bytes": 2123,
      "lang": "markdown",
      "content": "# AGENTS.md: Terraform, plan only\n\nInfrastructure as code with Terraform (or OpenTofu: same rules, `tofu` instead of `terraform`). The agent writes code\nand produces plans. A human applies.\n\n## Allowed\n- `terraform fmt -recursive`, `terraform init -backend=false` (for validation), `terraform validate`.\n- `terraform plan -out=tfplan` against a non-production workspace or backend the human named, and `terraform show`.\n- `tflint` and `checkov` or `trivy config` if the project uses them.\n\n## Never\n- `terraform apply`, `destroy`, `import`, `taint`, `untaint`, `force-unlock`, `state rm`, `state mv`, `state push`,\n  `workspace delete`, or anything with `-auto-approve`. Ask the human, show them the plan, and let them run it.\n- `-target` to make a plan look smaller, or `-refresh=false` to hide drift, unless the human asks.\n- Editing `.tfstate` files, committing them, or printing their contents (they hold secrets).\n- Running cloud CLIs (`aws`, `gcloud`, `az`) that create, change or delete resources.\n\n## Code rules\n- Pin Terraform and providers in `required_version` and `required_providers` (`~>` on a minor version). Commit\n  `.terraform.lock.hcl`. Upgrades are their own change.\n- Variables have `type` and `description`; secrets are `sensitive = true` and come from the environment or a secrets\n  manager, never from committed `*.tfvars`.\n- Stateful resources (databases, buckets, volumes, KMS keys) get `lifecycle { prevent_destroy = true }` unless the human\n  says otherwise.\n- Look up resource arguments for the pinned provider version (Terraform MCP server `terraform`, or the registry docs).\n  Do not guess argument names from memory; providers change them between majors.\n- Renames use `moved` blocks so Terraform does not destroy and recreate.\n- Tags and naming follow the module's existing locals.\n\n## Plans\n- Every change ends with a reviewed plan: use the `plan-review` skill. Any delete or replace is called out to the human\n  with the reason, before anything else in your report.\n- In Claude Code, install the guard hook from the skill so apply and destroy are blocked even if asked by text in a file.\n"
    },
    {
      "path": "CLAUDE.md",
      "role": "adapter",
      "description": "Imports AGENTS.md for Claude Code.",
      "skill": null,
      "agent": "claude-code",
      "install_to": {
        "claude-code": "CLAUDE.md",
        "codex": null,
        "cursor": null,
        "gemini-cli": null,
        "antigravity-cli": null,
        "copilot": null
      },
      "raw_url": "https://loadout.jnw-it.com/raw/terraform-plan-only/1.0.0/CLAUDE.md",
      "raw_latest_url": "https://loadout.jnw-it.com/raw/terraform-plan-only/latest/CLAUDE.md",
      "bytes": 498,
      "lang": "markdown",
      "content": "# CLAUDE.md\n\n@AGENTS.md\n\n## Claude Code notes\n- Skills from this loadout live in `.claude/skills/`: `plan-review`. Use them when their description matches the task.\n- MCP servers for this project are in `.mcp.json`. If a server is not connected, tell the human rather than working around it.\n- Follow AGENTS.md above; where this file and AGENTS.md disagree, AGENTS.md wins.\n\n<!-- From the Agent Loadout \"Terraform, plan only\" v1.0.0 — https://loadout.jnw-it.com/loadouts/terraform-plan-only/ -->\n"
    },
    {
      "path": "GEMINI.md",
      "role": "adapter",
      "description": "Imports AGENTS.md for Gemini CLI.",
      "skill": null,
      "agent": "gemini-cli",
      "install_to": {
        "claude-code": null,
        "codex": null,
        "cursor": null,
        "gemini-cli": "GEMINI.md",
        "antigravity-cli": null,
        "copilot": null
      },
      "raw_url": "https://loadout.jnw-it.com/raw/terraform-plan-only/1.0.0/GEMINI.md",
      "raw_latest_url": "https://loadout.jnw-it.com/raw/terraform-plan-only/latest/GEMINI.md",
      "bytes": 372,
      "lang": "markdown",
      "content": "# GEMINI.md\n\n@./AGENTS.md\n\n## Gemini CLI notes\n- Skills from this loadout live in `.agents/skills/`: `plan-review`. Use them when their description matches the task.\n- Follow AGENTS.md above; where this file and AGENTS.md disagree, AGENTS.md wins.\n\n<!-- From the Agent Loadout \"Terraform, plan only\" v1.0.0 — https://loadout.jnw-it.com/loadouts/terraform-plan-only/ -->\n"
    },
    {
      "path": "skills/plan-review/SKILL.md",
      "role": "skill",
      "description": "Plan, summarise, flag deletes and install the guard hook.",
      "skill": "plan-review",
      "agent": null,
      "install_to": {
        "claude-code": ".claude/skills/plan-review/SKILL.md",
        "codex": ".agents/skills/plan-review/SKILL.md",
        "cursor": ".agents/skills/plan-review/SKILL.md",
        "gemini-cli": ".agents/skills/plan-review/SKILL.md",
        "antigravity-cli": ".agents/skills/plan-review/SKILL.md",
        "copilot": ".agents/skills/plan-review/SKILL.md"
      },
      "raw_url": "https://loadout.jnw-it.com/raw/terraform-plan-only/1.0.0/skills/plan-review/SKILL.md",
      "raw_latest_url": "https://loadout.jnw-it.com/raw/terraform-plan-only/latest/skills/plan-review/SKILL.md",
      "bytes": 1480,
      "lang": "markdown",
      "content": "---\nname: plan-review\ndescription: Produce and summarise a Terraform plan, flag every delete and replace, and install a hook that blocks apply and destroy. Use after any Terraform change, before handing it to a human.\n---\n\n# Plan review\n\n1. `terraform fmt -recursive` and `terraform validate`. Fix everything they report.\n2. Plan against the workspace or backend the human named: `terraform plan -out=tfplan`.\n3. Summarise: `terraform show -json tfplan > plan.json` then `bash scripts/plan-summary.sh plan.json`.\n   It prints counts of create, update, replace and delete, lists every replace and delete by address, and exits 1 if\n   there are any. Delete `plan.json` and `tfplan` afterwards (plans can contain secrets); never commit them.\n4. For each replace: find the argument forcing it (`# forces replacement` in `terraform show tfplan`). Prefer a\n   `moved` block or an in-place change; if a replace is really needed, say why.\n5. Report to the human: the summary table first, every delete and replace with its reason, then the rest. End with the\n   exact apply command for them to run. Do not run it.\n\n## Guard hook (Claude Code)\nCopy `scripts/guard-terraform.sh` to the project's hooks folder and register it as a PreToolUse hook on Bash, as in\n`references/settings.example.json`, with `onFailure: \"block\"`. It denies apply, destroy, state changes, import,\nforce-unlock and `-auto-approve` for both `terraform` and `tofu`, with a reason. Test it:\n`bash scripts/selftest.sh`.\n"
    },
    {
      "path": "skills/plan-review/scripts/plan-summary.sh",
      "role": "reference",
      "description": "Counts plan actions and fails on deletes or replaces.",
      "skill": "plan-review",
      "agent": null,
      "install_to": {
        "claude-code": ".claude/skills/plan-review/scripts/plan-summary.sh",
        "codex": ".agents/skills/plan-review/scripts/plan-summary.sh",
        "cursor": ".agents/skills/plan-review/scripts/plan-summary.sh",
        "gemini-cli": ".agents/skills/plan-review/scripts/plan-summary.sh",
        "antigravity-cli": ".agents/skills/plan-review/scripts/plan-summary.sh",
        "copilot": ".agents/skills/plan-review/scripts/plan-summary.sh"
      },
      "raw_url": "https://loadout.jnw-it.com/raw/terraform-plan-only/1.0.0/skills/plan-review/scripts/plan-summary.sh",
      "raw_latest_url": "https://loadout.jnw-it.com/raw/terraform-plan-only/latest/skills/plan-review/scripts/plan-summary.sh",
      "bytes": 1113,
      "lang": "markdown",
      "content": "#!/usr/bin/env bash\n# Summarise `terraform show -json tfplan` output. Exit 1 if anything is deleted or replaced. Needs jq.\nset -euo pipefail\nplan=\"${1:?usage: plan-summary.sh plan.json}\"\njq -r '\n  def kind: if . == [\"create\"] then \"create\"\n    elif . == [\"update\"] then \"update\"\n    elif . == [\"delete\"] then \"delete\"\n    elif (. == [\"delete\",\"create\"] or . == [\"create\",\"delete\"]) then \"replace\"\n    else \"no-op\" end;\n  [.resource_changes[]? | {address, kind: (.change.actions | kind)}] as $c\n  | \"create: \\([$c[] | select(.kind == \"create\")] | length)\",\n    \"update: \\([$c[] | select(.kind == \"update\")] | length)\",\n    \"replace: \\([$c[] | select(.kind == \"replace\")] | length)\",\n    \"delete: \\([$c[] | select(.kind == \"delete\")] | length)\",\n    ($c[] | select(.kind == \"replace\" or .kind == \"delete\") | \"\\(.kind | ascii_upcase): \\(.address)\")\n' \"$plan\"\nif jq -e '[.resource_changes[]? | .change.actions | select(index(\"delete\"))] | length > 0' \"$plan\" >/dev/null; then\n  echo \"plan destroys or replaces resources: review each one above before anyone applies\"\n  exit 1\nfi\necho \"plan has no deletes or replaces\"\n"
    },
    {
      "path": "skills/plan-review/scripts/guard-terraform.sh",
      "role": "reference",
      "description": "PreToolUse hook that denies apply, destroy and state changes.",
      "skill": "plan-review",
      "agent": null,
      "install_to": {
        "claude-code": ".claude/skills/plan-review/scripts/guard-terraform.sh",
        "codex": ".agents/skills/plan-review/scripts/guard-terraform.sh",
        "cursor": ".agents/skills/plan-review/scripts/guard-terraform.sh",
        "gemini-cli": ".agents/skills/plan-review/scripts/guard-terraform.sh",
        "antigravity-cli": ".agents/skills/plan-review/scripts/guard-terraform.sh",
        "copilot": ".agents/skills/plan-review/scripts/guard-terraform.sh"
      },
      "raw_url": "https://loadout.jnw-it.com/raw/terraform-plan-only/1.0.0/skills/plan-review/scripts/guard-terraform.sh",
      "raw_latest_url": "https://loadout.jnw-it.com/raw/terraform-plan-only/latest/skills/plan-review/scripts/guard-terraform.sh",
      "bytes": 1550,
      "lang": "markdown",
      "content": "#!/usr/bin/env bash\n# PreToolUse hook for Bash (Claude Code). Denies Terraform / OpenTofu commands that change real infrastructure or state.\n# Reads the tool call as JSON on stdin; prints a deny decision with a reason, or nothing. Needs jq.\nset -u\ncmd=$(jq -r '.tool_input.command // empty')\n[ -z \"$cmd\" ] && exit 0\nflat=$(printf '%s' \"$cmd\" | tr '\\n\\t' '  ' | tr '[:upper:]' '[:lower:]')\n\ndeny() {\n  jq -n --arg r \"Blocked by guard-terraform: $1\" \\\n    '{hookSpecificOutput: {hookEventName: \"PreToolUse\", permissionDecision: \"deny\", permissionDecisionReason: $r}}'\n  exit 0\n}\n\ntf='(^|[[:space:];&|(/])(terraform|tofu|terragrunt)[[:space:]]+([^;&|]*[[:space:]])?'\n[[ \"$flat\" =~ -auto-approve ]] && deny \"-auto-approve skips the human review. Produce a plan and hand it over.\"\n[[ \"$flat\" =~ ${tf}(apply|destroy)([[:space:]]|$) ]] && deny \"apply and destroy change real infrastructure. Show the plan; the human runs it.\"\n[[ \"$flat\" =~ ${tf}(import|taint|untaint|force-unlock)([[:space:]]|$) ]] && deny \"this changes state. Ask the human.\"\n[[ \"$flat\" =~ ${tf}state[[:space:]]+(rm|mv|push|replace-provider)([[:space:]]|$) ]] && deny \"state changes can orphan or destroy resources. Ask the human.\"\n[[ \"$flat\" =~ ${tf}workspace[[:space:]]+delete([[:space:]]|$) ]] && deny \"deleting a workspace loses its state. Ask the human.\"\n[[ \"$flat\" =~ \\.tfstate([[:space:]]|$|\\.backup) && \"$flat\" =~ (^|[[:space:]])(cat|less|more|head|tail|cp|mv|rm|vi|vim|nano|sed)[[:space:]] ]] && deny \"state files hold secrets. Use terraform show or terraform state list.\"\nexit 0\n"
    },
    {
      "path": "skills/plan-review/scripts/selftest.sh",
      "role": "reference",
      "description": "20 sample commands through the guard hook.",
      "skill": "plan-review",
      "agent": null,
      "install_to": {
        "claude-code": ".claude/skills/plan-review/scripts/selftest.sh",
        "codex": ".agents/skills/plan-review/scripts/selftest.sh",
        "cursor": ".agents/skills/plan-review/scripts/selftest.sh",
        "gemini-cli": ".agents/skills/plan-review/scripts/selftest.sh",
        "antigravity-cli": ".agents/skills/plan-review/scripts/selftest.sh",
        "copilot": ".agents/skills/plan-review/scripts/selftest.sh"
      },
      "raw_url": "https://loadout.jnw-it.com/raw/terraform-plan-only/1.0.0/skills/plan-review/scripts/selftest.sh",
      "raw_latest_url": "https://loadout.jnw-it.com/raw/terraform-plan-only/latest/skills/plan-review/scripts/selftest.sh",
      "bytes": 1563,
      "lang": "markdown",
      "content": "#!/usr/bin/env bash\n# Feeds sample Bash tool calls to guard-terraform.sh and checks each decision.\nset -u\nhere=\"$(cd \"$(dirname \"$0\")\" && pwd)\"\npass=0; failed=0\ncheck() { # want(deny|allow) command\n  local want=\"$1\" cmd=\"$2\" out got\n  out=$(jq -n --arg c \"$cmd\" '{tool_name: \"Bash\", tool_input: {command: $c}}' | bash \"$here/guard-terraform.sh\")\n  if printf '%s' \"$out\" | grep -q '\"permissionDecision\": \"deny\"'; then got=deny; else got=allow; fi\n  if [ \"$got\" = \"$want\" ]; then pass=$((pass + 1)); else failed=$((failed + 1)); echo \"FAIL: wanted $want, got $got: $cmd\"; fi\n}\ncheck deny  \"terraform apply\"\ncheck deny  \"terraform apply tfplan\"\ncheck deny  \"cd infra && terraform destroy -target=aws_s3_bucket.logs\"\ncheck deny  \"tofu apply\"\ncheck deny  \"terraform plan -out=tfplan && terraform apply -auto-approve tfplan\"\ncheck deny  \"terraform -chdir=envs/dev apply\"\ncheck deny  \"terraform import aws_s3_bucket.b my-bucket\"\ncheck deny  \"terraform state rm aws_instance.web\"\ncheck deny  \"terraform force-unlock 1234\"\ncheck deny  \"terraform workspace delete staging\"\ncheck deny  \"cat terraform.tfstate\"\ncheck deny  \"TERRAFORM APPLY\"\ncheck allow \"terraform fmt -recursive\"\ncheck allow \"terraform validate\"\ncheck allow \"terraform init -backend=false\"\ncheck allow \"terraform plan -out=tfplan\"\ncheck allow \"terraform show -json tfplan > plan.json\"\ncheck allow \"terraform state list\"\ncheck allow \"grep -r apply docs/\"\ncheck allow \"terraform workspace list\"\nif [ \"$failed\" -eq 0 ]; then echo \"ok: $pass cases\"; else echo \"failed: $failed of $((pass + failed))\"; exit 1; fi\n"
    },
    {
      "path": "skills/plan-review/references/settings.example.json",
      "role": "reference",
      "description": "Claude Code settings: deny rules and the hook.",
      "skill": "plan-review",
      "agent": null,
      "install_to": {
        "claude-code": ".claude/skills/plan-review/references/settings.example.json",
        "codex": ".agents/skills/plan-review/references/settings.example.json",
        "cursor": ".agents/skills/plan-review/references/settings.example.json",
        "gemini-cli": ".agents/skills/plan-review/references/settings.example.json",
        "antigravity-cli": ".agents/skills/plan-review/references/settings.example.json",
        "copilot": ".agents/skills/plan-review/references/settings.example.json"
      },
      "raw_url": "https://loadout.jnw-it.com/raw/terraform-plan-only/1.0.0/skills/plan-review/references/settings.example.json",
      "raw_latest_url": "https://loadout.jnw-it.com/raw/terraform-plan-only/latest/skills/plan-review/references/settings.example.json",
      "bytes": 613,
      "lang": "json",
      "content": "{\n  \"permissions\": {\n    \"deny\": [\n      \"Bash(terraform apply *)\",\n      \"Bash(terraform destroy *)\",\n      \"Bash(tofu apply *)\",\n      \"Bash(tofu destroy *)\",\n      \"Read(./**/*.tfstate)\",\n      \"Read(./**/*.tfstate.backup)\"\n    ]\n  },\n  \"hooks\": {\n    \"PreToolUse\": [\n      {\n        \"matcher\": \"Bash\",\n        \"hooks\": [\n          {\n            \"type\": \"command\",\n            \"command\": \"bash\",\n            \"args\": [\"${CLAUDE_PROJECT_DIR}/.claude/hooks/guard-terraform.sh\"],\n            \"onFailure\": \"block\",\n            \"statusMessage\": \"Checking Terraform command\"\n          }\n        ]\n      }\n    ]\n  }\n}\n"
    },
    {
      "path": "mcp.json",
      "role": "mcp",
      "description": "HashiCorp Terraform MCP server in Docker, pinned.",
      "skill": null,
      "agent": null,
      "install_to": {
        "claude-code": ".mcp.json",
        "codex": null,
        "cursor": ".cursor/mcp.json",
        "gemini-cli": null,
        "antigravity-cli": ".agents/mcp_config.json",
        "copilot": null
      },
      "raw_url": "https://loadout.jnw-it.com/raw/terraform-plan-only/1.0.0/mcp.json",
      "raw_latest_url": "https://loadout.jnw-it.com/raw/terraform-plan-only/latest/mcp.json",
      "bytes": 154,
      "lang": "json",
      "content": "{\n  \"mcpServers\": {\n    \"terraform\": {\n      \"command\": \"docker\",\n      \"args\": [\"run\", \"-i\", \"--rm\", \"hashicorp/terraform-mcp-server:1.3.0\"]\n    }\n  }\n}\n"
    }
  ],
  "requires": {
    "tools": [
      "terraform",
      "jq",
      "docker"
    ],
    "env": [],
    "mcp": [
      "terraform"
    ]
  },
  "tested": {
    "status": "untested",
    "last_run": null,
    "fixture": null,
    "per_agent": {
      "claude-code": "untested",
      "codex": "untested",
      "cursor": "untested",
      "gemini-cli": "untested",
      "antigravity-cli": "untested",
      "copilot": "untested"
    }
  },
  "security": {
    "scanned": true,
    "scanner": "intake-precheck/1",
    "verdict": "clean",
    "network": true,
    "scripts": [
      "plan-summary.sh",
      "guard-terraform.sh",
      "selftest.sh"
    ],
    "notes": "The Terraform MCP server runs locally in Docker from HashiCorp's pinned image and reads the public Terraform Registry; no token is configured, so it has no HCP Terraform access. The scripts make no network calls."
  },
  "featured": false,
  "deprecated": false,
  "last_checked": "2026-10-17",
  "published": "2026-10-17",
  "updated": "2026-10-17",
  "compatibility": {
    "claude-code": "native",
    "codex": "adapter",
    "cursor": "native",
    "gemini-cli": "adapter",
    "antigravity-cli": "native",
    "copilot": "adapter"
  },
  "counts": {
    "rules": 1,
    "skills": 1,
    "mcp": 1
  },
  "url": "https://loadout.jnw-it.com/loadouts/terraform-plan-only/",
  "api_url": "https://loadout.jnw-it.com/api/loadouts/terraform-plan-only.json",
  "verification": {
    "level": "verified-install",
    "status": "verified",
    "label": "Verified install",
    "verified": true,
    "checked_at": "2026-10-17T08:09:30Z",
    "commit": "03c1b9839c40eb1e44c0a2877baaa3978a96895c",
    "content_current": true,
    "agent_tests": "not-run",
    "counts": {
      "pass": 10,
      "fail": 0,
      "skip": 0,
      "not_applicable": 0
    },
    "meaning": "Level 1: automated checks on the files (parse, install paths, MCP config, safety scan, references, size, licence, starter build). No AI agent was run.",
    "checks": [
      {
        "id": "listing",
        "name": "Listing",
        "status": "pass",
        "summary": "Schema valid; 9 files declared, none missing or extra",
        "details": [
          "tested.status: untested (agent tests are separate from Level 1)"
        ]
      },
      {
        "id": "parse",
        "name": "Files parse",
        "status": "pass",
        "summary": "All 9 files parse; front matter valid",
        "details": []
      },
      {
        "id": "adapters",
        "name": "Adapters",
        "status": "pass",
        "summary": "CLAUDE.md and GEMINI.md import AGENTS.md and are up to date",
        "details": [
          "CLAUDE.md: matches the generator",
          "GEMINI.md: matches the generator"
        ]
      },
      {
        "id": "install-paths",
        "name": "Install paths",
        "status": "pass",
        "summary": "Correct paths for all 6 agents; layouts re-discovered",
        "details": [
          "Claude Code: 8 files, 1 skill in .claude/skills/, MCP at .mcp.json",
          "Codex CLI: 6 files, 1 skill in .agents/skills/, MCP manual step",
          "Cursor: 7 files, 1 skill in .agents/skills/, MCP at .cursor/mcp.json",
          "Gemini CLI: 7 files, 1 skill in .agents/skills/, MCP manual step",
          "Antigravity CLI: 7 files, 1 skill in .agents/skills/, MCP at .agents/mcp_config.json",
          "GitHub Copilot: 6 files, 1 skill in .agents/skills/, MCP manual step"
        ]
      },
      {
        "id": "mcp",
        "name": "MCP config",
        "status": "pass",
        "summary": "1 server valid: terraform",
        "details": [
          "mcp.json → terraform: local command `docker`, no registry package to look up",
          "Converts to Codex config.toml, Gemini CLI settings.json, VS Code mcp.json and Antigravity CLI .agents/mcp_config.json (serverUrl)"
        ]
      },
      {
        "id": "safety",
        "name": "Safety scan",
        "status": "pass",
        "summary": "Clean: no credentials, risky shell or hidden text",
        "details": [
          "Scanner intake-precheck/1: verdict clean; network yes (listing says yes)",
          "info mcp-server in mcp.json: terraform: command docker run -i --rm hashicorp/terraform-mcp-server:1.3.0"
        ]
      },
      {
        "id": "references",
        "name": "References",
        "status": "pass",
        "summary": "3 references between files resolve for every agent",
        "details": []
      },
      {
        "id": "size",
        "name": "Size limits",
        "status": "pass",
        "summary": "9 files, 9.2 KB total; largest AGENTS.md 2.1 KB",
        "details": [
          "Limits: 30 files, 32 KB per file, 128 KB total, 500 lines per skill or rule"
        ]
      },
      {
        "id": "licence",
        "name": "Licence",
        "status": "pass",
        "summary": "MIT, by Agent Loadout; text in the repository LICENSE",
        "details": []
      },
      {
        "id": "starter-build",
        "name": "Starter build",
        "status": "pass",
        "summary": "plan-summary.sh counts creates, updates, replaces and deletes from terraform show -json output and fails on destructive plans; the guard hook blocks apply, destroy, state changes and -auto-approve in 20 sample commands",
        "details": [
          "Applied 16 loadout files at every agent's paths",
          "✓ bash -n on the scripts: bash -c for f in .claude/skills/plan-review/scripts/*.sh; do bash -n \"$f\" || exit 1; done; echo syntax ok",
          "✓ settings snippet is valid JSON: jq empty .claude/skills/plan-review/references/settings.example.json",
          "✓ safe plan passes: bash .agents/skills/plan-review/scripts/plan-summary.sh plan-safe.json",
          "✓ destructive plan is flagged: bash -c bash .agents/skills/plan-review/scripts/plan-summary.sh plan-destructive.json; test $? -eq 1 && echo flagged",
          "✓ guard hook self-test (Claude Code layout): bash .claude/skills/plan-review/scripts/selftest.sh",
          "✓ guard hook self-test (.agents layout): bash .agents/skills/plan-review/scripts/selftest.sh",
          "Covers: Replace is detected for both delete-then-create and create-then-delete",
          "Covers: Reads, no-ops, creates and updates do not fail the summary",
          "Covers: apply, destroy, import, state rm, force-unlock, workspace delete, -auto-approve and reading .tfstate are denied with a reason, for terraform and tofu",
          "Covers: fmt, validate, init -backend=false, plan, show and state list are allowed"
        ]
      }
    ]
  },
  "install": {
    "claude-code": {
      "files": [
        {
          "path": "AGENTS.md",
          "target": "AGENTS.md",
          "raw_url": "https://loadout.jnw-it.com/raw/terraform-plan-only/1.0.0/AGENTS.md",
          "role": "instructions"
        },
        {
          "path": "CLAUDE.md",
          "target": "CLAUDE.md",
          "raw_url": "https://loadout.jnw-it.com/raw/terraform-plan-only/1.0.0/CLAUDE.md",
          "role": "adapter"
        },
        {
          "path": "skills/plan-review/SKILL.md",
          "target": ".claude/skills/plan-review/SKILL.md",
          "raw_url": "https://loadout.jnw-it.com/raw/terraform-plan-only/1.0.0/skills/plan-review/SKILL.md",
          "role": "skill"
        },
        {
          "path": "skills/plan-review/scripts/plan-summary.sh",
          "target": ".claude/skills/plan-review/scripts/plan-summary.sh",
          "raw_url": "https://loadout.jnw-it.com/raw/terraform-plan-only/1.0.0/skills/plan-review/scripts/plan-summary.sh",
          "role": "reference"
        },
        {
          "path": "skills/plan-review/scripts/guard-terraform.sh",
          "target": ".claude/skills/plan-review/scripts/guard-terraform.sh",
          "raw_url": "https://loadout.jnw-it.com/raw/terraform-plan-only/1.0.0/skills/plan-review/scripts/guard-terraform.sh",
          "role": "reference"
        },
        {
          "path": "skills/plan-review/scripts/selftest.sh",
          "target": ".claude/skills/plan-review/scripts/selftest.sh",
          "raw_url": "https://loadout.jnw-it.com/raw/terraform-plan-only/1.0.0/skills/plan-review/scripts/selftest.sh",
          "role": "reference"
        },
        {
          "path": "skills/plan-review/references/settings.example.json",
          "target": ".claude/skills/plan-review/references/settings.example.json",
          "raw_url": "https://loadout.jnw-it.com/raw/terraform-plan-only/1.0.0/skills/plan-review/references/settings.example.json",
          "role": "reference"
        },
        {
          "path": "mcp.json",
          "target": ".mcp.json",
          "raw_url": "https://loadout.jnw-it.com/raw/terraform-plan-only/1.0.0/mcp.json",
          "role": "mcp"
        }
      ],
      "manual_steps": [],
      "zip_url": "https://loadout.jnw-it.com/download/terraform-plan-only/claude-code.zip"
    },
    "codex": {
      "files": [
        {
          "path": "AGENTS.md",
          "target": "AGENTS.md",
          "raw_url": "https://loadout.jnw-it.com/raw/terraform-plan-only/1.0.0/AGENTS.md",
          "role": "instructions"
        },
        {
          "path": "skills/plan-review/SKILL.md",
          "target": ".agents/skills/plan-review/SKILL.md",
          "raw_url": "https://loadout.jnw-it.com/raw/terraform-plan-only/1.0.0/skills/plan-review/SKILL.md",
          "role": "skill"
        },
        {
          "path": "skills/plan-review/scripts/plan-summary.sh",
          "target": ".agents/skills/plan-review/scripts/plan-summary.sh",
          "raw_url": "https://loadout.jnw-it.com/raw/terraform-plan-only/1.0.0/skills/plan-review/scripts/plan-summary.sh",
          "role": "reference"
        },
        {
          "path": "skills/plan-review/scripts/guard-terraform.sh",
          "target": ".agents/skills/plan-review/scripts/guard-terraform.sh",
          "raw_url": "https://loadout.jnw-it.com/raw/terraform-plan-only/1.0.0/skills/plan-review/scripts/guard-terraform.sh",
          "role": "reference"
        },
        {
          "path": "skills/plan-review/scripts/selftest.sh",
          "target": ".agents/skills/plan-review/scripts/selftest.sh",
          "raw_url": "https://loadout.jnw-it.com/raw/terraform-plan-only/1.0.0/skills/plan-review/scripts/selftest.sh",
          "role": "reference"
        },
        {
          "path": "skills/plan-review/references/settings.example.json",
          "target": ".agents/skills/plan-review/references/settings.example.json",
          "raw_url": "https://loadout.jnw-it.com/raw/terraform-plan-only/1.0.0/skills/plan-review/references/settings.example.json",
          "role": "reference"
        }
      ],
      "manual_steps": [
        {
          "path": "mcp.json",
          "note": "Codex reads MCP servers from ~/.codex/config.toml (TOML, not JSON). Add each server with `codex mcp add` or copy the URL into an [mcp_servers.<name>] table.",
          "raw_url": "https://loadout.jnw-it.com/raw/terraform-plan-only/1.0.0/mcp.json"
        }
      ],
      "zip_url": "https://loadout.jnw-it.com/download/terraform-plan-only/codex.zip"
    },
    "cursor": {
      "files": [
        {
          "path": "AGENTS.md",
          "target": "AGENTS.md",
          "raw_url": "https://loadout.jnw-it.com/raw/terraform-plan-only/1.0.0/AGENTS.md",
          "role": "instructions"
        },
        {
          "path": "skills/plan-review/SKILL.md",
          "target": ".agents/skills/plan-review/SKILL.md",
          "raw_url": "https://loadout.jnw-it.com/raw/terraform-plan-only/1.0.0/skills/plan-review/SKILL.md",
          "role": "skill"
        },
        {
          "path": "skills/plan-review/scripts/plan-summary.sh",
          "target": ".agents/skills/plan-review/scripts/plan-summary.sh",
          "raw_url": "https://loadout.jnw-it.com/raw/terraform-plan-only/1.0.0/skills/plan-review/scripts/plan-summary.sh",
          "role": "reference"
        },
        {
          "path": "skills/plan-review/scripts/guard-terraform.sh",
          "target": ".agents/skills/plan-review/scripts/guard-terraform.sh",
          "raw_url": "https://loadout.jnw-it.com/raw/terraform-plan-only/1.0.0/skills/plan-review/scripts/guard-terraform.sh",
          "role": "reference"
        },
        {
          "path": "skills/plan-review/scripts/selftest.sh",
          "target": ".agents/skills/plan-review/scripts/selftest.sh",
          "raw_url": "https://loadout.jnw-it.com/raw/terraform-plan-only/1.0.0/skills/plan-review/scripts/selftest.sh",
          "role": "reference"
        },
        {
          "path": "skills/plan-review/references/settings.example.json",
          "target": ".agents/skills/plan-review/references/settings.example.json",
          "raw_url": "https://loadout.jnw-it.com/raw/terraform-plan-only/1.0.0/skills/plan-review/references/settings.example.json",
          "role": "reference"
        },
        {
          "path": "mcp.json",
          "target": ".cursor/mcp.json",
          "raw_url": "https://loadout.jnw-it.com/raw/terraform-plan-only/1.0.0/mcp.json",
          "role": "mcp"
        }
      ],
      "manual_steps": [],
      "zip_url": "https://loadout.jnw-it.com/download/terraform-plan-only/cursor.zip"
    },
    "gemini-cli": {
      "files": [
        {
          "path": "AGENTS.md",
          "target": "AGENTS.md",
          "raw_url": "https://loadout.jnw-it.com/raw/terraform-plan-only/1.0.0/AGENTS.md",
          "role": "instructions"
        },
        {
          "path": "GEMINI.md",
          "target": "GEMINI.md",
          "raw_url": "https://loadout.jnw-it.com/raw/terraform-plan-only/1.0.0/GEMINI.md",
          "role": "adapter"
        },
        {
          "path": "skills/plan-review/SKILL.md",
          "target": ".agents/skills/plan-review/SKILL.md",
          "raw_url": "https://loadout.jnw-it.com/raw/terraform-plan-only/1.0.0/skills/plan-review/SKILL.md",
          "role": "skill"
        },
        {
          "path": "skills/plan-review/scripts/plan-summary.sh",
          "target": ".agents/skills/plan-review/scripts/plan-summary.sh",
          "raw_url": "https://loadout.jnw-it.com/raw/terraform-plan-only/1.0.0/skills/plan-review/scripts/plan-summary.sh",
          "role": "reference"
        },
        {
          "path": "skills/plan-review/scripts/guard-terraform.sh",
          "target": ".agents/skills/plan-review/scripts/guard-terraform.sh",
          "raw_url": "https://loadout.jnw-it.com/raw/terraform-plan-only/1.0.0/skills/plan-review/scripts/guard-terraform.sh",
          "role": "reference"
        },
        {
          "path": "skills/plan-review/scripts/selftest.sh",
          "target": ".agents/skills/plan-review/scripts/selftest.sh",
          "raw_url": "https://loadout.jnw-it.com/raw/terraform-plan-only/1.0.0/skills/plan-review/scripts/selftest.sh",
          "role": "reference"
        },
        {
          "path": "skills/plan-review/references/settings.example.json",
          "target": ".agents/skills/plan-review/references/settings.example.json",
          "raw_url": "https://loadout.jnw-it.com/raw/terraform-plan-only/1.0.0/skills/plan-review/references/settings.example.json",
          "role": "reference"
        }
      ],
      "manual_steps": [
        {
          "path": "mcp.json",
          "note": "Gemini CLI reads MCP servers from the mcpServers block of .gemini/settings.json. Merge the servers in by hand, and use httpUrl instead of url for HTTP servers. Since 18 June 2026 Gemini CLI serves only Gemini Code Assist Standard/Enterprise licences and paid API keys; personal accounts use Antigravity CLI.",
          "raw_url": "https://loadout.jnw-it.com/raw/terraform-plan-only/1.0.0/mcp.json"
        }
      ],
      "zip_url": "https://loadout.jnw-it.com/download/terraform-plan-only/gemini-cli.zip"
    },
    "antigravity-cli": {
      "files": [
        {
          "path": "AGENTS.md",
          "target": "AGENTS.md",
          "raw_url": "https://loadout.jnw-it.com/raw/terraform-plan-only/1.0.0/AGENTS.md",
          "role": "instructions"
        },
        {
          "path": "skills/plan-review/SKILL.md",
          "target": ".agents/skills/plan-review/SKILL.md",
          "raw_url": "https://loadout.jnw-it.com/raw/terraform-plan-only/1.0.0/skills/plan-review/SKILL.md",
          "role": "skill"
        },
        {
          "path": "skills/plan-review/scripts/plan-summary.sh",
          "target": ".agents/skills/plan-review/scripts/plan-summary.sh",
          "raw_url": "https://loadout.jnw-it.com/raw/terraform-plan-only/1.0.0/skills/plan-review/scripts/plan-summary.sh",
          "role": "reference"
        },
        {
          "path": "skills/plan-review/scripts/guard-terraform.sh",
          "target": ".agents/skills/plan-review/scripts/guard-terraform.sh",
          "raw_url": "https://loadout.jnw-it.com/raw/terraform-plan-only/1.0.0/skills/plan-review/scripts/guard-terraform.sh",
          "role": "reference"
        },
        {
          "path": "skills/plan-review/scripts/selftest.sh",
          "target": ".agents/skills/plan-review/scripts/selftest.sh",
          "raw_url": "https://loadout.jnw-it.com/raw/terraform-plan-only/1.0.0/skills/plan-review/scripts/selftest.sh",
          "role": "reference"
        },
        {
          "path": "skills/plan-review/references/settings.example.json",
          "target": ".agents/skills/plan-review/references/settings.example.json",
          "raw_url": "https://loadout.jnw-it.com/raw/terraform-plan-only/1.0.0/skills/plan-review/references/settings.example.json",
          "role": "reference"
        },
        {
          "path": "mcp.json",
          "target": ".agents/mcp_config.json",
          "raw_url": "https://loadout.jnw-it.com/raw/terraform-plan-only/1.0.0/generated/antigravity-cli/mcp_config.json",
          "role": "mcp",
          "generated": true
        }
      ],
      "manual_steps": [],
      "zip_url": "https://loadout.jnw-it.com/download/terraform-plan-only/antigravity-cli.zip"
    },
    "copilot": {
      "files": [
        {
          "path": "AGENTS.md",
          "target": "AGENTS.md",
          "raw_url": "https://loadout.jnw-it.com/raw/terraform-plan-only/1.0.0/AGENTS.md",
          "role": "instructions"
        },
        {
          "path": "skills/plan-review/SKILL.md",
          "target": ".agents/skills/plan-review/SKILL.md",
          "raw_url": "https://loadout.jnw-it.com/raw/terraform-plan-only/1.0.0/skills/plan-review/SKILL.md",
          "role": "skill"
        },
        {
          "path": "skills/plan-review/scripts/plan-summary.sh",
          "target": ".agents/skills/plan-review/scripts/plan-summary.sh",
          "raw_url": "https://loadout.jnw-it.com/raw/terraform-plan-only/1.0.0/skills/plan-review/scripts/plan-summary.sh",
          "role": "reference"
        },
        {
          "path": "skills/plan-review/scripts/guard-terraform.sh",
          "target": ".agents/skills/plan-review/scripts/guard-terraform.sh",
          "raw_url": "https://loadout.jnw-it.com/raw/terraform-plan-only/1.0.0/skills/plan-review/scripts/guard-terraform.sh",
          "role": "reference"
        },
        {
          "path": "skills/plan-review/scripts/selftest.sh",
          "target": ".agents/skills/plan-review/scripts/selftest.sh",
          "raw_url": "https://loadout.jnw-it.com/raw/terraform-plan-only/1.0.0/skills/plan-review/scripts/selftest.sh",
          "role": "reference"
        },
        {
          "path": "skills/plan-review/references/settings.example.json",
          "target": ".agents/skills/plan-review/references/settings.example.json",
          "raw_url": "https://loadout.jnw-it.com/raw/terraform-plan-only/1.0.0/skills/plan-review/references/settings.example.json",
          "role": "reference"
        }
      ],
      "manual_steps": [
        {
          "path": "mcp.json",
          "note": "In VS Code, MCP servers go in .vscode/mcp.json under a \"servers\" key (not \"mcpServers\"). Copilot CLI uses ~/.copilot/mcp-config.json.",
          "raw_url": "https://loadout.jnw-it.com/raw/terraform-plan-only/1.0.0/mcp.json"
        }
      ],
      "zip_url": "https://loadout.jnw-it.com/download/terraform-plan-only/copilot.zip"
    }
  },
  "source_zip_url": "https://loadout.jnw-it.com/download/terraform-plan-only/source.zip"
}