Skip to content

Validation

llms.txtlists every page for an agent

Each smoke claim runs twice and passes only when both runs hold: as written it must pass, and with its property broken on purpose (the BREAK) it must fail.

By tool, on Forgejo

Swipe for more columns

BinaryRepo shape
Feature areaOpenTofuTerraformchoudoufuTerragruntAtmosTerramateCDK Terrain
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 in the full tables below.
Plan and review, TerraformNot re-run on Terraform. These 42 checks run the same code on every binary; on OpenTofu, 42 are 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 in the full tables below.
Plan and review, choudoufu1 check, proven.
  • the generated workflow for a choudoufu estate fails a resource that live-check refuses and names it
42 other checks run the same code on every binary and are not re-run here.
Plan and review, Terragrunt10 checks, all proven.
  • tf-check fails an unformatted Terragrunt file and names it
  • only the units a change reaches are planned, including a file a module reads that Terragrunt misses
  • a dependency whose mock_outputs can stand in for apply is named by a tip
7 more in the full tables below.
Plan and review, Atmos2 checks, all proven.
  • a pull request that changes one Atmos instance plans that instance and the instances whose dependencies.components name it, and no other
  • the check job of an Atmos repo runs atmos validate stacks before it writes the instances, and fails on a manifest Atmos refuses, with the error Atmos gives
Plan and review, Terramate2 checks, all proven.
  • a pull request that changes one Terramate stack plans that stack and the stacks whose after or before put them after it, and no other
  • the check job of a Terramate repo fails on stale generated code, naming the file terramate generate would change
Plan and review, CDK Terrain4 checks, all proven.
  • with synth set to npx cdktn synth the pipeline synthesizes the CDK Terrain stacks before check, apply and tf-plan, and tf-plan plans the stack the change reaches
  • with synth set a pull request that changes one CDK Terrain stack plans that stack alone, and the plan note says how many stacks were unchanged
  • with synth set the tips job synthesizes the CDK Terrain stacks and opens the canary tip, and says the pin and lock file tips are left out
1 more in the full tables below.
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 in the full tables below.
Approve and apply, Terraform4 checks, all proven.
  • each wave goes out only once approved
  • with apply.when: pull-request, a comment on an open and approved pull request applies its head in waves and then merges it with apply.merge: auto
  • terragucci approve --plan with a digest the plans moved past approves nothing, exits 1 and names the digest waiting
1 more in the full tables below.47 other checks run the same code on every binary and are not re-run here.
Approve and apply, choudoufu6 checks, all proven.
  • each wave goes out only once approved
  • with apply.when: pull-request, a comment on an open and approved pull request applies its head in waves and then merges it with apply.merge: auto
  • with binary: choudoufu a gated wave killed after its approved apply of one resource returned is found by terragucci resume, and the wave run again applies only the other resource under the same approval, with no new one
3 more in the full tables below.47 other checks run the same code on every binary and are not re-run here.
Approve and apply, Terragrunt14 checks, all proven.
  • the Terragrunt example boots in five waves, one job each: the dependency layers of the dev canary, then the layers of staging and prod, each with one run --all
  • a Terragrunt wave waits for an approval of its set digest, and once approved applies its saved plans while the next wave waits at its own gate
  • a Terragrunt wave whose plans changed after approval applies nothing and names the unit that moved
11 more in the full tables below.
Approve and apply, Atmos3 checks, all proven.
  • init names one root per Atmos instance, <stack>/<component>, from atmos describe stacks, and cuts a wave per layer of dependencies.components: each dependent instance applies in the wave after its dependency, behind its own gate
  • an Atmos wave whose plans changed after approval applies nothing and names the instance that moved; once its new plans are approved it applies the plans whose digest was approved
  • an Atmos instance whose stack reads an unapplied instance with !terraform.state is held back, never planned on a stand-in, and applies on the output of the upstream once it has applied
Approve and apply, Terramate2 checks, all proven.
  • init takes the stacks of a Terramate repo as roots and cuts a wave per layer of their order: a stack after a tag or before another applies in the wave its order gives it, behind its own gate
  • a Terramate stack whose input block reads an output of an unapplied stack is held back, never planned on the mock, and applies on the output of the upstream once it has applied
Approve and apply, CDK Terrain1 check, proven.
  • with synth set each apply wave synthesizes the CDK Terrain stacks and applies its stack behind the gate: dev once wave 1 is approved, prod once wave 2 is
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 in the full tables below.
Locks and safety, Terraform3 checks, all proven.
  • two pushes to main apply one after the other, and the commit carries one terragucci/apply status
  • with binary: terraform a tf-apply wave whose plan meets a state lock another Terraform plan holds waits for it under the default -lock-timeout terragucci adds, the root's plan time in the report covering the wait, and applies once the lock is released
  • terragucci unlock-state refuses to release a state lock while a run that began before it is alive, and once the apply that held it is killed releases it only after an approval of its lock ID, recording who released which lock, and the next wave applies
26 other checks run the same code on every binary and are not re-run here.
Locks and safety, choudoufu9 checks, all proven.
  • a plan that waits for a state lock another plan holds shows the wait as a State lock wait span, in its report and its trace
  • with binary: choudoufu two tf-apply waves of one estate that change different resources run at once, both reach their record write together and both apply, with no lock wait and no lock object
  • with binary: choudoufu two tf-apply waves of one estate, each adding a resource whose apply takes 60 seconds, finish both resources in under 90 seconds: the second wave starts while the first is applying and does not wait for it
6 more in the full tables below.27 other checks run the same code on every binary and are not re-run here.
Locks and safety, Terragrunt3 checks, all proven.
  • a new upstream and its dependent merge together and apply in order, so no mock reaches real state
  • in a Terragrunt repo, a pull request that changes a unit whose dependencies block names a unit another open pull request applied is refused with the unit and the holder named
  • in a Terragrunt repo a change to root.hcl locks every unit and says why, and a Markdown-only change locks none
Locks and safety, Atmos1 check, proven.
  • with apply.when: pull-request in an Atmos repo, a pull request applied on a comment locks the Atmos instances it reaches (every instance, for a change to a stack manifest), and a second pull request that changes one is refused with the instance and the holder named, its state left as the first applied it
Locks and safety, Terramate1 check, proven.
  • with apply.when: pull-request in a Terramate repo, a pull request applied on a comment locks the stack it changes, and a second pull request that changes that stack is refused with the stack and the holder named, its state left as the first applied it
Locks and safety, CDK Terrain1 check, proven.
  • with synth and apply.when: pull-request, a pull request applied on a comment locks every CDK Terrain stack, since its change to the app can reach any, and a second pull request that changes a stack is refused with the stack and the holder named, its state left as the first applied it
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 in the full tables below.
Policy, Terraform2 checks, all proven.
  • 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
  • with cost.approve_above set, a wave whose monthly change is over the amount waits for an approval under gate: never, its log naming the change, the amount and the commit read, and the plan note of a pull request sets the change of each wave against the amount at base
14 other checks run the same code on every binary and are not re-run here.
Policy, choudoufu2 checks, all proven.
  • 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
  • with cost.approve_above set, a wave whose monthly change is over the amount waits for an approval under gate: never, its log naming the change, the amount and the commit read, and the plan note of a pull request sets the change of each wave against the amount at base
14 other checks run the same code on every binary and are not re-run here.
Policy, Terragrunt2 checks, all proven.
  • in a Terragrunt repo a unit the policy denies fails tf-plan, and its wave applies nothing
  • with cost.approve_above set, a Terragrunt wave whose saved unit plans are priced over the amount waits for an approval under gate: never, while a wave within it applies
Policy, AtmosNo check recorded.Policy, TerramateNo check recorded.Policy, CDK TerrainNo check recorded.
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 in the full tables below.
Drift, Terraform2 checks, all proven.
  • drift is reported by root
  • with binary: terraform a root with a .tfquery.hcl gets the drift pull request with the config terraform query generated for what it lists
9 other checks run the same code on every binary and are not re-run here.
Drift, choudoufu2 checks, all proven.
  • with binary: choudoufu and the roots under live resource markers, drift is a config error: init and stage tf-drift exit 2 naming the roots, before any plan
  • with binary: choudoufu a queue changed outside choudoufu on a root under live resource markers is drift: tf-drift plans the root in full, its report and one drift issue name the root and the attribute, and a run with no change closes the issue
9 other checks run the same code on every binary and are not re-run here.
Drift, Terragrunt4 checks, all proven.
  • drift is reported by unit in a Terragrunt repo, with the same tracking issue
  • a drifted Terragrunt unit gets a pull request that writes the live value into its own terragrunt.hcl inputs and leaves the module its units share alone
  • with respond.drift: attribute in a Terragrunt repo, tf-drift lists who changed each drifted attribute under its unit in the drift issue
1 more in the full tables below.
Drift, AtmosNo check recorded.The drift pull request is refused: a live value belongs in the stack vars or the component.Drift, TerramateNo check recorded.The drift pull request is refused: a live value belongs in the stack .tm.hcl or its own Terraform.Drift, CDK TerrainNo check recorded.The drift pull request is refused: a live value belongs in the app that writes the stacks.
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 in the full tables below.
Chat and notify, Terraform1 check, proven.
  • 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
5 other checks run the same code on every binary and are not re-run here.
Chat and notify, choudoufu1 check, proven.
  • 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
5 other checks run the same code on every binary and are not re-run here.
Chat and notify, TerragruntNo check recorded.Chat and notify, AtmosNo check recorded.Chat and notify, TerramateNo check recorded.Chat and notify, CDK TerrainNo check recorded.
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 in the full tables below.
Reports and visibility, Terraform5 checks, all proven.
  • the report is JSON and HTML, and links every root to its full plan
  • terragucci audit writes one record to the bucket: every approval on the ledger with its approver, digest and time and who relayed it, the request, and the apply that names its approval; --check passes and the estate page links the audit page
  • after two apply waves of the example roots the estate page lists every resource of each root by address, type and provider, with the count of each type, and no value
2 more in the full tables below.36 other checks run the same code on every binary and are not re-run here.
Reports and visibility, choudoufu8 checks, all proven.
  • the report is JSON and HTML, and links every root to its full plan
  • with binary: choudoufu the report lists the slowest provider calls of a root, each with its method, provider and resource type, from the provider call spans choudoufu sends
  • with binary: choudoufu past its span budget the report lists the timings choudoufu summed by resource type, and the note of the root says it summed them
