Skip to content

Truth Rules

github-actions[bot] edited this page Oct 19, 2026 · 1 revision

Truth Rules

The truth check of nself-ci keeps false facts out of a repository. It reads rule files, scans the files of the repository and reports every line that breaks a rule. It never touches the network. The engine is free/ci/internal/gates/truth; the org rules are data in .github/truth/.

Rule files

File Holds Kinds
.github/truth/org.yaml dead hosts, retired terms, banned literals dead-host, retired-term, banned-literal
.github/truth/claims.yaml hand-typed counts, current-version literals, retired vocabulary numeric-claim, version-claim, plus two vocabulary rules

The claim kinds live in their own file so that a pinned nself-ci release that predates them keeps parsing org.yaml. A repo lists claims.yaml only after its pinned release carries the claim kinds.

A repo enforces the rules with .nself/ci.yaml:

version: 1
checks:
  truth:
    rules: [.github/truth.yaml]

and a .github/truth.yaml that includes the vendored org rules and adds its own exemptions:

version: 1
include: [.github/truth/org.yaml, .github/truth/claims.yaml]
overrides:
  claims.current-version:
    facts: .github/facts.json
    exempt_paths:
      - {glob: "docs/history/**", reason: dated notes keep the version that was current then}

Rule format

All rule files are version: 1. A rule has id, kind, message (what to write instead) and optional paths (globs; default every file). Unknown keys, duplicate ids, bad patterns, exemptions without a reason and rule files outside the repository are E644 and name the file and key.

Key Kinds Meaning
pattern numeric-claim, version-claim RE2, matched case-insensitively against one line. Required, with paths.
facts version-claim Repo-relative JSON or YAML file with a top-level version. A literal equal to it passes (a leading v is ignored).
exempt_paths all [{glob, reason}]: files the rule skips.
exempt_matches all but dead-host [{regex, reason}]: a hit inside a match of the regex is exempt.
exempt_regions retired-term, banned-literal true makes the rule honour the markers below (the claim kinds always do).
term ending in (s) retired-term Matches with and without the plural s.

A reason has at least 8 characters.

Exempting a hit

A claim rule (and a vocabulary rule that sets exempt_regions: true) skips a hit that sits in:

  1. A generated region: <!-- BEGIN GENERATED:<id> --> to <!-- END GENERATED:<id> --> (in .mdx: {/* BEGIN GENERATED:<id> */}). Both markers must be present; an unclosed or repeated BEGIN exempts nothing.
  2. A JSX expression {...} in an .astro or .mdx file. Braces must balance within a paragraph, inline code and code fences do not count, and an expression that is only a quoted string or a template literal without ${} is typed text, so it is not exempt. In .astro files the frontmatter, <script> and <style> blocks are code and are skipped.
  3. The line after a comment that is the whole line: <!-- truth: exempt <reason> --> (in .mdx: {/* truth: exempt <reason> */}). Text that merely mentions the marker, in prose, inline code or a fence, exempts nothing. A comment with no reason (fewer than four letters or digits) is a finding (truth.exempt-without-reason) and exempts nothing.
  4. A file with a comment in its first three lines that says GENERATED BY (its generator gates it).

Claim rules never read Go source, go.mod, go.sum or go.work, and skip changelogs, release notes (release-notes/, releases/v*), blog posts (content/blog, blog/*.md), ADRs, history folders, testdata, vendor and node_modules by default. They apply to prose paths only: Markdown, MDX, Astro text, README*, text files, i18n JSON values and packaging descriptions.

Known limits: the rules read one line at a time (a count split over two lines is missed), do not look through zero-width characters, miss a count written as Plugins: 62, all 62 free and paid plugins, 62 <b>plugins</b>, with a dash between the number and the noun, or in full-width digits, and do not read .tsx/.jsx text or .astro frontmatter strings; a file that is binary, UTF-16 or over 4 MiB is skipped and counted. A dead host is never printed: another rule's match or a file name that holds one is replaced by a redaction note.

Overrides

A rule file may carry an overrides block keyed by rule id. It adds exempt_paths (and, for a version-claim, facts) to a rule declared in that file or in a file it includes, directly or not. An override that names an unknown rule id, or a rule the file does not include, is E644. facts is resolved against the scanned root, and a facts file reached through a symlink out of the tree is refused.

The shipped claim rules

Id Kind Catches Write instead
claims.counts numeric-claim a count of plugins, commands, verbs, bundles or integrations render it from the generated facts, or use words
claims.counts-ar numeric-claim the same count in Arabic i18n values (Western or Arabic-Indic digits) render it from the generated facts
claims.current-version version-claim a version typed next to "nself" or "current/latest release" render it from the facts file
vocab.pro-plugin retired-term the retired phrase for licensed plugins "licensed plugin(s)"
vocab.bundles-repo-slug banned-literal the old name of the Bundles repository nself-org/bundles

vocab.bundles-repo-slug exempts Go module paths (exempt_matches): renaming a module path is a breaking change and GitHub redirects the old name.

Examples (each line below is exempt from the rules it shows, so this page stays clean):

  • fails: We ship 129 free plugins.
  • passes: a line preceded by <!-- truth: exempt a quoted line from the 2019 launch post -->

Output

Human mode prints one line per finding, then the rule's message:

truth: <rule-id> <file>:<line>: <match>
    fix: <message>

A dead-host finding prints a hash prefix, never the host. --json prints one document with data.result (pass, fail, error), per-check results and the findings.

Running the check

From free/ci of this repository (the plugin binary does not link the check until the V15 engine does):

go run -mod=vendor ./internal/gates/truth/run.go check --root DIR [--json] [--kind K|rules] RULEFILE...

Exit 0 pass, 1 findings, 2 rule-file or scan error. --kind rules validates the files without scanning.

Vendoring the rules

bash scripts/truth/vendor-rules.sh TARGET_DIR          # writes TARGET_DIR/.github/truth/{org,claims}.yaml
bash scripts/truth/vendor-rules.sh --check TARGET_DIR  # exit 1 when a copy is missing or differs

Each copy starts with # VENDORED FROM nself-org/plugins@<sha> — DO NOT HAND EDIT, then this checkout's bytes unchanged. --check ignores the header line. The truth-sweep drill runs --check on every public clone that carries .github/truth/, so a drifted copy fails the nightly sweep.

nself-plugins

Start

Commands

Architecture

Plugin Ecosystem

Popular Plugins

View All: Home (or see the full alphabetical list below — 129/129 synced with registry.json)

All Free Plugins

Guides

Operations


Related

Clone this wiki locally