CLI reference
The github-warden binary has six subcommands. reconcile, audit and
report load the policy file (--config) and authenticate the same way; they
differ in what they do with live GitHub state. codeowners, lifecycle and checks read
a chant workspace from disk and touch neither GitHub nor the policy file.
| Subcommand | What it does | Mutates? |
|---|---|---|
reconcile |
Diff desired vs live per cycle, guardrail-check, print the plan (dry-run) or apply it. |
Only with --mode apply. |
audit |
Run chant's posture-audit engine over every repo declared in the config. | Never. |
report |
Run cycles in dry-run, optionally add audit and identity passes, print a compliance snapshot, optionally write a JSON artifact. | Never. |
codeowners |
Generate CODEOWNERS from the members of a chant workspace. | Only the --out file, and not with --check. |
checks |
Print the ruleset that requires each member pipeline's job names as status checks. | Never. |
lifecycle |
Show the chant/lifecycle ledger paths, or print the ruleset that protects the branch. |
Never. |
github-warden --help (or no arguments, or --help after a subcommand)
prints usage; github-warden --version prints the version (inlined from
package.json at build time).
Config file parsing
--config accepts YAML or JSON, decided by extension: .json is parsed as
JSON, anything else goes through the built-in YAML reader (block-style
mappings/sequences, string/bool/number scalars, comments; no flow style, no
multi-line scalars, no anchors). For complex YAML, use JSON. Invalid config
shape exits 2 with the offending field path.
reconcile
github-warden reconcile --config <path> [auth flags] [--mode dry-run|apply]
[--cycles a,b,c] [--allow-guardrail-override]
[--removal-cap-fraction <value>]
| Flag | Default | Meaning |
|---|---|---|
--config <path> |
required | Governance config (YAML or JSON). |
--mode dry-run\|apply |
dry-run |
dry-run prints the plan and changes nothing; apply executes it after guardrails pass. |
--cycles <name[,name...]> |
all | Subset of cycles to run. Unknown names exit 2 and print the known list. |
--token-env <VAR> |
— | Env var holding a pre-minted installation token (auth mode 1). |
--app-id-env <VAR> |
— | Env var holding the GitHub App ID (auth mode 2, with the next flag). |
--installation-id-env <VAR> |
— | Env var holding the installation ID. |
--allow-guardrail-override |
off | Apply even when guardrails trip. |
--removal-cap-fraction <value> |
0.25 |
removalDeltaCap threshold: the max fraction of any one resource type's live managed entries the plan may delete. Must be in (0,1]; anything else exits 2. See the canonical cap description in POLICY.md. |
Deletes come from the policy, not from a flag: a live resource missing from
the policy is planned for deletion only in an org whose policy declares
owned: true (or lists that resource type in owned). Without an owned
declaration, reconcile creates and updates but never deletes. See
the policy reference.
The valid --cycles names (from src/cli/registry.ts): branch-protection,
org-settings, repo-settings, membership, teams, rulesets,
security-features, environments, secrets-variables,
dependency-hygiene, repo-baseline, token-governance, token-approval.
See the cycles reference.
The output prints one === <cycle> @ <org> === block per cycle/org with the
plan; a GUARDRAIL BLOCK: line when a guardrail refused an apply;
Applied: N, Failed: N (plus per-entry FAILED lines) in apply mode;
ERROR in <cycle> lines on stderr for errored cycles; and a DEFERRED cycles
line when the API request budget (1000 requests per run) ran out before every
cycle finished.
audit
github-warden audit --config <path> [auth flags] [--fail-on none|merge-worthy|any]
| Flag | Default | Meaning |
|---|---|---|
--config <path> |
required | Governance config. The audit targets every repo declared under repos. |
--token-env / --app-id-env / --installation-id-env |
— | Auth, same as reconcile. |
--fail-on none\|merge-worthy\|any |
none |
Exit 4 when findings exceed this threshold. |
--help, -h |
— | Print audit usage and exit 0. |
The audit subcommand wraps chant's audit engine (the same checks as
chant audit) and reads private repos with warden's token. With no repos
declared it prints "nothing to audit" and exits 0.
report
github-warden report --config <path> [auth flags] [--cycles a,b] [--audit]
[--identity] [--out compliance.json] [--fail-on none|attention]
| Flag | Default | Meaning |
|---|---|---|
--config <path> |
required | Governance config. |
--token-env / --app-id-env / --installation-id-env |
— | Auth, same as reconcile. |
--cycles <name[,name...]> |
all | Cycles to include (always run in dry-run). |
--out <path> |
— | Write the committable JSON compliance artifact here. |
--audit |
off | Include an audit pass over the declared repos. |
--identity |
off | Include an identity and service-account hygiene pass (App installations vs seat-consuming machineUsers). |
--fail-on none\|attention |
none |
Exit 4 when the report needs attention. |
Report is detect-only; cycles run in dry-run and nothing is mutated.
Auth
Warden authenticates in one of two mutually exclusive modes; --token-env
takes precedence when both are given, and one of them is required (missing
auth exits 2).
- Pre-minted token (
--token-env GH_TOKEN): the named env var holds an installation token, e.g. minted byactions/create-github-app-token. No private key material is needed. Requests go straight tohttps://api.github.comwith that bearer token. - GitHub App (
--app-id-env APP_ID --installation-id-env INSTALL_ID): the App ID and installation ID are read from the named vars, and the private key PEM fromGOVERNANCE_APP_PRIVATE_KEY(orGITHUB_APP_PRIVATE_KEYas a fallback). warden mints a short-lived RS256 App JWT, exchanges it for an installation token, and refreshes it 60 seconds before expiry. A--private-key-envflag is documented in the source but not exposed yet; use the fixed env var names.
Note that a plain PAT passed via --token-env cannot reach the org-level
token APIs: the token cycles (token-governance, token-approval) and
several org administration endpoints are callable only by a GitHub App. See
SETUP.md and the App setup checklist.
Exit codes
| Code | Meaning |
|---|---|
| 0 | Success: the plan printed (dry-run), or apply completed with no failures. |
| 1 | Guardrail block: apply mode, at least one guardrail tripped, and --allow-guardrail-override was not set. |
| 2 | Argument or config error (unknown flag, unknown cycle, invalid config shape, missing auth). |
| 3 | Runtime error (unreadable config file, API failure, an errored cycle, or failed apply entries). |
| 4 | audit: findings exceed --fail-on; report: needs attention with --fail-on attention. |
codeowners
github-warden codeowners --owners <path> [--dir <path>] [--out <path>] [--check]
Generates a CODEOWNERS file with one rule per workspace member directory. The
members come from chant's workspace read contract: the warden runs
chant workspace ls --json (contract 1, chant 0.81.0 or newer) and never reads
chant.workspace.json itself. The chant that runs is the one installed beside
the warden, else chant on PATH.
| Flag | Default | Meaning |
|---|---|---|
--owners <path> |
required | Owners file (YAML or JSON), described below. |
--dir <path> |
. |
Where chant starts looking for the workspace declaration. |
--out <path> |
stdout | Write the file here, for example .github/CODEOWNERS. |
--check |
off | With --out, write nothing and exit 4 when the file differs from what would be generated. |
The owners file names owners by member name, so a member that moves keeps its
owners. Every list must be non-empty and hold @user, @org/team or email
owners.
{
"default": ["@acme/maintainers"],
"members": {
"api": ["@acme/api"],
"docs": ["@acme/docs", "@writer"]
}
}
default becomes a * rule. Each member becomes a rule on its directory,
prefixed with the workspace root when the workspace sits below the git root.
GitHub applies the last matching rule, so shallower directories come first and
a nested member's rule overrides its parent's. A member whose directory is
missing (reason dir-missing) is skipped with a note on stderr. A name in the
owners file that the workspace has no member for exits 2. A failed chant read
exits 3.
lifecycle
github-warden lifecycle --env <environment> [--dir <path>] [--format paths|ruleset] [--name <ruleset>]
Reads chant workspace status <environment> --json, which needs chant 0.81 or
newer. The branch name comes from lifecycle.ref in that document, and each
member's release ledger and gate ledger paths from members[].environments[].ledger.path
and members[].gateLedger.path. Nothing is hard-coded.
| Flag | Default | Meaning |
|---|---|---|
--env <name> |
required | The environment chant reads ledgers for. |
--dir <path> |
. |
Where chant starts looking for the workspace declaration. |
--format paths\|ruleset |
paths |
paths prints the branch and the ledger paths. ruleset prints the ruleset as JSON. |
--name <ruleset> |
chant-lifecycle |
The ruleset's name, its identity key in the repo. |
The ruleset targets refs/heads/<lifecycle.ref> with the rules deletion and
non_fast_forward. The branch can't be deleted and its history can't be rewritten. Appending
commits stays allowed, and that is how chant records releases and gate facts. Put the output under repos.<repo>.rulesets in the policy file and the
rulesets cycle reconciles it like any other ruleset.
checks
github-warden checks [--dir <path>] [--members <a,b>] [--branch <name>] [--name <ruleset>] [--format ruleset|contexts]
The names come from members[].generated[].jobs in chant workspace ls --json
(chant 0.101 or newer). Chant lists each generated file a member owns and, for a
forge CI file, the check names it declares. The warden uses the GitHub workflow
files under .github/workflows/ and prints a ruleset that requires those names
as status checks. A member with no such file, or whose names chant could not
read, is skipped with a note on stderr.
| Flag | Default | Meaning |
|---|---|---|
--dir <path> |
. |
Where chant starts looking for the workspace declaration. |
--members <a,b> |
all | Only these members. A name the workspace doesn't have exits 2. |
--branch <name> |
default branch | The branch the checks are required on. |
--name <ruleset> |
chant-required-checks |
The ruleset's name, its identity key in the repo. |
--format ruleset\|contexts |
ruleset |
ruleset prints the ruleset as JSON. contexts prints each member and its names. |
Add the output to repos.<repo>.rulesets in the policy file. A required name is the job's name, else its
id, which is what GitHub shows as the check.