5 more in the full tables below.36 other checks run the same code on every binary and are not re-run here.
Reports and visibility, Terragrunt2 checks, all proven.
  • the plan of each Terragrunt unit sends its spans to the report through the TG_TF_PATH wrapper, and waits up to five minutes for the state lock
  • in a Terragrunt repo the plan note gives the blast radius of a changed unit through the units that depend on it, and the run view and the estate graph hold each unit by wave with an edge for each dependency block
Reports and visibility, AtmosNo check recorded.Reports and visibility, TerramateNo check recorded.Reports and visibility, CDK TerrainNo check recorded.
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 in the full tables below.
Modules, TerraformNot re-run on Terraform. These 13 checks run the same code on every binary; on OpenTofu, 13 are 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 in the full tables below.
Modules, choudoufuNot re-run on choudoufu. These 13 checks run the same code on every binary; on OpenTofu, 13 are 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 in the full tables below.
Modules, Terragrunt1 check, proven.
  • with modules.require: attested in a Terragrunt repo tf-check and tf-plan refuse a unit whose terraform source pins an unattested release, and pass one that pins an attested release
Modules, AtmosNo check recorded.Rollouts are refused: every instance of a component shares its files, so no wave can move a pin alone.Modules, TerramateNo check recorded.Rollouts are refused: the pin is usually in code terramate generate writes.Modules, CDK TerrainNo check recorded.Rollouts are refused: the pin is in the app that writes the stacks.
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 in the full tables below.
State and migration, TerraformNot re-run on Terraform. These 20 checks run the same code on every binary; on OpenTofu, 20 are 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 in the full tables below.
State and migration, choudoufu3 checks, all proven.
  • with binary: choudoufu one tf-apply wave applies two estates into one record store bucket, each under its own prefix and estate tag, and the next plan of both shows no change
  • with binary: choudoufu a migration moves a resource between two estates by rewriting its ownership tags: proved by both plans, approved by digest, after which the next plan of both shows no change and the move is on chant/lifecycle
  • with binary: choudoufu a migration adopts a root on s3 state into an estate: proved against the live system, approved by digest, its resources stamped with no change, and its old state left as the version it was
20 other checks run the same code on every binary and are not re-run here.
State and migration, Terragrunt3 checks, all proven.
  • a Terragrunt unit whose state is in a versioned S3 bucket applies twice, its backend read from its remote_state block, and the estate page lists both state version ids newest first, each one the bucket holds
  • a migration file moves a resource from the state of one Terragrunt unit to that of another: the plan proves it with no change, wave 1 waits for its digest, and once approved writes both states under their locks, recording each version before and after
  • terragucci state export of a Terragrunt unit prepares it through Terragrunt, asks for the version of the state its remote_state block names, and once someone else approved it writes that version on the machine of the person who asked, recorded on chant/lifecycle
State and migration, Atmos1 check, 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
State and migration, TerramateNo check recorded.State and migration, CDK Terrain1 check, proven.
  • a migration moves a resource between two CDK Terrain stacks, whose roots are cdk.tf.json: tf-plan proves it with no change, wave 1 waits for its digest, and once approved writes both states under their lock files
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 in the full tables below.
Agents and pull request environments, TerraformNot re-run on Terraform. These 10 checks run the same code on every binary; on OpenTofu, 10 are 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 in the full tables below.
Agents and pull request environments, choudoufuNot re-run on choudoufu. These 10 checks run the same code on every binary; on OpenTofu, 10 are 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 in the full tables below.
Agents and pull request environments, Terragrunt1 check, proven.
  • in a Terragrunt repo whose remote_state key reads TERRAGUCCI_EPHEMERAL_SUFFIX, opening a pull request applies its own copy of a unit at the key suffixed -pr-<n>, prepared through Terragrunt, beside the state of the unit itself, and closing it destroys the copy on the record
Agents and pull request environments, AtmosNo check recorded.A copy per pull request is refused: the stack backend and workspace name the state of an instance.Agents and pull request environments, TerramateNo check recorded.Agents and pull request environments, CDK Terrain1 check, proven.
  • with synth set, opening a pull request runs the synth command in its checkout and applies its own copy of a CDK Terrain stack at the key suffixed -pr-<n>, beside the state of the stack itself, and closing it destroys the copy on the record
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 in the full tables below.
Setup and runtime, Terraform3 checks, all proven.
  • the example boots and deploys locally
  • with binary: terraform the pipeline runs in the terraform image, check and the plan pass, and a wave waits for its approval and then applies with Terraform
  • in a Terragrunt repo with binary: terraform the pipeline installs Terraform and Terragrunt applies every unit with it
38 other checks run the same code on every binary and are not re-run here.
Setup and runtime, choudoufu3 checks, all proven.
  • the example boots and deploys locally
  • with binary: choudoufu a role granted one estate by its ownership tag applies a change to that estate, and IAM refuses it a change to an instance of another estate
  • in a Terragrunt repo with binary: choudoufu the jobs run in the choudoufu image with Terragrunt installed beside it, and every unit plans with choudoufu through TG_TF_PATH
38 other checks run the same code on every binary and are not re-run here.
Setup and runtime, Terragrunt8 checks, all proven.
  • init finds Terragrunt and its 15 units on its own and writes the pipeline the Terragrunt example commits
  • terragucci import terragrunt-scale writes the plan and apply roles of each Gruntwork Pipelines environment as terragrunt.credentials, and every unit then assumes the roles of its environment, a unit with its own gruntwork.hcl its own
  • in a Terragrunt repo terragucci generate writes terragucci.hcl from terragucci.yml, the check step passes it, and each unit that includes it applies with the backend key and provider settings generate gives it, while a unit that does not include it is refused by name
5 more in the full tables below.A Terragrunt repo takes no synth, so a CDK Terrain app cannot run in one.
Setup and runtime, Atmos3 checks, all proven.
  • atmos.version in terragucci.yml is the Atmos release every job installs
  • oidc.roles by stack glob gives the instances of each Atmos stack roles of their own: config check lists each role with the states of its stack, and each instance plans and applies as the role of its stack
  • config check and init refuse the drift pull request of an Atmos repo in the same words, about the vars of the stack, never synth; respond tips proposes lock files for the components and a canary of instances
Setup and runtime, TerramateNo check recorded.Setup and runtime, CDK Terrain2 checks, all proven.
  • with synth set init refuses the drift pull request and rollouts as config errors saying why, and with respond.drift: attribute the drift job runs no pull request
  • with synth set init and terragucci generate refuse a generate key as a config error that names the CDK Terrain constructs that set a backend
A CDK Terrain app cannot run in a Terragrunt repo, which takes no synth.

By forge

Feature areaForgejoGitHubGitLab
Plan and reviewPlan and review, Forgejo43 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
40 more in the full tables below.
Plan and review, GitHub7 checks: 3 proven, 4 pass with nothing cut out.
  • a pull request that changes one root plans that root alone, and its plan note covers it alone
  • /terragucci plan on a pull request re-plans it in a run of its own, and the re-plan edits the plan note
  • the plan note ends with the terragucci footer, and its taco image answers 200 with a PNG
4 more in the full tables below.On github.com most checks run with nothing cut out.
Plan and review, GitLab9 checks, all proven.
  • a merge request that changes one of two roots plans that root alone, against its target branch, and its plan note covers it alone
  • the plan note on a merge request counts the tips the plan report holds, each naming its rule and page
  • the plan note on a merge request ends with the terragucci footer, GitLab renders its taco image, and the image answers 200 with a PNG
6 more in the full tables below.
Approve and applyApprove and apply, Forgejo53 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
50 more in the full tables below.
Approve and apply, GitHub8 checks: 3 proven, 5 pass with nothing cut out.
  • a merged destroy stops its wave with the approve command, and after a sealed chant approve the re-run applies it
  • /terragucci apply on a merged pull request applies it again from its merge commit, and while its wave waits it applies nothing and gives the approve command; on an open pull request it is refused
  • terragucci approve in a clone approves the waiting wave with no digest copied, and the re-run applies it; with --dry-run it records nothing
5 more in the full tables below.On github.com most checks run with nothing cut out.
Approve and apply, GitLab8 checks, all proven.
  • roots on GitLab-managed state apply at most 3 at once, and the apply job says so
  • with apply.when pull-request, /terragucci apply starts a pipeline on main with the merge token whose mr-apply applies the head and pr-merge merges it
  • with approval pr-review, a Developer approval of the merge request lets the merge commit gated wave apply, and the job names the approver
5 more in the full tables below.
Locks and safetyLocks and safety, Forgejo36 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 plan that waits for a state lock another plan holds shows the wait as a State lock wait span, in its report and its trace
33 more in the full tables below.
Locks and safety, GitHub5 checks, all proven.
  • with locks: plan a pull request locks the root it plans, and a second one reaching that root fails terragucci/lock and is answered with the root and the holder
  • two merges pushed back to back apply in the order they arrived, the older run stands down once the newer push lands and the newer applies the tree, none is cancelled, and each commit ends with a terragucci/apply success
  • with apply.when: pull-request a second pull request that reaches a root an open one applied is refused with the root and the holder named, and applies once the first is unlocked with /terragucci unlock
2 more in the full tables below.
Locks and safety, GitLab6 checks, all proven.
  • two pushes to main apply one after the other through the resource group, none is cancelled, and the commit carries one terragucci/apply success
  • with apply.when pull-request, a merge request applied on a note locks the roots it reaches: /terragucci apply on a second merge request that reaches one is refused with the root and the holder named, and applies once the first is unlocked with /terragucci unlock
  • with apply.when pull-request, closing a merge request releases the roots it locked: /terragucci lock on a second merge request then takes them
3 more in the full tables below.Locks from the first plan (locks: plan) are refused on GitLab, where no merge request event runs a job from the default branch.
PolicyPolicy, Forgejo16 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 in the full tables below.
Policy, GitHub2 checks: 0 proven, 2 pass with nothing cut out.
  • a pull request that replaces a table fails terragucci/plan under the Rego policy on main, and its plan note names the denial
  • a wave the policy denies applies once the approver policy.override lists overrides its plan with terragucci override, and the report names the override; an override by someone it does not list counts for nothing
