Lock roots to a pull request
Optional: hand this page to your coding agentThe steps work by hand too.Show the whole prompt
Read https://intentius.io/terragucci/guides/lock-roots/.
Add `locks: plan` to terragucci.yml, run `npx terragucci config check --json` and `npx terragucci init`, and open a pull request with the result.
Tell me the status check to require in branch protection; do not change branch protection yourself.
Never comment `/terragucci lock` or `/terragucci unlock`.
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`.Result
Section titled “Result”Each root an open change reaches is held for it. A second change that reaches a held root is refused, and the reply names the root and its holder.
These holds work across pull requests. The backend’s state lock keeps two writers off one state file while a binary runs, a separate layer (Locking and staleness).
| Setting | Roots are held | Forges |
|---|---|---|
locks: apply (the default), with apply.when: pull-request |
when the change applies before merge, or a writer comments /terragucci lock |
GitHub, GitLab, Forgejo |
locks: plan |
from the first plan, and again on each push or /terragucci plan |
GitHub, Forgejo |
Under the defaults, apply.when: merge and locks: apply, nothing is held.
init and config check refuse locks: plan on GitLab. The hold is taken by a job that runs from the default branch, and no merge request event on GitLab runs such a job. With apply.when: pull-request on GitLab, the comments schedule reads /terragucci apply and /terragucci lock on a merge request and takes the hold.
-
Set the mode in
terragucci.yml:locks: plan -
Check the file and write the pipeline again:
Terminal window npx terragucci config checknpx terragucci initinitadds thepr-lockjob. It runs from the default branch on each event and comment, with no checkout of the change and no cloud role, and reads the change as data from git. -
Open a pull request with the file and the pipeline, and merge it.
-
Require
terragucci/lockin branch protection. Underapply.when: mergethe hold gates nothing by itself; the required status keeps a refused change from merging. -
Open a change.
terragucci/lockpasses and names the roots it holds. A second change that reaches one gets a failingterragucci/lockand a reply naming the root and the holder.
Nothing queues a refused change. Once the holder lets go, comment /terragucci plan on it to take the roots.
Comments
Section titled “Comments”| Comment, by anyone with write access | Does |
|---|---|
/terragucci lock |
holds every root the change reaches and applies nothing; the reply names the roots |
/terragucci unlock |
lets go of the change’s roots; the reply names them |
On GitLab a Developer or above comments, and the comments schedule answers on its next run. Both need apply.when: pull-request or locks: plan.
Release
Section titled “Release”| Event | Held roots |
|---|---|
| the holder merges or closes | released |
/terragucci unlock on the holder |
released |
a push stops reaching a root, with locks: plan |
that root is released |
The holds are kept in _locks/tf-apply.json on chant/lifecycle. A hold whose pull request merged or closed counts as released. A fork’s pull request takes none.
Outside plain roots, a change reaches more than the files it touches:
| Repo | Held |
|---|---|
| Terragrunt | the units it touches and every unit whose dependency or dependencies block names one, followed through; a change outside every unit, such as root.hcl, holds every unit |
| Atmos | the instances of each component it touches and their dependents; a stack manifest or atmos.yaml holds every instance |
synth, such as CDK Terrain |
every stack, for any file but Markdown |
A Markdown-only change holds nothing. Locks has the full rules.
- Release a state lock a killed job left frees a backend’s state lock.
- Plan locks lists what the
pr-lockjob has and never has.
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.