Skip to content

Terraform or OpenTofu roots

llms.txtlists every page for an agent

Directories of .tf files with their own state.

Works

  • init finds every root and writes the pipeline for your forge
  • Each root runs its own pinned Terraform or OpenTofu version
  • Roots that read each other through terraform_remote_state apply in waves, in order

Differs

Nothing beyond what the other pages describe.

On Terraform, choudoufu, GitLab

On Terraform

  • Two overlapping pushes to one root can fail the newer apply with "Saved plan is stale"; run it again and it plans again.

On choudoufu

  • terragucci does not read a root's required_version as a choudoufu release.

On GitLab

  • Comment commands answer on a schedule, since a merge request note starts no pipeline.
  • Roots lock on /terragucci apply or /terragucci lock, not at the first plan.
  • The agent comment and drift fixes are GitHub and Forgejo only.

First step

Get your first plan note

Proof

OpenTofu, on Forgejo

  • Plan and reviewPlan and review, OpenTofu42 checks, all proven.
    • tf-check fails an unformatted root and names the file
    • only the roots a change touches are planned
    • one note groups many plans
    39 more on the validation page.
  • Approve and applyApprove and apply, OpenTofu51 checks, all proven.
    • each wave goes out only once approved
    • a wave whose plans changed after approval applies nothing
    • under approval: sealed a wave counts only an approval sealed by a key the signers file lists
    48 more on the validation page.
  • Locks and safetyLocks and safety, OpenTofu28 checks, all proven.
    • two pushes to main apply one after the other, and the commit carries one terragucci/apply status
    • a new upstream and its dependent merge together and apply in order, so no mock reaches real state
    • a second pull request that reaches a root another open pull request has applied is refused with the root and the holder named, and applies once the first is unlocked with /terragucci unlock
    25 more on the validation page.
  • PolicyPolicy, OpenTofu16 checks, all proven.
    • an opt-in policy denies a plan, fails the root in tf-plan, and names the violation
    • a tf-apply wave whose plan the policy denies applies nothing, and its report keeps the changes of the denied root with the denial and the warnings
    • a tf-apply wave gives the policy the risk the review workflow of the default branch kept as its artifact for the head of the merged pull request as input.review; the edited review job of the pull request itself keeping risk low and a forged low-risk note posted with the pipeline token change nothing, and a policy that denies risk high stops the wave
    13 more on the validation page.
  • DriftDrift, OpenTofu10 checks, all proven.
    • drift is reported by root
    • drift is reported by unit in a Terragrunt repo, with the same tracking issue
    • drift on a literal becomes a pull request with the live value, and import blocks for what is unmanaged
    7 more on the validation page.
  • Chat and notifyChat and notify, OpenTofu6 checks, all proven.
    • with notify naming a Slack and a Teams webhook secret and approval: pr-review, a wave of a merged pull request that waits posts the wave, its root, the digest, the approve command, the run and a link to review the pull request to each, and once that review lands the next run applies it
    • with notify naming a generic webhook and its key, a wave that waits posts a terragucci.notify/v1 event signed with HMAC-SHA256 over its body, carrying the outcome, digest and approve command
    • a click on the Approve button of the Slack message of a waiting wave, signed with the signing secret of the app, reaches the relay, which maps the Slack user to their principal in the signers file, records the approval of that digest as them and says so in the thread; the resume workflow then applies the wave
    3 more on the validation page.
  • Reports and visibilityReports and visibility, OpenTofu41 checks, all proven.
    • the report is JSON and HTML, and links every root to its full plan
    • each plan run is one trace, with a span per root and the binary spans inside it
    • the metrics of a plan run reach Prometheus with the counts in its report
    38 more on the validation page.
  • ModulesModules, OpenTofu13 checks, all proven.
    • a module version rolls out one pull request per wave
    • changed modules are published at a new version
    • with modules.attest each release is signed, attested and recorded in the release ledger with its tag
    10 more on the validation page.
  • State and migrationState and migration, OpenTofu20 checks, all proven.
    • each Atmos instance plans and applies in the Terraform workspace Atmos names for it, never default: the instances of one component in two stacks keep their own states, and plan no change after the apply
    • a root whose state is in a versioned S3 bucket applies twice, and the estate page lists both state version ids newest first, each one the bucket holds, and no state content
    • terragucci state export records a request, waits for an approval by someone else, then writes the state version on the machine of the person who asked, recorded on chant/lifecycle and in the audit trail, with no state in the bucket
    17 more on the validation page.
  • Agents and pull request environmentsAgents and pull request environments, OpenTofu10 checks, all proven.
    • a /terragucci agent comment pushes the commit of the stand-in agent to the branch of the pull request, which re-plans it and is linked in the reply, and a forbidden path, a non-writer and a fork push nothing
    • with review.agent on, the review workflow of the default branch runs on pull_request_target after the plan, and its review job runs a stand-in reviewer on the pull request, its plan and the instructions of the default branch, with the key of the model and no forge token, and the note it posts flags a destroy the description does not mention and approves nothing
    • with respond.description: check the plan job flags a destroy the pull request description leaves out, at the top of the note and in the report, and writes intent.json
    7 more on the validation page.
  • Setup and runtimeSetup and runtime, OpenTofu39 checks, all proven.
    • the example boots and deploys locally
    • with no more than a drift schedule and the canary wave in terragucci.yml, init writes the same pipeline
    • a control repo opens one pull request per project that changes, and the merged pipeline applies
    36 more on the validation page.
  • proven passes, and fails with the feature cut out

Every check runs on OpenTofu on Forgejo. Runs on Terraform, choudoufu and github.com are expensive, so they re-run only the checks where the binary or forge changes what happens.

Open a cell for the checks behind it. Recorded: example checks, last full run Oct 8, 2026; per-forge checks Oct 7 to Oct 9, 2026; github.com Oct 10, 2026.

You can count on

Then read

Tasks
Add terragucci to a repoChoose your binaryApprove a waiting wave
Background
ArchitectureWaves and approvals
Details
terragucci.yml keysStages

terragucci

These docs count page views and clicks with PostHog. They set no cookies, store nothing in your browser, and send nothing when your browser asks not to be tracked.