On github.com most checks run with nothing cut out.
Policy, GitLab2 checks, all proven.
  • a merge request whose plan the policy on main denies fails its plan job and terragucci/plan, though it rewrites that policy, and its plan note names the denial
  • a wave the policy denies is retried with no effect after an override by someone policy.override does not list, applies after the listed approver overrides its plan, and its report names the override
DriftDrift, Forgejo12 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
9 more in the full tables below.
Drift, GitHub2 checks: 1 proven, 1 passes with nothing cut out.
  • the drift job opens the drift issue, a second run updates that issue, and a run that finds no drift closes it
  • on GitHub, a drift run opens the drift issue, and a second run finds it and updates it instead of opening another
On github.com most checks run with nothing cut out.
Drift, GitLab1 check, proven.
  • the drift schedule opens one drift issue naming the root and attribute that drifted, updates the same issue when more drifts, and closes it when a run finds none
Chat and notifyChat and notify, Forgejo6 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 in the full tables below.
Chat and notify, GitHubNo check recorded.Chat and notify, GitLabNo check recorded.
Reports and visibilityReports and visibility, Forgejo44 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
41 more in the full tables below.
Reports and visibility, GitHubNo check recorded.Reports and visibility, GitLab3 checks, all proven.
  • with no static keys, the plan job assumes reports.role with its OIDC token from id_tokens, writes report.json to the bucket, and the index lists the run
  • with the bucket keys in CI/CD variables, which the pipeline maps nowhere, the plan job writes report.json to the bucket and the index lists the run
  • the estate job of the see-every-project page, pasted into .gitlab-ci.yml and run by a pipeline schedule with only its OIDC token, writes estate.html listing the project to the bucket and prints a presigned link
ModulesModules, Forgejo13 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 in the full tables below.
Modules, GitHub2 checks: 0 proven, 2 pass with nothing cut out.
  • with modules.publish: git-tags a conventional commit to a module on main makes the publish job push the module tag
  • once the roots pin that tag and the next version is published, terragucci rollout --mode apply opens one pull request for the canary wave that moves those pins alone
On github.com most checks run with nothing cut out.
Modules, GitLab2 checks, all proven.
  • a module version rolls out one merge request per wave, each changing only its roots and opened only after the last wave merged and applied
  • the publish job pushes a git tag for each changed module on a merge to main, none when no module changed, and the next version for a changed module
State and migrationState and migration, Forgejo23 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
  • with binary: choudoufu one tf-apply wave applies two estates into one record store bucket, each under its own prefix and estate tag, and the next plan of both shows no change
  • with binary: choudoufu a migration moves a resource between two estates by rewriting its ownership tags: proved by both plans, approved by digest, after which the next plan of both shows no change and the move is on chant/lifecycle
20 more in the full tables below.
State and migration, GitHubNo check recorded.State and migration, GitLab3 checks, all proven.
  • on GitLab-managed state, each apply wave logs the state address of the root and the serial GitLab holds after it, and GitLab keeps each of those versions
  • terragucci state export of a root on GitLab-managed state asks for a serial, and once someone else approved it writes the version GitLab keeps by that serial, recorded on chant/lifecycle
  • a root on GitLab-managed state applies with its backend password passed as TF_HTTP_PASSWORD from the job token, and GitLab holds its state
Agents and pull request environmentsAgents and pull request environments, Forgejo10 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 in the full tables below.
Agents and pull request environments, GitHub2 checks: 0 proven, 2 pass with nothing cut out.
  • a /terragucci agent comment pushes the commit of the stand-in agent onto the branch of the pull request, which plans again, and the reply links it; an ask whose change touches the pipeline is refused and nothing is pushed
  • after a refused wave the explain-refusal job of the refused-wave guide runs, and its respond wave-refused step names the root that moved; a stand-in takes the place of the model step
On github.com most checks run with nothing cut out.
Agents and pull request environments, GitLab4 checks, all proven.
  • after a wave is refused, the explain-refusal job of the agent-refused-wave page runs wave-refused on the wave reports and a stand-in agent prints a summary naming the root whose plan moved, and a branch pipeline still runs
  • a /terragucci agent note starts a pipeline on main whose agent sees no forge token and whose push job commits its change to the branch, refusing one to the pipeline file
  • the comments job starts a review on main whose note flags an unmentioned destroy with no forge token in reach, and the merged wave policy reads its risk
1 more in the full tables below.
Setup and runtimeSetup and runtime, Forgejo43 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
40 more in the full tables below.
Setup and runtime, GitHub2 checks: 1 proven, 1 passes with nothing cut out.
  • the plan job holds a GitHub-signed OIDC token for this repo and run, for the plan role, and the apply job on main one for the apply role; with no cloud account the token is checked, not traded with STS
  • a control repo opens one pull request per project that changes, and the merged pipeline applies both roots
On github.com most checks run with nothing cut out.
Setup and runtime, GitLab3 checks, all proven.
  • a control repo with projects on GitLab and Forgejo opens the merge request of the GitLab project, names the Forgejo project that failed, and exits 1
  • the merge request plan job holds a GitLab id_token for sts.amazonaws.com naming this project, pipeline and job, for the plan role, and the apply job on main one for the apply role; the token is verified against the keys the lab publishes, not traded with STS
  • a control repo opens one merge request per project that changes, and the merged pipeline applies both roots
  • proven passes, and fails with the feature cut out
  • passes passes, not run with the feature cut out
  • same code not re-run on this binary; its checks run the same code on every binary
  • not supported not supported by design; a corner mark means part of the area
  • none no check recorded

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. On github.com most checks run with nothing cut out, so they pass but are not proven.

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.

What is left

37 cells of the grids above are not proven yet.

CellNow
Terraform, Plan and reviewsame code
Terraform, Modulessame code
Terraform, State and migrationsame code
Terraform, Agents and pull request environmentssame code
choudoufu, Modulessame code
choudoufu, Agents and pull request environmentssame code
Terragrunt, Chat and notifynone
Atmos, Policynone
Atmos, Driftnone
Atmos, Chat and notifynone
Atmos, Reports and visibilitynone
Atmos, Modulesnone
Atmos, Agents and pull request environmentsnone
Terramate, Policynone
Terramate, Driftnone
Terramate, Chat and notifynone
Terramate, Reports and visibilitynone
Terramate, Modulesnone
Terramate, State and migrationnone
Terramate, Agents and pull request environmentsnone
Terramate, Setup and runtimenone
CDK Terrain, Policynone
CDK Terrain, Driftnone
CDK Terrain, Chat and notifynone
CDK Terrain, Reports and visibilitynone
CDK Terrain, Modulesnone
GitHub, Plan and reviewpasses
GitHub, Approve and applypasses
GitHub, Policypasses
GitHub, Driftpasses
GitHub, Chat and notifynone
GitHub, Reports and visibilitynone
GitHub, Modulespasses
GitHub, State and migrationnone
GitHub, Agents and pull request environmentspasses
GitHub, Setup and runtimepasses
GitLab, Chat and notifynone

Every check behind the grids is listed in the per-forge claims and the example’s checks below.

Forge What runs
Forgejo a Forgejo server and its runner
GitHub the generated workflow, run by act against a mock GitHub API
github.com the published release’s generated workflow on GitHub-hosted runners, in a public plan-only repo
GitLab GitLab CE and its runner

reconcile follows a control repo’s pull request until it is merged and applied. Pinned CI images run the tg- claims on a two-unit Terragrunt repo and the cdf- claims on a choudoufu estate.

The github.com claims run the newest published release against real GitHub pull request events and statuses, comments and reviews, and OIDC tokens. Every resource there is a terraform_data, so nothing needs a cloud account. The limits:

