Documentation

Governance

One governance model, written once and read everywhere: rules become versioned codes that surface locally, in CI, and in Fragments Cloud.

Overview

Governance follows one path: Rules FUI codes Surfaces. You author or enable rules once; each rule emits a stable diagnostic code; and every surface reads the same codes, so the local checks, CI, and Cloud all agree on what a finding means.

Governance is the layer Fragments sells: an enforceable contract over the React code your team and your agents write. The component library is the open-source substrate it governs — useful on its own, but the contract is what keeps a codebase on-system as it grows. To author the contract itself, follow Set up your design contract.

Enterprise wrapper and token example

A confirmed bridge makes the local wrapper canonical, limits direct MUI imports to its implementation file, loads TypeScript and declared-package tokens into one static catalog, and enables the raw-color rule at warning severity. Run fragments identity and fragments doctor --json to inspect the resolved identity and compiler capability before enabling CI.

fragments.config.ts
import type { FragmentsConfig } from "@usefragments/core";

export default {
  "app": {
    "path": ".",
    "include": [
      "src/**/*.{ts,tsx,css,scss}"
    ]
  },
  "components": [
    "src/components/**/*.tsx"
  ],
  "tokens": {
    "sources": [
      {
        "path": "src/theme.ts",
        "format": "auto"
      }
    ],
    "packages": [
      "@acme/design-tokens"
    ],
    "aliases": {
      "colors.brand": "--acme-color-brand"
    }
  },
  "govern": {
    "canonicalBridges": [
      {
        "underlying": {
          "packageName": "@mui/material",
          "exportName": "Button"
        },
        "local": {
          "componentKey": "src/components/Button#Button",
          "moduleSpecifier": "@/components/Button",
          "exportName": "Button",
          "implementationFiles": [
            "src/components/Button/Button.tsx"
          ]
        },
        "decision": {
          "state": "confirmed",
          "source": "authored"
        }
      }
    ],
    "styles": [
      {
        "kind": "style.rawColors.forbid",
        "except": [
          "transparent"
        ],
        "prefer": "token",
        "severity": "warn",
        "exclude": [
          {
            "glob": "src/legacy/vendor/**",
            "reason": "vendor drop, tracked in DS-611"
          }
        ]
      }
    ],
    "rules": {
      "styles/no-raw-color": {
        "enabled": true,
        "severity": "warn"
      }
    }
  }
} satisfies FragmentsConfig;

Intentional one-line exceptions stay attached to the next statement, name the exact FUI code, include a reason, and may carry a real calendar expiry.

Banner.tsx
// fragments-allow FUI2005: vendor-owned color, tracked in DS-482 expires="2026-12-31"
const Banner = () => <div style={{ color: "#39594d" }} />;
LegacyButton.tsx
// @fragments-expect-error FUI1003 reason="legacy import migration tracked in DS-611" expires="2026-12-31"
import { Button } from "@mui/material";

GitLab repositories include the generated Fragments job; GitHub repositories receive a GitHub Actions workflow. If both providers are present, setup requires an explicit choice and writes neither CI file. Fragments owns .gitlab-ci.fragments.yml and never edits your .gitlab-ci.yml. If your root file already has an include block, the job is still written and setup prints the one line to add.

.gitlab-ci.yml
include:
  - local: '.gitlab-ci.fragments.yml'

The generated job runs on merge requests and on your default branch, and publishes its findings as a Code Quality report. GitLab reads that report natively, so findings show up in the merge request itself — no bot, no token, no Fragments Cloud in the loop. Every finding carries a stable fingerprint, so GitLab follows the same one across pushes instead of listing it again.

.gitlab-ci.fragments.yml
fragments_governance:
  image: node:22
  stage: test
  rules:
    - if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
    - if: '$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH'
  script:
    - corepack enable
    - pnpm install --frozen-lockfile
    - pnpm exec fragments check --ci --format json --codequality gl-code-quality-report.json
  artifacts:
    when: always
    reports:
      codequality: gl-code-quality-report.json

Enforcement Layers

Fragments makes exactly one guarantee, and states everything else as measured probability: "A required CI check blocks covered violations deterministically. Agent guidance reduces how often they are drafted (measured, improving)."

The deterministic result lives in CI, which runs fragments check --ci deterministically on pull requests targeting the configured default branch. On repos where the check is required by branch protection, a covered violation cannot merge — regardless of which agent or human wrote it. Every layer upstream of the check exists to make it boring, and each is honest about being fail-open and bypassable:

  • Generation time. A compact vocabulary card (canonical component names, import paths, token prefix) is injected into supported agents before they write code, so the first draft is usually already on-system. Probabilistic by nature — measured, improving, never claimed as a guarantee.
  • Write time. The agent contract hook checks each governed write as it happens — advisory by default, optionally denying a small deterministic subset of what CI would fail. Fail-open by design: a hook error always allows the write, and fragments doctor is the honest answer to whether the chain is armed. Writes made outside hooked tools (for example shell-mediated edits) are not intercepted — the CI check covers them.
  • Merge time. Repository rules can require the deterministic CI result described above. Only that configured combination carries a merge-blocking guarantee.

Deny With a Fix

In blocking mode, when the hook denies a write on a confirmed violation, the deny reason embeds a conformed replacement — the same deterministic rewrite engine that powers design_system/conform produces corrected content (canonical component swap, token substitution), plus any items it could not resolve. The agent retries with the fix instead of guessing.

