Skip to content

Exception Approvals

Some checklist items can't simply be marked done — they require a second set of eyes. The Need Exception state captures this.

Who can approve

The approver must be a repo collaborator first. This applies to everyone who uses the checklist editor, not just approvers — GitHub OAuth verifies collaborator access before anything else (see Installation). It's easy to miss when testing: if someone tries to approve and just gets a generic "Forbidden," the most common cause is that they aren't actually a collaborator on the repo yet, before you even get to the team-membership rules below.

The issue opener can never approve their own exception — that's always true, regardless of any team setup.

Warning

The issue opener cannot approve their own exceptions, even if they are a member of the approvers team.

Beyond that, it depends on whether an approvers team has actually been set up:

  • No team created yet: any other collaborator can approve. This is the zero-configuration default — exceptions work out of the box, without requiring you to set anything up first.
  • Team created: once the resolved team (exception-approvers by default, or whatever exceptionApproversTeam is set to) exists in your org, approval is restricted to its members. Being in the team plus not being the opener are both required — being in the team never allows self-approval.

This means approval starts permissive and gets stricter the moment you create the team — you opt into the access control by setting it up, rather than being blocked until you do.

Note

If exceptionApproversTeam is explicitly set (in checklist-app.json or template frontmatter) but that team doesn't exist — a typo, or a deleted team — approval is blocked for everyone, not opened up. Only the unconfigured default falls back to "any collaborator"; a broken explicit configuration fails safe instead of silently granting broader access than intended.

Setting up the approvers team

  1. Go to your GitHub org → Teams → New team
  2. Name it whatever you like — the default the app looks for is exception-approvers
  3. Add members who are trusted to approve exceptions

To use a different team name, set exceptionApproversTeam in .github/checklist-app.json:

{ "exceptionApproversTeam": "security-leads" }

Individual templates can also override this with exceptionApproversTeam in their frontmatter, routing exceptions for that checklist type to a specific team. See the Templates guide for details.

The app reads team existence and membership in real time via the GitHub API, so creating the team — or changing who's on it — takes effect immediately, no redeploy or cache wait.

Approval flow

  1. A collaborator opens the checklist editor and marks an item as Need Exception, optionally adding Requestor notes explaining why the exception is needed
  2. A different collaborator — anyone, until an approvers team exists, then only its members — opens the editor, optionally adds Approver notes, and clicks Approve
  3. The app verifies the approver against the rules above via the GitHub API
  4. If valid, the item transitions to exception with approvedBy set to the approver's GitHub login
  5. The managed comment is updated to reflect the approval

Once approved, the item shows ✅ Approved by @alice in the checklist editor, and the bot comment on the issue is updated to reflect the new state.

Requestor and approver notes

Both notes fields are optional by default and editable by any collaborator — there's no separate approval workflow for the notes themselves. They stay editable until the item is approved, at which point they're locked to keep the audit trail intact.

While an exception is pending, the requestor notes show directly under the item in the checklist comment on the issue — not just in the editor — so an approver scanning the issue can see the reason without opening the editor. Once approved, the comment collapses to just ✅ Approved by @alice; the full requestor and approver notes stay available in the checklist editor and in the underlying state, they just don't keep cluttering the comment indefinitely.

A template can require either note with frontmatter:

---
requireExceptionRequestorComments: true
requireExceptionApprovalComments: true
---

When required, the app rejects a save that's missing the note — requesting an exception without requestor notes, or approving one without approver notes. See the Templates guide for details.

Revoking an exception

An approved exception can be revoked by any collaborator. Revoking resets the item to pending, clearing the approvedBy field. Requestor and approver notes are left in place so the history of what was requested and approved isn't lost.