Skip to content

Exit Codes

llms.txt lists every page for an agent

chant has one exit-code table (#4553), CHANT_EXIT in @intentius/chant/exit-codes. Every command that plans or applies exits by it, the op-wave jobs and pr-apply included. terragucci and plywood pass the code through unchanged, so a pipeline reads the same number from either product.

CodeNameMeaning
0doneApplied, or nothing to do.
1failedSomething broke, and no approval changes it. Usage and config errors are 1 too.
2driftA run asked to fail on drift (--fail-on-drift, failOn: "drift") found some.
3waitingStopped for a person: a gate, an open decision point, a review that does not count yet, unmet requires, an earlier wave waiting, or no pull request found.
4movedAn approved plan no longer matches the plan that would apply now, so nothing applied. An op-wave job under approvals.preview exits 4 when its plans are not the ones its pull request previewed.
5heldAnother run or open pull request holds a lock on a target or resource this changes, so nothing applied. A run that waited for its row until the job’s deadline (LockWaitTimeoutError) exits 5 too.
6supersededA newer push applies instead.
7deniedThe policy denied the plan and no override counts. The same at plan and at apply.
8declinedA decision point answered with an answer the gate does not pass on.
9misplacedThe apply-job guard stopped the job: it runs somewhere its spec did not set it to run, or its CHANT_JOB_GUARD spec could not be read (#4624). chant ci check-job exits 9 for the same reasons.

--gated-exit <code> remaps 3 and nothing else. A pipeline that routes 7 to the override flow still sees a red job.

A policy that could not run is 1, as is a failure to record the override an apply runs under. On GitLab the op-wave jobs set allow_failure: exit_codes: [1], so 3 to 9 stop the next wave. A refused guard fails its job and stops the waves after it.

The terraform lexicon maps the outcomes of OpenTofu and Terraform, and of choudoufu (terraformExitOf in @intentius/chant-lexicon-terraform). It never sets the process’s code itself: for a moved plan it throws an error core marks as moved, and core exits 4.

Engine outcomeCode
plan -detailed-exitcode 0 or 2the plan’s answer, never a job’s exit. 2 under a drift check is 2
any 11
choudoufu apply <planfile> 3, approval mismatch4
choudoufu apply <planfile> 3, plan made against another estate1: the pipeline handed the wrong file, and no approval fixes that
choudoufu live-wave-apply 3, set moved4
choudoufu live-wave-apply 4 or live-plan-set 4, a root failed1
a composed plan that moved4
live-affected 2, live-cone 2answers to chant’s planner, never a job’s exit

The pulumi lexicon maps Pulumi and plunge codes (pulumiExitOf in @intentius/chant-lexicon-pulumi). Pulumi’s own numbers overlap chant’s with other meanings (Pulumi’s 3 is an authentication failure), so no raw Pulumi code passes through.

Pulumi or plungeCode
00
5, policy violation from a mandatory CrossGuard pack7
7, changes found under --expect-no-changes in a drift job2
plunge 40, a moved or unstamped plan4
a moved preview shape on stock Pulumi4
1, 2 configuration, 3 authentication, 4 resource, 6 stack not found, 8 cancelled, 9 timeout, 10 await, 2551

A Pulumi older than its exit-code taxonomy exits 1 for everything, which maps to 1.

The sql lexicon maps the outcomes of the versioned migration engine, sql-yodeler (sqlExitOf and yodelExitOf in @intentius/chant-lexicon-sql). A refusal that no approval fixes is 1; one a person can clear is 3.

Engine outcomeCode
applied, or nothing pending0
a wave plan that moved, or an approval of another digest4
a policy rule denies the plan and no override counts7
another apply holds the history lock5
a newer commit on the branch applies the same environment6
an apply stopped at its gate, pending migrations under yodel status, a migration the required environment has not applied, a change that needs an Op the engine does not run, a manual step3
drift found by yodel drift2
a checksum mismatch, a fork, an out-of-order migration, an applied migration gone from the directory, reader and writer one identity, a write run with the reader, yodel lint errors1

A yodel on this table passes its code through. An older yodel exits 4 for every refusal and 3 for lint errors, so yodelExitOf with legacy: true reads both as 1. Its 2 stays 2 from yodel drift and is 3 from any other verb.

Three commands report outcomes beyond a plan or an apply, and each maps them onto the table.

Command and outcomeCode
chant workspace records --require attested, a record printed is not attested3
chant workspace work claim, renew or release, lease held by another worker or won by another writer (lease-held, lease-race, lease-push-rejected)5
chant workspace work, lease-not-held or lease-token-mismatch1
chant audit, no audit lexicon installed1

Before this table, a moved plan exited 3 outside op waves; it now exits 4, apart from a gate’s 3. A held lock exited 3 as well and is now 5. A policy denial exited 3 at apply and 1 at plan, and is now 7 at both. chant lifecycle drift refuses a read with 1 in place of 3; its {"refused": ...} line on stdout is unchanged, and chant workspace drift reads that line from a member on either version. An error a lexicon throws with exitCode: 3 still reads as a moved plan for one more release. The three commands in the commands table above each used 2 for their own outcome: records for an unattested record, work for a refused lease and audit for a missing lexicon. Drift owns 2 now.

chant