Producing the fix is deterministic; the agent applying it is probabilistic — so the deny is capped. After two denies for the same file and finding set in one session, the hook downgrades to advisory and lets CI be the arbiter, so an agent never thrashes against a wall. Deny copy also names the sanctioned in-source suppression path (@fragments-expect-error) for intentional, reviewable exceptions. The deny set is a strict subset of what CI fails: the hook never blocks something the CI check would allow.

What "Caught Before Merge" Counts

The dashboard's "Caught before merge" number counts unique blocking violations observed on open PRs — deduplicated by finding fingerprint per PR, so repeated pushes to the same failing PR never re-count the same violation. A second line reports how many of those PRs later merged clean, verified against the merge commit's recorded verdict.

Both figures count observed events only. Fragments does not report counterfactual "violations prevented" numbers, and does not sum counts across enforcement layers into a single headline.

What Runs When

Start by choosing a contract: the canonical components your team should reuse and the files that define your tokens. That arms the four contract rules (Tier A); every other customer rule is opt-in (Tier B). Until a contract exists, the customer default produces zero findings, so there is no flood on day one.

The universal, fragments, and tailwind presets provide ready-made starting policies; the fragments preset turns every rule on. Only a small allowlist of rules may hard-block (stop) a write; everything else advises.

Rules

Governance rules live in @usefragments/core and run over the same usage facts extracted from your source. A rule decides whether a given fact is a violation; it does not care which surface asked.

This reference is generated from the core registries and currently covers 25 rules across 9 domains. The Fragments-only tokens/require-dual-fallback convention is available through the full fragments preset but is excluded from customer defaults.

Components

Components governance rules
Rule
FUI code
Tier
Title
components/unknown-propFUI6005Opt-inComponent prop is unknown
components/forbidden-prop-valueFUI6004Opt-inProp value is forbidden
components/preferred-componentFUI1002Opt-inPreferred component should be used
components/prefer-libraryFUI1004ContractLibrary component should be preferred
components/shadow-componentFUI1007ContractComponent shadows a canonical primitive

Props

Props governance rules
Rule
FUI code
Tier
Title
props/invalid-valueFUI6002Opt-inProp value is invalid

Imports

Imports governance rules
Rule
FUI code
Tier
Title
imports/preferred-pathFUI1003Opt-inImport should use the preferred path

Styles

Styles governance rules
Rule
FUI code
Tier
Title
styles/no-raw-colorFUI2005Opt-inRaw color should use a token
styles/no-raw-dimensionsFUI2004Opt-inRaw dimension should use a token
styles/no-raw-spacingFUI2006Opt-inRaw spacing should use the scale
styles/no-raw-typographyFUI2016Opt-inRaw typography should use a token

Tailwind

Tailwind governance rules
Rule
FUI code
Tier
Title
tailwind/arbitrary-colorFUI2007Opt-inTailwind arbitrary color should use a token
tailwind/arbitrary-spacingFUI2008Opt-inTailwind arbitrary spacing should use the scale
tailwind/forbidden-paletteFUI2009Opt-inTailwind palette is forbidden
tailwind/off-scale-spacing-tokenFUI2011Opt-inTailwind spacing token is off scale
tailwind/raw-color-via-tokenFUI2010Opt-inTailwind color should use a resolved token
tailwind/unknown-classFUI2012Opt-inTailwind class is unknown

Tokens

Tokens governance rules
Rule
FUI code
Tier
Title
tokens/require-dual-fallbackFUI2003Opt-inToken fallback is required
tokens/css-vars-must-be-definedFUI2015ContractCSS variable is not in the contract vocabulary
tokens/upstream-driftFUI2017ContractLocal token differs from its declared upstream source

Theme

Theme governance rules
Rule
FUI code
Tier
Title
theme/no-theme-coupled-literalFUI2014Opt-inTheme-coupled literal should use a semantic token

Accessibility

Accessibility governance rules
Rule
FUI code
Tier
Title
a11y/required-accessible-nameFUI3001Opt-inAccessible name is required
a11y/standardFUI3002Opt-inAccessibility standard failed

Composition

Composition governance rules
Rule
FUI code
Tier
Title
composition/cardinalityFUI5003Opt-inToo many of a component in one region
composition/co-occurrenceFUI5004Opt-inRequired companion component is missing from the region

FUI Codes

Every rule emits a versioned FUI diagnostic code. The code is the stable identifier a finding carries across surfaces, so local checks, CI, and Cloud can all point to the same explanation. The Error Codes catalog is the canonical per-code reference, with an explain page for each code.

Surfaces

Because findings flow through the shared engine, the same code reaches three surfaces without per-surface wiring:

  • Local. fragments check reports violations before you push, with each FUI code linking to its explain page.
  • CI. fragments check --ci annotates the run and can emit SARIF for code-scanning pipelines.
  • Cloud. Fragments Cloud ingests the same findings and lists them in the issue inventory, grouped and filterable by rule and code.

Topology

Findings don't float free — they roll up by topology. You map your repo into product areas (checkout, dashboard, …), each with a criticality and owners, so risk and ownership aggregate by the parts of your product that matter most — and the highest-stakes areas rise to the top.