Limit What runs instead
no cloud role oidc checks each job’s token against GitHub’s published keys, its repo, run, audience and role, and trades it with nothing; the trade with STS is proven on Forgejo
no bucket report-keys, report-oidc and estate-job write to floci, the AWS emulator, run in the job beside a stand-in for STS that checks each token and role as oidc does
one GitHub account the refusals of a commenter with no write access and of a pull request from a fork are proven on Forgejo; the apply-before-merge pull requests are opened by a workflow, so the account that runs the claims may approve them
no model key the agent comment and the refused-wave job run a stand-in agent that makes one edit or prints the summary input
BREAK for the locking and report claims alone pr-lock, pr-lock-fmt, apply-serial, pr-apply-lock, pr-apply-stale, report-keys, report-oidc and estate-job run a second time with their property broken (a lock dropped from chant/lifecycle, a guard cut from the committed pipeline, undiverged left out of apply.requires, or the job’s keys or token taken away); the other claims have no BREAK run, so they read “passes”
Every per-forge claim
ForgeClaimWhat it showsResult
AWS emulators3floci starts and answers S3proven
Forgejochecka push that is formatted goes green, and one with an unformatted file goes red naming the fileproven
Forgejoapplya push to main applies the root, and the bucket exists afterwardsproven
Forgejotg-checkthe generated workflow for a Terragrunt repo fails an unformatted unit file and names itproven
Forgejotg-applythe generated workflow for a Terragrunt repo applies both of its units on the default branchproven
Forgejocdf-checkthe generated workflow for a choudoufu estate fails a resource that live-check refuses and names itproven
Forgejocdf-applythe generated workflow for a choudoufu estate applies it on the default branch, and the bucket carries the estate markerproven
GitHubcheckthe generated workflow fails an unformatted root and names the fileproven
GitHubapplythe generated workflow applies the root on the default branchproven
GitHubreconcilea control repo opens one pull request per project that changes, and the merged pipeline applies both rootsproven
GitHubtg-checkthe generated workflow for a Terragrunt repo fails an unformatted unit file and names itproven
GitHubtg-applythe generated workflow for a Terragrunt repo applies both of its units on the default branchproven
GitHubcdf-checkthe generated workflow for a choudoufu estate fails a resource that live-check refuses and names itproven
GitHubcdf-applythe generated workflow for a choudoufu estate applies it on the default branch, and the bucket carries the estate markerproven
github.comaffecteda pull request that changes one root plans that root alone, and its plan note covers it alonepasses
github.comcomment-plan/terragucci plan on a pull request re-plans it in a run of its own, and the re-plan edits the plan notepasses
github.compr-lockwith locks: plan a pull request locks the root it plans, and a second one reaching that root fails terragucci/lock and is answered with the root and the holderproven
github.compolicya pull request that replaces a table fails terragucci/plan under the Rego policy on main, and its plan note names the denialpasses
github.comoidcthe plan job holds a GitHub-signed OIDC token for this repo and run, for the plan role, and the apply job on main one for the apply role; with no cloud account the token is checked, not traded with STSpasses
github.comgate-waita merged destroy stops its wave with the approve command, and after a sealed chant approve the re-run applies itpasses
github.comnote-footerthe plan note ends with the terragucci footer, and its taco image answers 200 with a PNGpasses
github.comtipsthe plan note counts the tips the run report holds, and each tip in the report names its rule and its pagepasses
github.comcomment-agenta /terragucci agent comment pushes the commit of the stand-in agent onto the branch of the pull request, which plans again, and the reply links it; an ask whose change touches the pipeline is refused and nothing is pushedpasses
github.compolicy-overridea wave the policy denies applies once the approver policy.override lists overrides its plan with terragucci override, and the report names the override; an override by someone it does not list counts for nothingpasses
github.comapply-serialtwo merges pushed back to back apply in the order they arrived, the older run stands down once the newer push lands and the newer applies the tree, none is cancelled, and each commit ends with a terragucci/apply successproven
github.comcomment-apply/terragucci apply on a merged pull request applies it again from its merge commit, and while its wave waits it applies nothing and gives the approve command; on an open pull request it is refusedpasses
github.comapprove-commandterragucci approve in a clone approves the waiting wave with no digest copied, and the re-run applies it; with --dry-run it records nothingpasses
github.comdrift-issuethe drift job opens the drift issue, a second run updates that issue, and a run that finds no drift closes itpasses
github.compr-apply-lockwith apply.when: pull-request a second pull request that reaches a root an open one applied is refused with the root and the holder named, and applies once the first is unlocked with /terragucci unlockproven
github.compr-apply-stalea comment on an approved pull request whose head is behind main is refused as not up to date, and nothing appliesproven
github.compr-applywith apply.merge: auto a comment on an open, approved pull request applies its head in every wave, and pr-merge merges it with the job tokenpasses
github.compr-apply-tokenwith apply.merge: auto and merge_token_env the merge is made with that token, so the merge commit starts its own run on mainpasses
github.compublishwith modules.publish: git-tags a conventional commit to a module on main makes the publish job push the module tagpasses
github.comrolloutonce the roots pin that tag and the next version is published, terragucci rollout --mode apply opens one pull request for the canary wave that moves those pins alonepasses
github.comexplain-refusalafter a refused wave the explain-refusal job of the refused-wave guide runs, and its respond wave-refused step names the root that moved; a stand-in takes the place of the model steppasses
github.compr-lock-fmtwith locks: plan a pull request whose check job formats it, with a push that starts no workflow, still has its lock answered on the formatted headproven
GitLabcheckthe generated pipeline fails an unformatted root and names the fileproven
GitLabapplythe generated pipeline applies the root on the default branchproven
GitLabreconcilea control repo opens one merge request per project that changes, and the merged pipeline applies both rootsproven
GitLabtg-checkthe generated pipeline for a Terragrunt repo fails an unformatted unit file and names itproven
GitLabtg-applythe generated pipeline for a Terragrunt repo applies both of its units on the default branchproven
GitLabcdf-checkthe generated pipeline for a choudoufu estate fails a resource that live-check refuses and names itproven
GitLabcdf-applythe generated pipeline for a choudoufu estate applies it on the default branch, and the bucket carries the estate markerproven
GitLabgl-check-tokenwith GITLAB_TOKEN an unprotected variable the synth command of a branch runs in the check job with no forge token variable, and the check passesproven
GitLabgl-managed-statea root on GitLab-managed state applies with its backend password passed as TF_HTTP_PASSWORD from the job token, and GitLab holds its stateproven

These checks run against the tutorial’s example on a local Forgejo with OpenTofu. The GitLab column lists the ones that also run on a local GitLab CE and its runner. There, each gets a small repo holding the pipeline terragucci init writes for GitLab.

The Terraform and choudoufu columns list the core checks run again on that binary in its CI image. They use binary: in each repo’s terragucci.yml, on a copy of the repo written for the binary under names of its own:

Binary What the copy changes
Terraform each root’s required_version, which pins OpenTofu’s release line, takes that release or later, and its .terraform.lock.hcl is the one Terraform writes, for Terraform’s registry
choudoufu each root’s backend becomes a live block: an estate per root, its records in an S3 record store; a service reads the platform’s logs bucket through terraform_estate_outputs instead of terraform_remote_state, and its registration in that bucket is a terraform_data, since choudoufu admits no aws_s3_object; drift is left out, since it is a config error there, which the drift row shows
Every check on the example
CheckWhat it showsForgejoTerraformchoudoufuGitLab
bootthe example boots and deploys locallyprovenprovenproven
checktf-check fails an unformatted root and names the fileproven
affectedonly the roots a change touches are plannedprovenproven
groupedone note groups many plansproven
reportthe report is JSON and HTML, and links every root to its full planprovenprovenproven
highlightdestroys and outliers are open, identical groups are foldedproven
waveseach wave goes out only once approvedprovenprovenproven
refusea wave whose plans changed after approval applies nothingproven
sealedunder approval: sealed a wave counts only an approval sealed by a key the signers file listsproven
driftdrift is reported by rootprovenprovenprovenwith binary: choudoufu and the roots under live resource markers, drift is a config error: init and stage tf-drift exit 2 naming the roots, before any plan
rollouta module version rolls out one pull request per waveprovenproven
publishchanged modules are published at a new versionprovenproven
publish-attestwith modules.attest each release is signed, attested and recorded in the release ledger with its tagproven
require-attestedwith modules.require: attested tf-plan plans a root that pins an attested release, and refuses one whose tag was movedproven
require-recordedwith modules.require: attested tf-plan refuses a root that pins a version the release ledger does not recordproven
tg-require-attestedwith modules.require: attested in a Terragrunt repo tf-check and tf-plan refuse a unit whose terraform source pins an unattested release, and pass one that pins an attested releaseproven
module-registrywith modules.registry each release is written as the module registry protocol to a bucket, and a root that pins ~> 1.0 resolves the newest 1.x from it; with modules.test an untested release is refusedproven
tipstips are on by default and name their ruleprovenproven
zero-configwith no more than a drift schedule and the canary wave in terragucci.yml, init writes the same pipelineproven
apply-serialtwo pushes to main apply one after the other, and the commit carries one terragucci/apply statusprovenprovenproven
reconcilea control repo opens one pull request per project that changes, and the merged pipeline appliesproven
reconcile-mixeda control repo with projects on Forgejo, on GitHub (the mock) and on a forge that does not answer opens the Forgejo pull request and the GitHub one, each with its own pipeline, names the project that failed, and exits 1provenproven
traceseach plan run is one trace, with a span per root and the binary spans inside itproven
metricsthe metrics of a plan run reach Prometheus with the counts in its reportproven
tg-zero-configinit finds Terragrunt and its 15 units on its own and writes the pipeline the Terragrunt example commitsproven
tg-wavesthe Terragrunt example boots in five waves, one job each: the dependency layers of the dev canary, then the layers of staging and prod, each with one run --allproven
tg-checktf-check fails an unformatted Terragrunt file and names itproven
tg-affectedonly the units a change reaches are planned, including a file a module reads that Terragrunt missesproven
tg-mock-linta dependency whose mock_outputs can stand in for apply is named by a tipproven
tg-refusea unit that reads a new upstream is planned on the planned outputs of that upstream, never on its mock_outputsproven
tg-mock-trapa new upstream and its dependent merge together and apply in order, so no mock reaches real stateproven
tg-driftdrift is reported by unit in a Terragrunt repo, with the same tracking issueproven
respond-refuseda refused wave names each root whose plan moved and the attributes that movedproven
respond-triagea failed apply is triaged from the known-error tableproven
respond-driftdrift on a literal becomes a pull request with the live value, and import blocks for what is unmanagedproven
respond-tipseach tip becomes its own small pull requestproven
respond-fmtfmt on request commits to the pull request branch and nowhere elseproven
respond-notesrelease notes come from the conventional commits that touched the moduleproven
fresh-planon a fresh estate the plan job holds back a root whose upstream is unapplied, names it in the report, and stays greenproven
forgejo-oidca Forgejo job gets an OIDC token Forgejo signed for its repo and ref, and trades it for the plan or apply roleproven
policyan opt-in policy denies a plan, fails the root in tf-plan, and names the violationprovenproven
comment-plana pull request comment re-plans on request and never applies, and a root outside the configured ones is refusedproven
import-atlantisterragucci import atlantis writes terragucci.yml from an atlantis.yaml, names what it leaves out, and the pipeline init then writes plans exactly the Atlantis projectsproven
import-spaceliftterragucci import spacelift writes terragucci.yml from spacelift_* code and .spacelift/config.yml, with context secrets to create and hooks as steps, and init then applies the roots in the order the stack dependencies askproven
import-env0terragucci import env0 writes terragucci.yml from env0_* code, env0.yml and env0-discovery.yml, and init then plans the environment roots, keeps ephemeral copies of the ones with a TTL, and holds every wave for an approvalproven
import-hcpterragucci import hcp reads the workspaces of an organization over the TFE API, only reading, and writes a root per workspace directory, lists a directory several workspaces run to split, names sensitive variables as secrets without their values, and init then applies in the order the run triggers askproven
import-scalrterragucci import scalr reads the workspaces of a Scalr account over the Scalr API, only reading, and writes their roots on tofu with the sensitive variables as secrets the pipeline passes, without their values, and names the policies of each OPA policy groupproven
import-tg-scaleterragucci import terragrunt-scale writes the plan and apply roles of each Gruntwork Pipelines environment as terragrunt.credentials, and every unit then assumes the roles of its environment, a unit with its own gruntwork.hcl its ownproven
waves-afterwaves.after orders plain roots that read nothing of each other: network, database and app apply in three waves, and a pull request that changes network plans all threeproven
comment-atlantiswith atlantis_comments on, atlantis plan re-plans a pull request, and atlantis apply and an Atlantis-only flag are refused as the terragucci forms areproven
lock-waita plan that waits for a state lock another plan holds shows the wait as a State lock wait span, in its report and its traceprovenprovenwith binary: terraform a tf-apply wave whose plan meets a state lock another Terraform plan holds waits for it under the default -lock-timeout terragucci adds, the root's plan time in the report covering the wait, and applies once the lock is released
dash-pipelinethe Pipeline health dashboard init writes shows the runs, errors and results of a plan, a drift run and a gated waveproven
dash-changesthe Change review dashboard init writes shows the roots, groups and changes by action of a pull requestproven
dash-wavesthe Rollouts and waves dashboard init writes shows a wave waiting for its approval, how long, and wave runs by resultproven
dash-driftthe Drift dashboard init writes shows the roots a drift run found drifted and how old the drift isproven
dash-estatethe Estate dashboard init writes shows the roots of a project and the binary and terragucci versions it runsproven
dash-runsthe Runs dashboard init writes shows the slowest roots, stage durations and the trace of each run from Tempoproven
dash-slosthe SLO dashboards init writes are provisioned, and the plan SLO records the plans of a project from the rules init writesproven
drill-downthe plan note links the report in the bucket, the report links each root plan and the trace of the run, the trace and the dashboards link back to the report, and the index row links the commit, pull request and jobproven
policy-wavea 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 warningsprovenprovenproven
check-diagnosticstf-check fails with the cause in its log for a validate error, a failing policy test and a choudoufu live-check refusalproven
comment-not-affecteda re-plan comment for a root the pull request does not reach is answered that it is not affected and plans nothing, and a re-plan whose forge call fails fails its job with the causeproven
drift-attributewith respond.drift: attribute, tf-drift lists who changed each drifted attribute under its root in the drift issueproven
version-bump-jobwith respond.version-bump: suggest, the version-bump job of the pipeline runs after the last apply on the default branch and opens a release pull request with the answer of the decision serviceproven
tg-spansthe plan of each Terragrunt unit sends its spans to the report through the TG_TF_PATH wrapper, and waits up to five minutes for the state lockproven
oidc-cloudsa job with oidc.gcp and oidc.azure gets an external_account file and the ARM_* variables the google and azurerm providers read, with a token for the audience of each cloudproven
comment-applya comment on a merged pull request re-runs its apply from the merge commit, applies a wave under approval: sealed only once its approval is sealed, and refuses an open pull request and a commenter with no write accessproven
comment-agenta /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 nothingproven
review-agentwith 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 nothingproven
review-policya 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 waveproven
wave-reportthe report of a tf-apply wave behind a gate says waiting and links the ledger that holds its record, and approved once an approval of its digest standsproven
policy-delete-keya pull request that deletes the policy key from terragucci.yml and adds a change the policy denies still fails tf-plan, checked against the policy of the base branchproven
report-oidcwith no static keys, the plan job writes its report to the bucket as the role it assumes with its OIDC token through STS, and the index lists the runprovenproven
tg-gate-waita Terragrunt wave waits for an approval of its set digest, and once approved applies its saved plans while the next wave waits at its own gateproven
tg-gate-refusea Terragrunt wave whose plans changed after approval applies nothing and names the unit that movedproven
tg-sealedunder approval: sealed a Terragrunt wave counts only an approval sealed by a key the signers file listsproven
pr-applywith apply.when: pull-request, a comment on an open and approved pull request applies its head in waves and then merges it with apply.merge: autoprovenprovenproven
pr-apply-locka 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 unlockprovenproven
pr-apply-stalea comment on an approved pull request whose head is behind the default branch is refused as not up to date, and nothing appliesproven
tg-comment-applya comment on a merged pull request in a Terragrunt repo re-runs its waves of units from the merge commit, applies a wave under approval: sealed only once its approval is sealed, and refuses an open pull requestproven
provider-callswith binary: choudoufu the report lists the slowest provider calls of a root, each with its method, provider and resource type, from the provider call spans choudoufu sendsproven
summed-timingswith binary: choudoufu past its span budget the report lists the timings choudoufu summed by resource type, and the note of the root says it summed themproven
foreign-checkouta job that runs as root in the CI image on a checkout another user owns, with no git setting of its own, plans only the roots a change touchesproven
tg-layersa Terragrunt repo of three units in a chain goes out in three waves, one job each, every wave waiting for an approval of its own set digest before it appliesproven
atmos-wavesinit names one root per Atmos instance, <stack>/<component>, from atmos describe stacks, and cuts a wave per layer of dependencies.components: each dependent instance applies in the wave after its dependency, behind its own gateproven
atmos-workspaceeach 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 applyproven
atmos-affecteda pull request that changes one Atmos instance plans that instance and the instances whose dependencies.components name it, and no otherproven
atmos-from-planan Atmos wave whose plans changed after approval applies nothing and names the instance that moved; once its new plans are approved it applies the plans whose digest was approvedproven
atmos-upstream-waitan Atmos instance whose stack reads an unapplied instance with !terraform.state is held back, never planned on a stand-in, and applies on the output of the upstream once it has appliedproven
atmos-checkthe check job of an Atmos repo runs atmos validate stacks before it writes the instances, and fails on a manifest Atmos refuses, with the error Atmos givesproven
atmos-versionatmos.version in terragucci.yml is the Atmos release every job installsproven
terramate-wavesinit takes the stacks of a Terramate repo as roots and cuts a wave per layer of their order: a stack after a tag or before another applies in the wave its order gives it, behind its own gateproven
terramate-affecteda pull request that changes one Terramate stack plans that stack and the stacks whose after or before put them after it, and no otherproven
terramate-pr-apply-lockwith apply.when: pull-request in a Terramate repo, a pull request applied on a comment locks the stack it changes, and a second pull request that changes that stack is refused with the stack and the holder named, its state left as the first applied itproven
terramate-sharinga Terramate stack whose input block reads an output of an unapplied stack is held back, never planned on the mock, and applies on the output of the upstream once it has appliedproven
terramate-stalethe check job of a Terramate repo fails on stale generated code, naming the file terramate generate would changeproven
atmos-rolesoidc.roles by stack glob gives the instances of each Atmos stack roles of their own: config check lists each role with the states of its stack, and each instance plans and applies as the role of its stackproven
atmos-pr-apply-lockwith apply.when: pull-request in an Atmos repo, a pull request applied on a comment locks the Atmos instances it reaches (every instance, for a change to a stack manifest), and a second pull request that changes one is refused with the instance and the holder named, its state left as the first applied itproven
atmos-refuseconfig check and init refuse the drift pull request of an Atmos repo in the same words, about the vars of the stack, never synth; respond tips proposes lock files for the components and a canary of instancesproven
policy-sourcea project of a control repo with no policy directory is checked against the shared policy source the control repo defaults name, at its pinned refproven
reconcile-parallelisma project of a control repo plans with the parallelism its defaults set: reconcile writes the key into the terragucci.yml of the project, and the plan job reads it thereproven
provider-projectthe terragucci provider, applied with tofu, writes a project and the defaults into the terragucci.yml of a control repo, plans show a changed setting, and reconcile gives the project its pipeline with the settingproven
pr-requireswith apply.requires: [approved] an approved pull request behind the default branch applies from its head, the default requirements refuse it as not up to date, and a pull request that conflicts with the default branch is refused as not mergeableproven
pr-lock/terragucci lock on an open pull request locks the roots it reaches and applies nothing, and a second pull request that reaches one is refused with the root and the holder namedproven
front-doorthe front door template puts CloudFront in front of the private reports bucket at its own domain, reads the bucket through Origin Access Control and runs the sign-in check on every viewer requestproven
ledger-defaultwith no approval key a wave counts an unsigned approval of its set digest, init declares no gate, and the waiting wave prints the approval command without --signproven
approval-at-basea merge that switches approval from sealed to ledger is judged by the sealed rule of the commit before it, and the next merge by ledgerproven
sealed-migratea repo whose chant.workspace.json lists the wave gates and whose config names no approval mode stays sealed, and the wave and config check say soproven
estateterragucci estate writes one page to the reports bucket from the index of every project: three projects, a waiting wave with its age and a drift, with a presigned link to the pageproven
behold-viewthe behold step of the estate job reads the reports from the bucket and publishes the view of the commit under views/behold/<commit>/ with latest.json and history.json naming it, and headless Chrome, opening views/behold/ from the bucket, draws the drift the drift check found on the card of the deleted queueproven
behold-servebehold serve, given the checkout and the reports bucket, draws both roots, marks the queue deleted outside Terraform with the time the drift check finished, gives the terragucci approve line of the waiting wave and refuses a deploy, and refuses a corrupted index.jsonproven
terragucci-viewterragucci view, reading the bucket and project from terragucci.yml, starts the pinned behold, which draws both roots, marks the queue deleted outside Terraform with the time the drift check finished and gives the terragucci approve line of the waiting wave, and stops on SIGTERM; a corrupted index.json stops it with one lineproven
drift-overduethe plan of a pull request says in its note that drift checks are overdue when the drift schedule has come round twice with no drift runproven
pr-reviewwith approval: pr-review a pull request approved on its head by a writer other than its author merges, and its gated wave applies with no chant approve, recorded on the ledger as via pr-reviewproven
pr-review-movedwith approval: pr-review a wave whose plans changed between the review of the head and the merge applies nothing and prints the chant approve command for its new digestproven
pr-review-statuswith approval: pr-review terragucci/approval on the head of a pull request is pending while a wave waits, and success once a writer other than the author approves the headproven
cdf-concurrencywith binary: choudoufu two tf-apply waves of one estate that change different resources run at once, both reach their record write together and both apply, with no lock wait and no lock objectproven
cdf-concurrency-timewith binary: choudoufu two tf-apply waves of one estate, each adding a resource whose apply takes 60 seconds, finish both resources in under 90 seconds: the second wave starts while the first is applying and does not wait for itproven
cdf-write-racewith binary: choudoufu two tf-apply waves of one estate that change the same resource at once: one lands, the other fails its conditional write naming the resource and overwrites nothing, and its re-plan shows the value that landedproven
cdf-killed-recordswith binary: choudoufu a tf-apply wave killed after the apply of one resource returned, while the next one applies, leaves a record for the first and none for the second, and the next plan creates the second onlyproven
cdf-resumewith binary: choudoufu a gated wave killed after its approved apply of one resource returned is found by terragucci resume, and the wave run again applies only the other resource under the same approval, with no new oneproven
cdf-live-progresswith binary: choudoufu while a tf-apply wave applies, its run view and its progress.json show the resource whose apply returned done and the slow one after it in flight, read from the record storeproven
cdf-iamwith binary: choudoufu a role granted one estate by its ownership tag applies a change to that estate, and IAM refuses it a change to an instance of another estateproven
apply-per-roota second push applies one root while the wave of the first push is still applying another: no apply job waits for another run, and the state lock of the backend keeps the applies of one root apartproven
apply-stand-downa wave of a push whose commit is no longer the tip of main stands down once the newer push has landed: it applies nothing, its terragucci/apply says superseded by a newer push, and the newer push applies the rootproven
cdf-rows-overlapwith binary: choudoufu two pushes whose plans change different resources of one estate apply at the same time: each wave holds the resource it changes, both reach their record writes together, both apply, and no row is left heldproven
cdf-rows-waitwith binary: choudoufu two tf-apply waves change the visibility timeout of one SQS queue on floci: the second waits for the first and makes no call while the call of the first is in flight, as the request log of the emulator shows, then plans again and applies its valueproven
cdf-driftwith binary: choudoufu a queue changed outside choudoufu on a root under live resource markers is drift: tf-drift plans the root in full, its report and one drift issue name the root and the attribute, and a run with no change closes the issueproven
cdf-rows-takeoverwith binary: choudoufu a wave killed after its change landed, while it held the queue it changes, leaves its row held; the wave of the next push takes it over with nothing unlocked, and the re-read of its apply refuses the plan the killed run made stale before any callproven
resume-approveterragucci approve, given a forge token of the approver, resumes the waiting wave of a merged pull request, which applies with nothing else doneproven
resume-schedulewith apply.resume set, a run of the resume workflow applies a waiting wave once an approval of its digest is on chant/lifecycleproven
approve-planterragucci approve --plan with a digest the plans moved past approves nothing, exits 1 and names the digest waitingprovenprovenproven
approve-commandthe plan note of a pull request gives the chant approve command with the digest its gated wave asks for after the merge, and terragucci approve in a checkout approves that wave with no digest copiedproven
tg-pr-applywith apply.when: pull-request in a Terragrunt repo, a comment on an open and approved pull request applies its waves of units from its head and then merges it with apply.merge: autoproven
tg-pr-apply-lockin a Terragrunt repo, a pull request that changes a unit whose dependencies block names a unit another open pull request applied is refused with the unit and the holder namedproven
plan-lockwith locks: plan a pull request locks the roots it reaches from its first plan, a second pull request that reaches one gets a failing terragucci/lock and a reply naming the root and the holder, and after /terragucci unlock its /terragucci plan takes the lockproven
plan-lock-releasewith locks: plan the merge of a pull request releases the lock its first plan tookproven
plan-lock-fmtwith locks: plan a pull request whose push the fmt job formats, with a push that starts no run, has its lock answered on the formatted headproven
policy-overridea tf-apply wave the policy denies applies once an approver listed under policy.override at base overrides its plan with terragucci override, and its report names the override with who, the rules, the reason and the plan digestprovenproven
policy-override-movedan override of an earlier plan digest counts for nothing: once the root plans another digest the wave applies nothing and exits 4proven
policy-override-unlistedan override by someone policy.override at base does not list counts for nothing: the wave applies nothing and names whyproven
policy-override-appliedonce a wave applied a root under its override, the next plan of that root the policy denies is recorded as a new denial and waits for its own override, and only an override no wave applied refusesproven
blob-azurewith reports.bucket az://<account>/<container> and only the Azure OIDC identity of the job, tf-plan writes the report and both indexes to Azure Blob Storage, and terragucci estate writes the page there and prints a user delegation SAS that serves itproven
blob-gcswith reports.bucket gs://<bucket> and only the GCP OIDC identity of the job, tf-plan writes the report and both indexes to GCS through its JSON API, and terragucci estate writes the page there and prints a V4 signed URL that the service account signedproven
note-diffthe plan note on Forgejo shows the diff of a group as the binary prints it, with the value before and after of the attribute that changes, and the whole plan of the root in a collapsed blockproven
note-splita plan over the comment limit of the forge stays one note within the limit: the largest whole plan is left out and named in a Cut line that links its plan.txt, and the rest staysproven
note-report-linkwith reports.bucket set and no reports.url, the plan note links report.html and each plan.txt in the bucket by presigned links, which open from flociproven
config-tsinit writes the pipeline from a terragucci.ts folded as data, and config check refuses a terragucci.ts that reads process.env at its lineproven
role-refusedconfig check and init refuse an oidc block that names one role for plan and applyproven
description-checkwith 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.jsonproven
decide-backendsdecide.backend von, decider and jev each answer the description check through the same client, each pinned to its model, jev with its bearer token from token_envproven
otlp-headerstelemetry.headers_secret maps the collector key into the jobs, spans reach a collector that wants it, and a collector that does not answer leaves the plan greenproven
pinned-installa pinned binary version the image does not carry is installed in the job and checked against the SHA256SUMS of its releaseproven
generateterragucci generate writes the backend, provider and version files of each root from the repo, directory glob and root levels of terragucci.yml, a changed global reaches the backend file of every root, and tf-check refuses a hand-edited generated fileproven
tg-generatein a Terragrunt repo terragucci generate writes terragucci.hcl from terragucci.yml, the check step passes it, and each unit that includes it applies with the backend key and provider settings generate gives it, while a unit that does not include it is refused by nameproven
tg-generate-initwith generate.disable_init: false terragucci generate writes disable_init = false in the remote_state of terragucci.hcl, the check step passes it, and the apply job has Terragrunt create the missing state bucket and applies into itproven
root-pinstwo roots of one wave plan on two OpenTofu versions, the one the .opentofu-version of a root pins, installed in the job and checked against its SHA256SUMS, and the one in the image, and the report and the plan note name the binary and version of each rootproven
drift-closea drift run that finds no drift closes the drift issue an earlier run openedproven
estate-controlterragucci estate in a control repo reads each project from its own bucket with its own reports.role and writes one page to the bucket under defaultsproven
estate-overridethe estate page counts the roots applied under a policy override, in estate.json and estate.htmlproven
reader-contractsthe index.json files, estate.json and report.json a run and terragucci estate write to the bucket hold to the JSON Schemas the package ships, and a project named views writes nothing under the prefix kept for viewersproven
comment-refuseda comment naming approve, merge, destroy, import, state or force-unlock is answered that a comment never runs it, and nothing plans or appliesproven
note-stalea push to the default branch that changes a root an open pull request planned marks its plan note staleproven
pr-confirmwith apply.when: pull-request the push of the merge commit runs confirm, which plans every root, posts terragucci/apply success and applies nothingproven
pr-base-configwith apply.when: pull-request a pull request that sets gate: never still waits at the gate of the default branchproven
pr-guardwith apply.when: pull-request a pull request that changes the pipeline file, or whose checks failed, is refused and applies nothingproven
pr-close-releasewith apply.when: pull-request closing a pull request releases the roots it lockedprovenproven
tg-lock-fanoutin a Terragrunt repo a change to root.hcl locks every unit and says why, and a Markdown-only change locks noneproven
token-scrubthe binary tf-plan starts gets no forge token by name or by value, and a TF_ variable passes as setproven
plan-token-freethe plan and re-plan jobs run the code of a pull request with no forge token variable in its environment or that of its parent processes and no credential in the checkout, and the note jobs still post the note and terragucci/planproven
fork-no-plana pull request from a fork runs check and no plan jobproven
highlight-sensitiveIAM, security group, KMS and DNS changes are open with their reasons, and an import and a forget are named, the forget not counted as a destroyproven
approval-revokeremoving an approval line from chant/lifecycle makes its wave wait againproven
pending-expirya pending fact past its 48 hours is recorded afresh by the next run of its waveproven
signer-trustinit --signer writes the signers line from git config user.signingkey, .chant/trust.json moves the signers file, and a sealed approval verifies against itproven
rollout-controlfrom a control repo a module rollout opens wave 1 as one pull request per project for its canaries, then each project in turn, each wave once the last appliedproven
rollout-providerrollout --provider moves that provider alone in the lock file and its exact constraint, one pull request per waveproven
rollout-pinsrollout moves an oci:// tag and a registry version pin, each in the shape it hadproven
rollout-continuewith rollouts set, once wave 1 merged and applied the rollout job opens wave 2 with no manual runproven
policy-opawith policy.engine: opa a tf-apply wave the policy denies applies nothing, and its report keeps the denial and the warningsproven
policy-hcpwith policy.input: hcp an HCP Terraform policy reads input.plan and input.run and denies the waveproven
policy-hclwith a policies.hcl a mandatory policy denies the wave and an advisory one warnsproven
tg-policyin a Terragrunt repo a unit the policy denies fails tf-plan, and its wave applies nothingproven
tg-credentialsin a Terragrunt repo each unit assumes the plan role of the first glob its path matches, and a unit with its own iam_role keeps itproven
tg-dependentsterragrunt.dependents: plan previews the dependents of a change provisional and outside every digest, and terragrunt.exclude leaves a unit outproven
tg-previewa pull request previews the later layers of a Terragrunt change: a unit is planned on the planned outputs of its upstream, and one that reads a value known only once its upstream applies is named with that value and wave, never planned on a stand-inproven
tg-preview-gatea Terragrunt wave whose plan differs from the preview of it in the pull request says so at its gate, naming what moved, before anyone approvesproven
tf-terraformwith binary: terraform the pipeline runs in the terraform image, check and the plan pass, and a wave waits for its approval and then applies with Terraformproven
tg-terraformin a Terragrunt repo with binary: terraform the pipeline installs Terraform and Terragrunt applies every unit with itproven
tfquery-importwith binary: terraform a root with a .tfquery.hcl gets the drift pull request with the config terraform query generated for what it listsproven
alerts-firewith short thresholds every alert init writes fires on its signal, and the apply-success and drift-corrected SLOs recordproven
blob-gcs-keywith a service_account key file the job writes the report and both indexes to GCS, and the estate link is signed with the keyproven
blob-azure-keywith AZURE_STORAGE_KEY the job writes the report and both indexes to Azure Blob Storage, and the estate link is a SAS signed with the account keyproven
index-writestwo plan runs that write one index at once both land in it, and a store that answers 501 to a conditional write gets the row without the conditionproven
note-footerthe plan note on a pull request ends with the terragucci footer, Forgejo renders its taco image, and the image answers 200 with a PNGprovenproven
replan-dispatcha workflow_dispatch of the plan workflow with pr set re-plans that pull request: the replan job posts a new terragucci/plan status on its head and updates the same plan note, and Forgejo refuses the dispatch of a user with read access onlyproven
cdf-shared-bucketwith binary: choudoufu one tf-apply wave applies two estates into one record store bucket, each under its own prefix and estate tag, and the next plan of both shows no changeproven
cdf-migratewith binary: choudoufu a migration moves a resource between two estates by rewriting its ownership tags: proved by both plans, approved by digest, after which the next plan of both shows no change and the move is on chant/lifecycleproven
cdf-adoptwith binary: choudoufu a migration adopts a root on s3 state into an estate: proved against the live system, approved by digest, its resources stamped with no change, and its old state left as the version it wasproven
cdktn-synthwith synth set to npx cdktn synth the pipeline synthesizes the CDK Terrain stacks before check, apply and tf-plan, and tf-plan plans the stack the change reachesproven
apply-outcomestage tf-apply writes how its wave ended to TG_OUTCOME_JSON as terragucci.outcome/v1: waiting with its digest, mode and approve command, refused with the digest approved and the root that moved, and failed with the rootproven
auditterragucci audit writes one record to the bucket: every approval on the ledger with its approver, digest and time and who relayed it, the request, and the apply that names its approval; --check passes and the estate page links the audit pageprovenprovenproven
audit-overridethe audit record keeps a policy refusal after its report is replaced, and holds the override with its reason and rules and the apply under itproven
audit-refuseda wave whose plans changed after approval is in the audit record as refused, with the approver, the digest approved and the root that movedproven
audit-controlterragucci audit in a control repo fetches each project ledger from its url and reads each project reports into one recordproven
inventoryafter two apply waves of the example roots the estate page lists every resource of each root by address, type and provider, with the count of each type, and no valueprovenprovenproven
estate-graphthe estate page draws the example roots by wave with an edge for each state the example reads and an edge from a root of another project that reads one, and the run view shows the blast radius of wave 1 and a timeline of the plan, gate wait and apply of each waveprovenprovenproven
resource-historyone resource changed by three approved applies has a history that lists the three in order with their approvers from the audit trail, linked from the estate page, and no valueprovenprovenproven
query-sqlterragucci query, run on the reports bucket with no server, answers the SQS queues changed in the last 7 days with their approvers with the rows the audit trail holdsproven
state-versionsa 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 contentproven
state-roleswith oidc.roles each environment root plans and applies as the role of its own environment, config check lists the state key of each role, and it warns when a prod root reads the dev stateproven
state-exportterragucci 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 bucketproven
gcs-statea root whose state is in a bucket on fake-gcs-server with object versioning applies twice, each wave naming the generation it left, and terragucci state export writes the first generation once someone else approved the requestproven
azurerm-statea root whose azurerm backend on Azurite takes snapshots applies twice, each wave naming the snapshot it took of the state blob, and terragucci state export writes the first snapshot once someone else approved the requestproven
gcs-unlockterragucci unlock-state reads the lock a killed apply left on a gcs backend, by the generation of the lock object, and releases it only after an approval of that lock, recording who released itproven
azurerm-unlockterragucci unlock-state reads the lease a killed apply left on an azurerm state blob, with the lock info in its metadata, and releases it only after an approval of that lock, recording who released itproven
blob-migratea migration moves a resource from a root whose state is on GCS to one whose state is on Azure Blob Storage: approved by digest, written under the lock object and the blob lease, and each version before and after recordedproven
cloud-roleswith oidc.gcp.roles and oidc.azure.roles, the roots of each environment plan and apply with the service account and the client of their glob, from the exports of the pipeline, and never the identity of the jobproven
state-edgesthe estate page lists a root that reads the state of another with its last plan against the last apply of the producer: stale after the producer alone applied, current once the consumer planned againproven
migrate-resumewith apply.resume set, a migration that waits in wave 1 of a Forgejo run is approved with terragucci approve and no argument, and one run of the resume workflow writes both states and applies, with nobody running wave 1 againproven
migrate-backenda migration moves the state of a root to a new bucket: proved with no change, approved by digest, written under both lock files, the old state left where it was, and both versions recordedproven
migrate-backend-tfea migration moves the state of a workspace from a TFE API, the protocol of the remote backend, to a bucket: read through discovery, proved with no change, approved by digest, written under the workspace lock, the versions of the workspace left as they were, and the version it read recordedproven
migrate-backend-pga migration moves the state of a root between two pg backends: read with state pull, proved with no change, approved by the digest of its contents, written by the binary under the advisory lock, the old row left as it wasproven
migrate-backend-k8sa migration moves the state of a root between two kubernetes backends: read with state pull, proved with no change, approved by the digest of its contents, written by the binary under its Lease, the old Secret left as it wasproven
migrate-backend-consula migration moves the state of a root between two consul paths: read with state pull, proved with no change, approved by the digest of its contents, written by the binary under its session lock, the old key left as it wasproven
migrate-backend-httpa migration moves the state of a root between two http backend addresses: read with state pull, proved with no change, approved by the digest of its contents, written by the binary under the lock of the server, the old state left as it wasproven
migrate-revertterragucci migrate revert writes the migration that puts back the states a split wrote, and once approved it restores each state to the version the split recorded before, refused when a state moved past the version the split leftproven
migrate-resume-neverwith gate: never and apply.resume set, init still writes the resume workflow, and one run of it applies an approved migration that waits in wave 1proven
migrate-splita migration file splits one root into two: the plan proves it with no change, wave 1 waits for its digest, and once approved writes both states under their locks with no change, recording each version before and afterproven
doraterragucci estate computes the four DORA metrics from the audit trail and the indexes into dora.json and the estate page: deployments, lead time with the share at the gate, a change failure rate counting a failed apply and an applied wave that drifted, and the time to restore eachproven
notify-chatwith 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 itproven
notify-webhookwith 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 commandprovenprovenproven
cost-estimatewith cost set, the plan note of a pull request gives the monthly cost change of each root and the total, from the estimator run with the key the plan job gets from its secretproven
cost-gatewith cost.approve_above set, a wave whose monthly change is over the amount waits for an approval under gate: never, its log naming the change, the amount and the commit read, and the plan note of a pull request sets the change of each wave against the amount at baseprovenprovenproven
cost-policywith cost set, an HCP Terraform policy set reads the cost of the root from input.run.cost_estimate and of its wave from input.cost, and its mandatory policy denies the waveproven
approval-usedonce a wave applied under its approval, the next merge that moves its plans waits with the approve command for the new digest, and only an approval of plans that never applied refusesproven
cdktn-affectedwith synth set a pull request that changes one CDK Terrain stack plans that stack alone, and the plan note says how many stacks were unchangedproven
cdktn-applywith synth set each apply wave synthesizes the CDK Terrain stacks and applies its stack behind the gate: dev once wave 1 is approved, prod once wave 2 isproven
cdktn-pr-apply-lockwith synth and apply.when: pull-request, a pull request applied on a comment locks every CDK Terrain stack, since its change to the app can reach any, and a second pull request that changes a stack is refused with the stack and the holder named, its state left as the first applied itproven
cdktn-tipswith synth set the tips job synthesizes the CDK Terrain stacks and opens the canary tip, and says the pin and lock file tips are left outproven
cdktn-migratea migration moves a resource between two CDK Terrain stacks, whose roots are cdk.tf.json: tf-plan proves it with no change, wave 1 waits for its digest, and once approved writes both states under their lock filesproven
cdktn-refusedwith synth set init refuses the drift pull request and rollouts as config errors saying why, and with respond.drift: attribute the drift job runs no pull requestproven
apply-brancheswith apply.branches mapping release to canary/*, a push to main applies the fleet roots behind the gate and never canary/one, and a push to release applies canary/one alone, waiting at the same gate until its wave is approvedproven
apply-branches-driftwith apply.branches mapping release to canary, the drift run on main plans canary from release, the branch that applied it, and finds no drift where planning it from main would read the state release left behind and report a false driftproven
own-jobs-keptwith own_jobs naming a file of jobs in terragucci.yml, init run twice keeps the job in the Forgejo pipeline as the file has it, and the job runs after the check job and passesproven
wave-jobswith waves.jobs: 2 a wave of four roots waits at one gate in its own job, and once approved applies in two share jobs of two roots each, under one approval used onceproven
steps-before-plana step before plan writes a file the plan reads, read from terragucci.yml at base, and the plan note lists the stepproven
steps-stopa step before apply that exits 1 fails the wave job before anything appliesproven
steps-gatea step with on_failure approve that fails holds its wave at the gate under gate never, and an approval of the digest applies itprovenprovenproven
tg-cost-gatewith cost.approve_above set, a Terragrunt wave whose saved unit plans are priced over the amount waits for an approval under gate: never, while a wave within it appliesproven
tg-steps-gatea step after plan with on_failure approve runs in the unit its glob picks after the run --all plan of the wave, holds the Terragrunt wave at its gate under gate never, and an approval of the digest applies itproven
tg-wave-jobswith waves.jobs: 2 a Terragrunt wave of two units waits at one gate in its own job, and once approved each share job plans and applies its own unit with run --all --filter, under one approval used onceproven
tg-respond-fmtin a Terragrunt repo the fmt job runs terragrunt hcl fmt after a branch fails its check and pushes the formatting commit to the branch, and nowhere elseproven
tg-state-versionsa Terragrunt unit whose state is in a versioned S3 bucket applies twice, its backend read from its remote_state block, and the estate page lists both state version ids newest first, each one the bucket holdsproven
tg-drift-pra drifted Terragrunt unit gets a pull request that writes the live value into its own terragrunt.hcl inputs and leaves the module its units share aloneproven
tg-drift-attributewith respond.drift: attribute in a Terragrunt repo, tf-drift lists who changed each drifted attribute under its unit in the drift issueproven
tg-migrate-splita migration file moves a resource from the state of one Terragrunt unit to that of another: the plan proves it with no change, wave 1 waits for its digest, and once approved writes both states under their locks, recording each version before and afterproven
tg-root-pinsthree Terragrunt units of one wave plan with their own releases: the tofu the .opentofu-version of a unit pins and the Terragrunt its terragrunt_version_constraint pins, each installed and checked in the job, and the releases of the image for the third, and the report names eachproven
tg-choudoufuin a Terragrunt repo with binary: choudoufu the jobs run in the choudoufu image with Terragrunt installed beside it, and every unit plans with choudoufu through TG_TF_PATHproven
tg-estate-graphin a Terragrunt repo the plan note gives the blast radius of a changed unit through the units that depend on it, and the run view and the estate graph hold each unit by wave with an edge for each dependency blockproven
tg-state-exportterragucci state export of a Terragrunt unit prepares it through Terragrunt, asks for the version of the state its remote_state block names, and once someone else approved it writes that version on the machine of the person who asked, recorded on chant/lifecycleproven
tg-apply-brancheswith apply.branches mapping release to live/canary/*, a push to main applies the fleet units behind the gate and never live/canary/one, and a push to release applies live/canary/one alone, waiting at the same gate until its wave is approvedproven
tg-stacksthe units of an explicit stack are generated before discovery, cut into waves by their dependencies, and applied in order from a checkout that holds none of themproven
tg-stack-checkthe check job of a Terragrunt repo generates its explicit stack and validates the generated units, failing on a unit whose template reads a value the stack file does not feed it, and naming that unitproven
tg-stack-affecteda pull request that changes one value in a terragrunt.stack.hcl plans only the unit that value feeds, says so, lists the unit that depends on it as waiting, and the report and note name the stack fileproven
tg-stack-gatethe waves of the units of an explicit stack wait at their gates: the first unit applies only once its wave is approved, and the unit generated beside it waits at its own gateproven
tg-stack-drifttf-drift from a checkout that holds no generated unit generates the explicit stack, reports the resource deleted outside Terraform under its generated unit, and names the stack file that unit comes fromproven
chat-approvea 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 waveproven
chat-approve-lambdathe relay built as the AWS Lambda function of the guide, run under the Lambda runtime interface emulator, takes a signed Slack click as a function URL event and records the approval of that digest as the mapped principal; the resume workflow then applies the waveproven
chat-approve-teamsa Teams reply that approves a waiting wave, signed as an outgoing webhook signs it, reaches the relay, which maps the Teams user to their principal in the signers file and records the approval of that digest as them; the resume workflow then applies the waveproven
chat-replanwith notify naming a Slack webhook, a drift run that finds drift posts the drifted root with a Re-plan button that opens the drift workflow, which runs on workflow_dispatchproven
linked-plana root that reads the state of another plans in tf-plan on the planned outputs of that root, unknown where unknown, and its wave is marked to plan again once the upstream appliesproven
linked-plan-localtwo roots on the local backend, one reading the other through terraform_remote_state by the same path: terragucci orders them into two waves on its own, and the reader plans on the planned outputs of the writerproven
resource-blasta pull request that changes a queue gets a plan note whose blast radius lists, under the queue, its policy in the same root and the function and mapping that read its ARN in another root, and leaves out the log group that reads only another outputproven
linked-statesafter a pull request changes an output of wave 1, wave 2 plans again once wave 1 applied, shows the new value, and waits for an approval of that plan; the run view in the bucket shows where each wave standsproven
plan-no-locka pull request plan and a drift run plan a root while an apply holds its state lock, and neither waits for itproven
sensitive-redacteda change to a sensitive variable and a sensitive output keeps both values out of the plan note, the report, the job log and every object in the reports bucketproven
provider-cache-oncea wave of eight roots that use one provider downloads it once: the job log names one download and the cache volume holds one copyproven
unlock-stateterragucci unlock-state refuses to release a state lock while a run that began before it is alive, and once the apply that held it is killed releases it only after an approval of its lock ID, recording who released which lock, and the next wave appliesprovenprovenprovenwith binary: choudoufu and a root under live resource markers, terragucci unlock-state finds no state file and no state lock: it says there is nothing to release, runs no binary, asks for no approval and records nothing
tip-moveda resource renamed on a branch plans as a destroy and a create, the plan report tips the moved block, respond tips opens a pull request into the branch that adds it, and once merged the plan moves the resource and destroys nothingproven
mcp-last-applyan MCP client of terragucci mcp, which reads the reports bucket with the credentials of its environment, reads the last apply of a root, and the server lists only read-only tools and refuses an approve call and a token argumentproven
drift-agentwith agent.drift on, a drift run that opens the drift issue runs the stand-in agent with no forge token in its step, and the push job opens a pull request with its change, which plans like any other and is linked on the issueproven
tg-pr-plana pull request on the Terragrunt example, five waves and the tips job below the check job, gets its plan note on Forgejoproven
github-drift-issueon GitHub, a drift run opens the drift issue, and a second run finds it and updates it instead of opening anotherproven
runner-nudgeon the validation stack a job left waiting after the run ahead of it in its concurrency group is cancelled, with nothing running, starts within three minutes: a wait restarts the idle runnerproven
ephemeral-prwith ephemeral naming canary/*, opening a pull request applies its own copy of canary/one under the state key suffixed -pr-<n>, beside the state of the root itself, and closing it destroys the copy through a planned destroy recorded on chant/lifecycle with the reason closedproven
ephemeral-ttlwith ephemeral naming canary/* and a TTL of one minute, a run of the sweep workflow once the TTL has passed destroys the copy of an open pull request through a planned destroy recorded with the reason expiredproven
tg-ephemeral-prin a Terragrunt repo whose remote_state key reads TERRAGUCCI_EPHEMERAL_SUFFIX, opening a pull request applies its own copy of a unit at the key suffixed -pr-<n>, prepared through Terragrunt, beside the state of the unit itself, and closing it destroys the copy on the recordproven
cdktn-ephemeralwith synth set, opening a pull request runs the synth command in its checkout and applies its own copy of a CDK Terrain stack at the key suffixed -pr-<n>, beside the state of the stack itself, and closing it destroys the copy on the recordproven
cdktn-generatewith synth set init and terragucci generate refuse a generate key as a config error that names the CDK Terrain constructs that set a backendproven
cdktn-linkeda CDK Terrain stack that reads the state of another through a remote state data source plans in tf-plan on the planned outputs of that stack, read from its cdk.tf.json, unknown where unknownproven
imagewith image naming an image built from the terragucci image, init writes it into every job of the pipeline and the jobs run in it: check passes, a step prints a file only that image holds, and the root appliesproven
envwith env setting TF_VAR_greeting, init writes it into the pipeline, and the apply job applies the root with that value in its stateproven
local-planterragucci plan run on a machine plans each root its glob names against the applied state: the changed root plans its one change, the others none, and the --json envelope lists them all with exit 0proven
runner-labelwith runner.apply naming a label only a second Forgejo runner serves, init writes it as the runs-on of the apply jobs alone, and the push to main runs check on the runner of the stack and the apply job on the labelled oneproven
pass-secretswith pass naming a repo secret and a repo variable, init writes their names and never their values into the jobs that plan and apply, and the apply job applies the root with both values in its stateproven
mr-widgetthe Terraform widget of a merge request counts the creates, updates and deletes of the plan job report, a replacement as a create and a deleteproven
managed-state-parallelismroots on GitLab-managed state apply at most 3 at once, and the apply job says soproven
report-keyswith the bucket keys in CI/CD variables, which the pipeline maps nowhere, the plan job writes report.json to the bucket and the index lists the runproven
drift-issuethe drift schedule opens one drift issue naming the root and attribute that drifted, updates the same issue when more drifts, and closes it when a run finds noneproven
estate-jobthe estate job of the see-every-project page, pasted into .gitlab-ci.yml and run by a pipeline schedule with only its OIDC token, writes estate.html listing the project to the bucket and prints a presigned linkproven
explain-refusalafter a wave is refused, the explain-refusal job of the agent-refused-wave page runs wave-refused on the wave reports and a stand-in agent prints a summary naming the root whose plan moved, and a branch pipeline still runsproven
gl-commentsthe comments schedule answers a Developer merge request note once across two polls, carrying its marker, and never a non-member noteproven
gl-comment-plana Developer /terragucci plan note starts a merge request pipeline of the same head, whose plan job passes and updates the plan noteproven
gl-protected-tokenwith gitlab.token protected, the merge request plan job holds no token and passes, and the comments job posts its plan note and terragucci/planproven
gl-mr-applywith apply.when pull-request, /terragucci apply starts a pipeline on main with the merge token whose mr-apply applies the head and pr-merge merges itproven
gl-pr-reviewwith approval pr-review, a Developer approval of the merge request lets the merge commit gated wave apply, and the job names the approverproven
gl-wave-jobswith waves.jobs on GitLab a wave waits at one gate, then its share jobs apply their own roots under one approval, used once, and leave no lock behindproven
gl-comment-agenta /terragucci agent note starts a pipeline on main whose agent sees no forge token and whose push job commits its change to the branch, refusing one to the pipeline fileproven
gl-review-agentthe comments job starts a review on main whose note flags an unmentioned destroy with no forge token in reach, and the merged wave policy reads its riskproven
gl-state-versionson GitLab-managed state, each apply wave logs the state address of the root and the serial GitLab holds after it, and GitLab keeps each of those versionsproven
gl-state-exportterragucci state export of a root on GitLab-managed state asks for a serial, and once someone else approved it writes the version GitLab keeps by that serial, recorded on chant/lifecycleproven
gl-unlock-stateterragucci unlock-state reads the lock a killed apply left on GitLab-managed state, waits for an approval of its ID, then releases it on the GitLab lock endpoint and records it, and the next wave appliesproven
gl-ephemeralthe copy a pull request gets of a root on GitLab-managed state lives in the state named with the suffix -pr-<n>, apart from the state of the root, and its destroy leaves that state as it wasproven
gl-state-edgesa root that reads the GitLab-managed state of another through terraform_remote_state by its address applies in the wave after it, with its outputproven
oidcthe merge request plan job holds a GitLab id_token for sts.amazonaws.com naming this project, pipeline and job, for the plan role, and the apply job on main one for the apply role; the token is verified against the keys the lab publishes, not traded with STSproven

The same setup runs on your laptop. The tutorial boots it with one command and walks through each feature.

See CONTRIBUTING.md.

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.