{
  "markdown": "# tfstackplan\n\n> Your monorepo just opened **8 Terraform plans** on this one PR.\n> Your reviewer has gone very quiet.\n\n<p align=\"center\">\n  <img src=\"docs/images/hero-reviewer.jpg\" alt=\"An engineer at dusk, cold coffee in hand, a '127 files changed' sign glowing in the window\" width=\"760\">\n  <br><sub><i>He's reviewing the networking stack.</i></sub>\n</p>\n\n`tfstackplan` turns the N `plan.json` files a monorepo spits out per PR into a\nsingle comment a human can actually read — then, if you're brave, gates the\napply behind a button someone has to consciously press.\n\nTerramate makes a Terraform monorepo *runnable*. `tfstackplan` makes it\n**reviewable, governable, and safe** inside GitHub's PR workflow. It closes the\nfour gaps a raw `terramate run` in CI leaves wide open — and it has **four\nfaces**, one per gap:\n\n| Face | The gap it closes | In one line |\n| --- | --- | --- |\n| [**`render`**](docs/guide/04-render.md) | **Review** | N unreadable `plan.json` → one scannable PR comment |\n| [**`serve`**](docs/guide/07-serve.md) | **Governance** | no approval story → live gates + privilege-backed apply |\n| [**`run`**](docs/guide/06-run.md) | **Observability** | CI logs are a black hole → live DAG UI, per-stack logs, check runs |\n| [**`state`**](docs/guide/08-state.md) | **Management** | cross-stack refactors are scary → declarative state moves |\n\n> Terramate runs your stacks. GitHub shrugs and posts the logs. `terraform\n> apply` does exactly what you told it to, which is the problem. `tfstackplan`\n> is the adult in the room.\n\n`render` is **fully standalone** — point it at a directory of plans and you get\na comment. You never have to touch `run` / `serve` / `state`. The other three\nlayer a control plane on top, while Terraform keeps executing in *your* CI under\n*your* identities.\n\nNew here? Start with **[the guide](docs/index.md)** — it reads in order, from\n*why this exists* to *every flag there is*.\n\n---\n\n## What it looks like\n\nA run over eight stacks with classification on, rendered the way GitHub shows it\nin a PR comment: a scannable summary table, then a per-stack drill-down. Each\nresource is its own row inside an indented blockquote bar, so it's always clear\nwhich stack and resource you're reading. Small changes show expanded; big ones\ncollapse to a row you click to open.\n\n<!-- tfstackplan:nonprod -->\n\n### Terraform plan — nonprod  (8 stacks changed)\n\n| Stack | Add | Change | Destroy | Replace | Categories |\n| --- | ---: | ---: | ---: | ---: | --- |\n| platform/nonprod | 0 | 4 | 0 | 0 | 🔐 iam |\n| service-projects/app-dev | 4 | 3 | 0 | 0 | ✅ safe |\n| data/warehouse | 0 | 0 | 6 | 0 | 💣 destructive |\n| networking/shared-vpc | 0 | 5 | 0 | 2 | 💣 destructive |\n| observability/grafana | 5 | 6 | 0 | 0 | ✅ safe |\n\n<details open><summary>📁&nbsp;<b>platform/nonprod</b> · 🔐 iam · 4 change</summary>\n\n>\n> <details open><summary>✏️&nbsp;google_project_iam_member.data_engineers<br>&nbsp;&nbsp;&nbsp;&nbsp;1 changed</summary>\n>\n> ```diff\n> ~ role = \"roles/viewer\" → \"roles/editor\"\n> ```\n>\n> </details>\n\n</details>\n\n<details open><summary>📁&nbsp;<b>data/warehouse</b> · 💣 destructive · 6 destroy</summary>\n\n>\n> <details open><summary>➖&nbsp;google_bigquery_dataset.legacy_events<br>&nbsp;&nbsp;&nbsp;&nbsp;2 attrs</summary>\n>\n> ```diff\n> - location = \"us-central1\"\n> - name     = \"legacy_events\"\n> ```\n>\n> </details>\n\n</details>\n\nThat whole block is **live Markdown, not a screenshot** — it renders natively on\nGitHub and you can paste it anywhere. The first line of the real output is an\ninvisible HTML-comment marker (`<!-- tfstackplan:nonprod -->`) that CI uses to\nupsert one comment per environment. The full anatomy — folding rules, aligned\ndiffs, structured-value rendering, state-op rows — lives in\n**[the render chapter](docs/guide/04-render.md)**.\n\nMore worked outputs (big plans, the byte budget kicking in, state ops) are in\n**[`examples/`](examples/)**.\n\n---\n\n## 60-second quickstart\n\n`render` is offline and standalone — no `terraform`, no posting, no config\nrequired. Give it a directory of plans laid out to mirror your stack tree.\n\n```bash\n# 1. install\ngo install github.com/Fluent-Health/terraform-stack-plan/cmd/tfstackplan@latest\n\n# 2. for each stack, capture a plan as JSON next to where it lives\nterraform plan -out plan.bin && terraform show -json plan.bin > out/<stack>/tfplan.json\n\n# 3. render every stack under out/ into one comment\ntfstackplan render --plans-dir out/ \\\n  --title  \"Terraform plan — nonprod\" \\\n  --marker tfstackplan:nonprod \\\n  --output report.md\n```\n\n`report.md` is the comment you saw above. With no config, classification is off\nand the tool degrades gracefully — add a `.tfstackplan.hcl` when you want\ncategories, links, and budgets. Then have your CI post `report.md`; `render`\nwrites Markdown, your CI does the posting.\n\nThe full path from here — classification, then the control plane — is laid out\nin **[the guide](docs/index.md)**.\n\n---\n\n## The four faces\n\n**[`render`](docs/guide/04-render.md) — the review gap.** A pure, offline\nrenderer: many `plan.json` files in, one reviewer-friendly Markdown comment out,\nwith optional classification. It never runs `terraform` and never posts. Use it\nentirely on its own.\n\n**[`run`](docs/guide/06-run.md) — the observability gap.** The CI driver. It\nwraps your `terramate script run`, detects the changed stacks, runs\nplan/apply/verify, renders + classifies in-process, and reports the execution\nlifecycle to the control plane — so a CI run stops being a wall of interleaved\nlogs.\n\n**[`serve`](docs/guide/07-serve.md) — the governance gap.** The control plane: a\nlive dependency-DAG UI, approval gates, one GitHub check run per environment,\nand SSE-tailed per-stack logs.\n\n> `terraform apply` across 8 stacks, straight from CI, with no one watching, is\n> a perfectly reasonable thing to do. `serve` is for the other 100% of cases.\n\n**[`state`](docs/guide/08-state.md) — the management gap.** Declarative\ncross-stack Terraform state moves, applied as part of the normal apply — so\nrefactoring resources between stacks stops being a hand-run, fingers-crossed\noperation.\n\n---\n\n## Where do I go now?\n\nThe docs read as a sequence — **[start at the index](docs/index.md)** — but if\nyou know what you want:\n\n- **Why does this exist?** → [The gaps](docs/guide/01-the-gaps.md) ·\n  [Mental model](docs/guide/02-mental-model.md)\n- **I just want a comment.** → [Quickstart](docs/guide/03-quickstart.md) ·\n  [`render`](docs/guide/04-render.md) ·\n  [Classification](docs/guide/05-classification.md)\n- **I want a control plane.** → [`run`](docs/guide/06-run.md) ·\n  [`serve`](docs/guide/07-serve.md) ·\n  [CI integration](docs/guide/09-ci-integration.md)\n- **I'm moving resources between stacks.** → [`state`](docs/guide/08-state.md)\n- **Just give me every flag.** → [Reference](docs/reference/index.md) ·\n  [CLI](docs/reference/cli.md) · [Configuration](docs/reference/configuration.md)\n- **How is it built?** → [Architecture](docs/architecture/) ·\n  [`DESIGN.md`](docs/DESIGN.md)\n\n---\n\n## Install\n\n```bash\ngo install github.com/Fluent-Health/terraform-stack-plan/cmd/tfstackplan@latest\n# or\ngo build -o tfstackplan ./cmd/tfstackplan\n```\n\nPrebuilt binaries (linux/darwin · amd64/arm64) are on the\n[Releases](https://github.com/Fluent-Health/terraform-stack-plan/releases) page,\nwhich also ships a multi-arch, distroless **Cloud Run container** (entrypoint\n`serve`). The binary is fully static — pure-Go SQLite, no cgo — and embeds its\nassets, so the image needs no runtime files.\n\nThis repo is also **its own [asdf](https://asdf-vm.com) plugin** (hook scripts in\n[`bin/`](./bin), no separate plugin repo):\n\n```bash\nasdf plugin add tfstackplan https://github.com/Fluent-Health/terraform-stack-plan.git\nasdf install tfstackplan latest      # or a pinned version\nasdf set tfstackplan latest          # writes .tool-versions\n```\n\nFull install detail — toolchain notes, container, deployment — is in\n[Reference → Install & deploy](docs/reference/install-and-deploy.md).\n\n---\n\n## Agentic Workflows, Extensions & Workspace Skills\n\n`tfstackplan` publishes a comprehensive, cross-runtime **Workspace Agent Skill** directly in this repository under `skills/tfstackplan/SKILL.md`. This skill governs the entire lifecycle and CLI surface of `tfstackplan` (lint, plan, state refactoring, watch status, claims, and applies), instructing future coding agents on how to operate this codebase with maximum safety and TDD discipline.\n\n### Loading in Claude Code (Marketplace & Plugins)\n\nWe package `tfstackplan` as a standard Claude Code plugin. You can load this plugin directly from GitHub or subscribe to our marketplace feed:\n\n1. **Install directly as a Claude Plugin:**\n   ```bash\n   /plugin add https://github.com/Fluent-Health/terraform-stack-plan\n   ```\n2. **Add as a Marketplace Catalog:**\n   ```bash\n   /plugin marketplace add https://raw.githubusercontent.com/Fluent-Health/terraform-stack-plan/main/.claude-plugin/marketplace.json\n   ```\n*Claude Code will automatically detect `.claude-plugin/plugin.json` and load the configured `./skills` on demand when your session context matches the skill's frontmatter description, executing these instructions natively via the Claude `Skill` tool.*\n\n### Loading in Gemini CLI\n\nYou can install this repository's agent skill and extensions globally or link them locally during development:\n\n1. **Install globally as a Gemini Extension:**\n   ```bash\n   gemini extensions install https://github.com/Fluent-Health/terraform-stack-plan\n   ```\n2. **Link the skill locally:**\n   ```bash\n   gemini skills link ./skills/tfstackplan\n   ```\n*Once loaded, Gemini CLI will automatically trigger and follow this skill whenever you ask the model to validate, plan, or restructure Terraform state.*\n\n### Manual / Cross-Runtime Loading\n\nBoth Claude Code and Gemini CLI support the open [Agent Skills](https://agentskills.io) standard, enabling cross-runtime interoperability:\n\n1. **Create the global skill directory:**\n   ```bash\n   mkdir -p ~/.agents/skills/tfstackplan\n   ```\n2. **Symlink or copy the skill file:**\n   ```bash\n   ln -s \"$(pwd)/skills/tfstackplan/SKILL.md\" ~/.agents/skills/tfstackplan/SKILL.md\n   ```\n\n---\n\n## When *not* to use this\n\nHonesty up front saves everyone a wasted afternoon:\n\n- **One root module, one plan per PR.** If `terraform plan` already produces a\n  single readable diff, you don't need a *multi*-plan renderer. Reach for\n  [`tfplan2md`](https://github.com/oocx/tfplan2md) or\n  [`terraform-plan-summary`](https://github.com/dineshba/terraform-plan-summary).\n- **You want the tool to run `terraform` for you.** `render` doesn't; its inputs\n  are pre-existing `plan.json` files. (`run` *does* drive Terraform via\n  Terramate — that's a different face.)\n- **You want it to post comments for you.** `render` writes Markdown; your CI\n  posts it. (`serve` posts its own check runs, but that's the control plane, not\n  the renderer.)\n- **You need static-analysis rollups** (Checkov / Trivy / SARIF). Not today;\n  possibly later.\n\n---\n\n## Related tools\n\nYes, it's another Terraform tool. We're as surprised as you are. The difference\nis the **multi-plan** part — taking the many plans a monorepo emits per PR and\nmaking them one reviewable, gate-able, observable thing:\n\n- [`tfplan2md`](https://github.com/oocx/tfplan2md) — single-plan Markdown\n  renderer; the inspiration for the per-stack diff style.\n- [Atlantis](https://www.runatlantis.io/) — PR-comment-driven Terraform CI;\n  renders per-project, tied to its own workflow.\n- [`terraform-plan-summary`](https://github.com/dineshba/terraform-plan-summary)\n  — single-plan summary table; no multi-plan support.\n\n---\n\n## Contributing\n\nContributions welcome — see [CONTRIBUTING.md](CONTRIBUTING.md). For security\nissues, follow [SECURITY.md](SECURITY.md) rather than opening a public issue.\n\n## License\n\nLicensed under the Apache License, Version 2.0 — see [LICENSE](LICENSE).\n\n---\n\nBuilt and maintained by [Fluent Health](https://github.com/Fluent-Health).\n",
  "bytes": 11965,
  "sha": "38101c91f27b44427472187eb1519d2c81da95322399fcce68f02e8d352a2b5e",
  "repo_slug": "fluent-health/terraform-stack-plan",
  "fonte": "repo",
  "truncated": false,
  "api": "https://agentalog.com/api/listings/plg_fluent_health_terraform_stack_plan_b61ad57f/readme"
}