Overrides and exceptions
You often want a rule from a pack, but not exactly as it is. This page covers the two tools for that in a repository: overrides change an inherited rule for the whole repository, and exceptions excuse specific files from a rule until a date. It also explains how both work when your repository takes its rules from your workspace on Groundrule.
Which one to use
Section titled “Which one to use”| You want to | Use | Where |
|---|---|---|
| Turn a pack rule off in this repository | An override with disabled: true |
.groundrule/config.yaml |
| Make a pack rule more or less severe here | An override with severity |
.groundrule/config.yaml |
| Excuse some files from a rule, for a while | An exception | .groundrule/exceptions.yaml |
| Change a rule’s wording, examples or paths | Your own standard with a new ID, and turn the original off | .groundrule/standards/ |
| Change an organization rule for this repository, its team, or everyone | The rule’s rollout panel | The dashboard |
Overrides and exceptions are files in the repository, so changes to them go through your normal pull-request review.
Overrides
Section titled “Overrides”Overrides change standards your repository inherits through extends (packs, or folders of standards), and your own standards. They go in .groundrule/config.yaml, under overrides, keyed by standard ID:
overrides: TS-001: disabled: true reason: Our CLI prints to the console on purpose; the logger arrives in Q1. SEC-005: severity: blocker reason: Supply-chain policy requires lockfiles everywhere.| Field | Type | Description |
|---|---|---|
disabled |
boolean | true turns the standard off in this repository. |
severity |
info, advisory, warning, blocker |
Replaces the standard’s severity in this repository. Higher or lower are both allowed. |
reason |
string | Why. Optional, but write one: check, standards and explain show it. |
No other fields are allowed. You can’t override a rule’s paths, wording or checks yet.
What an override changes
Section titled “What an override changes”| Override | sync |
check |
standards |
explain |
|---|---|---|---|---|
disabled: true |
Left out of agent files | Not run; counted as not applicable, with the reason Disabled by config override: <reason> |
Listed as (disabled) |
Disabled in this repository: <reason> |
severity |
Written with the new severity | Findings count at the new severity | Shows the new severity | warning (overridden from blocker: <reason>) |
An override for an ID that doesn’t exist is a warning, not an error:
! .groundrule/config.yaml overrides.NOPE-001: Override for unknown standard NOPE-001.Changing a rule’s wording or paths
Section titled “Changing a rule’s wording or paths”Overrides can’t change what a rule says or where it applies. To do that:
-
Copy the standard into
.groundrule/standards/.npx @groundrule/cli explain TS-001shows where it is defined. Every bundled pack is also in the open-source repository. -
Give it a new ID, such as
ACME-012, and change what you need:scope.paths,scope.exclude,requirement, examples, checks. -
Turn the original off with an override, and name the replacement in the reason:
overrides:TS-001:disabled: truereason: Replaced by ACME-012, which excludes scripts/. -
Run
npx @groundrule/cli syncandnpx @groundrule/cli check --all.
You should see your new ID in groundrule standards and the original listed as (disabled). Keeping the same ID instead fails with Duplicate standard TS-001, because two standards can’t share an ID.
The copy no longer receives updates when the pack changes. In a connected workspace, customizing a pack rule in the dashboard keeps upstream updates flowing instead. See Adopting rules.
Exceptions
Section titled “Exceptions”An exception says: this rule doesn’t apply to these files, for this reason, until this date. Use one for code that is right to break a rule (a legacy module on its way out, a test fixture, a vendored file) instead of turning the rule off for everyone.
Exceptions live in .groundrule/exceptions.yaml:
# yaml-language-server: $schema=https://raw.githubusercontent.com/Metricall-AI-Lab/groundrule-oss/main/packages/spec/schemas/exception-list.schema.jsonapiVersion: groundrule.dev/v1alpha1kind: ExceptionListspec: exceptions: - id: EX-1042 standard: ACME-004 paths: ["src/http/refunds.ts"] reason: Legacy refund flow; moves to the gateway in the payments rewrite. requestedBy: maya@acme-payments.test approvedBy: team:payments expires: "2026-12-31" remediation: Move refunds to createRefund in the gateway.| Field | Type | Required | Default | Description |
|---|---|---|---|---|
id |
string | Yes | EX- and a number, for example EX-1042. |
|
standard |
standard ID | Yes | The standard it excuses. | |
paths |
list of globs | No | ["**"] |
Where it applies. At least one glob. |
reason |
string | Yes | Why the code is allowed to break the rule. | |
requestedBy |
string | No | Who asked for it. | |
approvedBy |
string | No | Who approved it. | |
expires |
date | Yes | YYYY-MM-DD. The exception applies through the end of this day (UTC), then stops. |
|
remediation |
string | No | The plan to remove the need for it. |
The file must have apiVersion: groundrule.dev/v1alpha1 and kind: ExceptionList. Every exception needs an expiry: there are no permanent exceptions.
What an exception does
Section titled “What an exception does”-
Findings it covers don’t fail. A finding is covered when its standard matches and its file matches one of
paths. A finding with no file (such as a missing required file) is covered only whenpathsincludes**. -
They stay visible.
checkcounts them:○ 1 finding covered by exceptions (show with --verbose). With--verbose, each one is taggedexcepted by EX-1042. -
Reports keep them. The JSON report sets
suppressedBy: "EX-1042"on the finding. SARIF marks it as suppressed, with the justificationGroundrule exception EX-1042. The Markdown summary countsN covered by exceptions. See Output formats. -
Agents still get the rule. Exceptions don’t change agent files.
-
explainlists them, with a filled dot for an active exception and an empty one for an expired one:Exceptions● EX-1042 src/http/refunds.ts until 2026-12-31 — Legacy refund flow; moves to the gateway in the payments rewrite.
When an exception expires
Section titled “When an exception expires”After its date, an exception stops covering findings, and every command warns:
! .groundrule/exceptions.yaml EX-1001 for SEC-001 expired on 2025-01-01 and no longer applies.Fix the code and delete the entry, or agree a new date and change expires.
An exception for a standard the repository doesn’t have is also a warning: EX-1 refers to unknown standard NOPE-001.
Exception policy on a standard
Section titled “Exception policy on a standard”A standard can say who approves its exceptions and for how long, in spec.exceptions:
spec: exceptions: approvers: [team:security-engineering] maxDurationDays: 90explain shows it as “Approved by team:security-engineering, for up to 90 days.” The CLI doesn’t enforce the policy yet, including allowed: false. Check new exceptions against it when you review the pull request. A CODEOWNERS entry for .groundrule/exceptions.yaml makes sure the right team reviews them.
With a connected workspace
Section titled “With a connected workspace”When .groundrule/config.yaml has platform:, the rules come from your workspace on Groundrule, with every setting the dashboard applies: on or off, stage, severity, and customizations, for the organization, the repository’s team, or the repository. Config changes work differently:
| In the config | With platform: |
|---|---|
overrides for an organization rule |
Ignored, with a warning: TS-001 comes from the platform; change it in Groundrule (for this repository or its team), not in config. |
overrides for your own .groundrule/standards/ |
Applied as usual. |
extends |
Ignored, with a warning: Ignored because `platform` is set: your organization's rulebook decides the packs. |
.groundrule/exceptions.yaml |
Applied to every rule, organization rules included. For an organization rule, the CLI currently also warns EX-1042 refers to unknown standard ACME-004.; the exception still applies. |
To change an organization rule, open it in the dashboard and use its rollout panel. Choose the scope (the organization, a team, or this repository), then turn it on or off (with a reason), set its stage, or set its severity. A team or repository can only be stricter than the organization: a later stage or a higher severity. To loosen a rule for one repository, record an exception, or change the organization’s setting. See Adopting rules and Rollout stages.
The team and repository settings only reach the CLI when the repository is registered in the workspace. Otherwise sync and check warn:
! .groundrule/config.yaml acme/checkout-api isn't registered in acme-payments, so the organization's rules apply. Add it under Teams → Repositories to use its team's settings.The dashboard doesn’t show or manage exceptions yet. They live in the repository.
Related
Section titled “Related”- Configuration: every config field.
- The rule format:
spec.exceptionsandscope. - Checks: narrowing a check before you need an exception.