chant lock
Synopsis
Section titled “Synopsis”chant lock <target>... --pr <n> [--stage plan|apply|lock] [--head <sha>] [--by <who>] [--gate <name>] [--forge github|gitlab|forgejo] [--json]chant lock --from-report <pr-plan.json> --pr <n> [--stage plan] [--head <sha>] [--forge <kind>] [--json]chant lock --list [--gate <name>] [--json]chant unlock --pr <n> [<target>...] [--gate <name>] [--json]A pull request that holds a target lock keeps every other pull request from applying or locking that target until it merges or closes (#4293). A target is any name; the pull-request loop uses the component names that chant components pr-plan selects, and under ci.locks pr-apply checks them. Lock the Targets a Pull Request Reaches sets the jobs up.
The locks of one gate are kept in one file, _locks/<gate>.json on chant/lifecycle (source). The gate is pr-apply unless --gate names another, as in pr-plan and pr-apply, and in a workspace member the file sits under the member’s ledger prefix, _members/<member>/_locks/<gate>.json.
{ "version": 1, "locks": { "net": { "pr": 12, "by": "alice", "at": "2026-10-22T10:00:00.000Z", "stage": "plan", "head": "3f2c..." } }}chant lock locks each target for --pr. When another open pull request holds one of them, nothing is locked and the command exits 3 with each holder named. When the targets are free, it writes the file and pushes chant/lifecycle, and the lock counts only once the remote has it. If the remote refuses the push because another job moved the branch first, chant drops its own commit, reads the branch again and decides again (source), so two jobs that lock one target at the same moment cannot both win. In a repository with no remote, the local write decides.
A target the same pull request already holds stays its own and gets the new head. --stage records how the lock was taken, which decides what happens to the pull request’s own earlier locks (source, source):
| Stage | Taken by | Over the pull request’s own locks |
|---|---|---|
lock (default) | a person running chant lock | takes over its plan locks |
plan | the lock job under ci.locks: plan | keeps its lock and apply locks as they are, and releases its plan locks on targets it no longer reaches |
apply | an apply | takes over its plan locks |
--from-report <file> takes the targets from a pr-plan.json that chant components pr-plan wrote, which means every component in its selection.waves (source). The report’s pr must match --pr, and its head becomes the lock’s head unless --head is given. This lets a lock job that runs the target branch’s code lock what the plan job selected without running the pull request’s code itself.
--forge <kind> asks the forge whether each holder is still open, with the client read from the job’s environment as pr-plan reads it. A lock whose pull request merged or closed then reads as released, and the write that takes it over drops it from the file (source). Without --forge every lock counts as held and only chant unlock releases one (source). Given a head commit as well, the command posts the chant/lock status on it: a success names what the pull request holds, and a failure names who holds what.
--by names who took the lock and defaults to GITHUB_ACTOR, then GITLAB_USER_LOGIN, then USER. The --json form prints { gate, pr, ok, stage, taken, released, expired, pushed }, or { gate, pr, ok: false, held } when a target is held.
chant lock --list prints one line per lock of the gate, in the order of the file’s targets. Each line holds the target and the fields of its lock. The --json form prints { gate, path, locks }.
unlock
Section titled “unlock”chant unlock releases the locks --pr holds on the gate, or only those on the targets named, and exits 0 when the pull request held none. Anyone who can push chant/lifecycle can run it, so a stuck lock never needs a hand edit of the file.
Exit codes
Section titled “Exit codes”| Code | Meaning |
|---|---|
| 0 | locked, listed or released |
| 1 | a usage error, or chant/lifecycle could not be read or pushed |
| 3 | another open pull request holds a target, and nothing was locked (source) |