Skip to content
Open the dashboard
Developer docs

Overrides and exceptions

Developers8 min read

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.

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 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.

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.

Overrides can’t change what a rule says or where it applies. To do that:

  1. Copy the standard into .groundrule/standards/. npx @groundrule/cli explain TS-001 shows where it is defined. Every bundled pack is also in the open-source repository.

  2. Give it a new ID, such as ACME-012, and change what you need: scope.paths, scope.exclude, requirement, examples, checks.

  3. Turn the original off with an override, and name the replacement in the reason:

    overrides:
    TS-001:
    disabled: true
    reason: Replaced by ACME-012, which excludes scripts/.
  4. Run npx @groundrule/cli sync and npx @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.

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.json
apiVersion: groundrule.dev/v1alpha1
kind: ExceptionList
spec:
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.

  • 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 when paths includes **.

  • They stay visible. check counts them: ○ 1 finding covered by exceptions (show with --verbose). With --verbose, each one is tagged excepted by EX-1042.

  • Reports keep them. The JSON report sets suppressedBy: "EX-1042" on the finding. SARIF marks it as suppressed, with the justification Groundrule exception EX-1042. The Markdown summary counts N covered by exceptions. See Output formats.

  • Agents still get the rule. Exceptions don’t change agent files.

  • explain lists 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.

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.

A standard can say who approves its exceptions and for how long, in spec.exceptions:

spec:
exceptions:
approvers: [team:security-engineering]
maxDurationDays: 90

explain 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.

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.