Skip to content

Get your first plan note

llms.txtlists every page for an agent
Optional: hand this page to your coding agentThe steps work by hand too.
Show the whole prompt
Read https://intentius.io/terragucci/getting-started/ and https://intentius.io/terragucci/getting-started/agents/.
Set up terragucci in this repository.
Run `npx terragucci init --dry-run --json` and show me the findings before writing anything.
Then run `npx terragucci init` and open a pull request with the files it wrote, package.json and package-lock.json only.
Do not create secrets.
Never apply, approve (a pull request review or `terragucci approve`), override a policy denial (`terragucci override`), use `--mode apply`, or merge; never touch `.chant/allowed_signers` or `chant/lifecycle`.
About 10 minutes

CI does this: everything runs as jobs in your CI and lands in your git and your bucket. No account, no sign-in, no platform.

You get Where it is shown
No server to host What runs where
GitHub, GitLab or Forgejo Per forge
Object storage on AWS, GCP or Azure, for state and reports Credentials, Keep reports in a bucket
Tracing and metrics Send traces and metrics
Rich lifecycles Architecture
Gated waves Waves and approvals
Aggregated plan output Plan grouping
Module publishing and pinned rollouts Publish your modules, roll out a version

A pull request with one plan note that groups the roots a change reaches and names every destroy.

You need Why
a repo of Terraform or OpenTofu roots, or a Terragrunt, Atmos, Terramate or CDK Terrain repo, on GitHub, GitLab or Forgejo terragucci reads the roots and the forge from the repo
Node.js 22 or later, on your machine only init is an npm package; the pipeline runs in terragucci’s CI image
a way for CI to read your state and providers the plan job runs plan; see Environment variables and credentials
push access to the repo you commit the generated pipeline
  1. Install terragucci from the root of the repo.

    Terminal window
    npm i -D @intentius/terragucci
  2. Preview what it finds. This writes nothing.

    Terminal window
    npx terragucci init --dry-run
    found 15 roots in 2 layers, tofu 1.13.1 (tofu on the path), forge github (the origin remote (github.com))
    would write .github/workflows/terragucci.yml
    no terragucci.yml needed (defaults fit)
    dry run: nothing was written
    Found Means If wrong
    roots directories with a backend, cloud block, choudoufu live block or provider; in a Terragrunt repo, the units terragrunt find lists --json says why
    layers dependency order, the waves
    binary tofu or terraform and its version; Terragrunt runs it underneath --binary
    forge the origin remote --forge

    If you have a terragucci.yml, run npx terragucci config check first. It names the approval mode and any unknown key, with the keys it accepts. The example’s output:

    $ npx terragucci config check
    terragucci.yml: ok
    approval: sealed (identity.gates in chant.workspace.json here, with no approval key)
    note: set approval: sealed in terragucci.yml to keep sealed approvals, or approval: ledger and run terragucci init to drop the gates
    $ npx terragucci init --dry-run
    found 15 roots in 2 layers, tofu 1.13.1 (terragucci.yml), forge forgejo (.forgejo/workflows)
    unchanged .forgejo/workflows/terragucci.yml
    unchanged chant.workspace.json
    using terragucci.yml
    note: approval: sealed counts only approvals sealed by a key .chant/allowed_signers lists, and there is none yet; terragucci init --signer <your principal> writes it from git config user.signingkey
    dry run: nothing was written
    $ echo 'gates: always' >> terragucci.yml && npx terragucci config check
    terragucci.yml: 1 problem(s)
      config.gates is not a setting (settings: roots, binary, version, forge, url, gate, approval, apply, locks, waves, drift, comments, gitlab, runtime, reports, token_env, env, telemetry, tips, modules, oidc, parallelism, terragrunt, atmos, policy, respond, agent, decide, audit_region, dashboards, synth, steps, image, notify, cost, rollouts, atlantis_comments, generate, review, own_jobs, ephemeral, runner, pass)
  3. Write the pipeline.

    Terminal window
    npx terragucci init
    found 15 roots in 2 layers, tofu 1.13.1 (tofu on the path), forge github (the origin remote (github.com))
    wrote .github/workflows/terragucci.yml
    no terragucci.yml needed (defaults fit)

    The defaults need no terragucci.yml; terragucci.yml keys lists every key.

  4. Give the pipeline a token.

    The jobs use the run’s github.token, so there is nothing to add.

    Cloud roles over OIDC and the required status are in Add terragucci to a repo.

  5. Commit and open a pull request.

    Terminal window
    git switch -c add-terragucci
    git status
    git add -A
    git commit -m "Add terragucci"
    git push -u origin add-terragucci

    git status should list the pipeline files init wrote and the two package files. Put node_modules in .gitignore. Open the pull request, then change a line in one root, since a change that touches no root has nothing to plan.

  6. Read the plan note. The plan job leaves one comment and a terragucci/plan status:

    terraguccicommented on #482 · bump modules/iam to 1.4.0

    200 roots planned. 3 groups, 1 destroy.

    180identical change ~ aws_iam_role.app tags
    15the same, plus -/+ aws_lambda_function.worker
    5different changes, listed one by one below
      # aws_iam_role.app will be updated in-place
    ~   resource "aws_iam_role" "app" {
    ~       tags = {
    -           "team" = "payments"
    +           "team" = "platform"
            }
            # (12 unchanged attributes hidden)
        }
    prod-eu/db: Plan: 0 to add, 1 to change, 1 to destroy.

    The root's whole plan, as the binary printed it.

    destroyprod-eu/db · aws_db_instance.main

    WaveRootsApproval
    13not-requested
    297not-requested
    3100not-requested

    A pull request comment, with the status in the checks box.

    The plan note on a GitHub pull request: one group, its waves table with the set digest, and the change to the jobs queueThe plan note on a GitHub pull request: one group, its waves table with the set digest, and the change to the jobs queue

    The plan report explains each part.

With the default gate, a wave waits for a person only when its plan destroys or replaces something. You approve it from your machine with terragucci approve.

Approval mode Set up once
ledger, the default nothing
pr-review, a pull request review counts approval: pr-review in terragucci.yml; to hold unreviewed changes, require terragucci/approval on GitHub or Forgejo, or an approval rule on GitLab: approve by review
sealed, signed approvals the same, and your ssh public key in .chant/allowed_signers on the default branch before the first change that destroys something: set up the signers file

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.