Skip to content

Track the roots that read other roots' state

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/guides/track-cross-state-edges/.
List the terraform_remote_state blocks in this repo's roots and the root whose state each reads, from the backend blocks, and tell me which reads terragucci cannot match to a root.
Read only. 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`.

A Cross-state edges section on the estate page. It lists each root that reads another root’s state, by producer. Beside each edge are the consumer’s last plan and the producer’s last apply that changed it, and a status.

Status Means
stale the producer applied a change after the consumer’s last plan, so that plan read outputs that have changed since
current the consumer’s last plan is newer than the producer’s last change
unknown no plan of the consumer, or no apply of the producer that changed it, is recorded yet

A consumer goes stale when a change reaches the producer and not the consumer: its wave applies the producer, and nothing plans the consumer again.

A root reads another through terragucci reads
a terraform_remote_state block whose config names the state another root’s backend block names the code of both roots, as it orders the apply waves
a Terragrunt unit’s dependency or dependencies block the unit’s terragrunt.hcl

A read matches a root when both name the same address:

Backend Address
s3, gcs, azurerm bucket and key (prefix for gcs)
local path, resolved against the root’s directory; a root with no backend block keeps terraform.tfstate there
pg the host and database in conn_str, schema_name and table_name
http address, such as GitLab’s .../projects/<id>/terraform/state/<name>
consul address and path
kubernetes namespace and secret_suffix
remote, or a cloud block hostname, organization and the workspace name

Credentials in conn_str or address are dropped from the address.

An address that is not plain strings in the code can’t be matched. This covers an expression such as var.env, a value the backend takes from the environment (PG_CONN_STR, TF_HTTP_ADDRESS, CONSUL_HTTP_ADDR, KUBE_NAMESPACE, TF_CLOUD_ORGANIZATION) or from a -backend-config file, and a workspace picked by tags or prefix. Nothing orders that read, so terragucci names it:

  • terragucci config check warns for each such read, and for each root whose own state has no address when any root reads state.
  • The report lists the read under roots[].unknown_reads and the root under roots[].unaddressed.
  • The plan log and report.html name both.

Write the address in the block to give the read its edge.

A report lists a root’s terraform_remote_state reads as roots[].reads and a unit’s dependencies as roots[].dependencies. Every upload keeps them in the project’s edges.json beside each root’s newest plan run and newest apply wave that changed it. The reads follow the newest plan or apply of the default branch. A pull request’s plan or a drift check moves the consumer’s last plan forward but never changes its reads. Nothing reads a state or an output’s value.

  1. Keep reports in a bucket. From then on, each run’s upload writes edges.json.

  2. Run terragucci estate (its scheduled job also runs it) and open the link it prints.

  3. For a stale edge, plan the consumer again: /terragucci plan <root> on a pull request, or a drift check of the default branch. When the plan changes something, the producer’s new outputs reach the consumer through a change you review.

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.