Documentation Concepts

governance.pxf + domains

governance.pxf is the file that tells Steward how to read your repository. Every dashboard, every PR verdict, every contributor reputation score eventually traces back to a decision encoded here. Read this once and the rest of the product stops feeling opinionated and starts feeling like it's executing your opinions.

Where it lives

The file sits at .steward/governance.pxf on the repository's default branch. Steward reads it from the default branch — not from the PR head — so a PR can't change the rules it's evaluated against (the rules change only when a separate PR amending governance.pxf is merged).

Format is PXF, a typed, comment-friendly serialization that compiles to protobuf. We dogfood our own format here; if you've written protobuf or HCL you'll be at home in seconds.

The minimal file

domains: [
  { name: "everything", path_globs: ["**/*"], max_cyclomatic_complexity: 15 }
]

That's it — a single domain that catches every file in the repo with one structural gate. Most repos start here and add specifics as they bump into them — or skip the typing entirely: the governance editor's posture wizard writes a preset-pinned file from three questions (see "Presets" below).

Domains: the central idea

A domain is a named slice of your code that gets its own evaluation rules. Every file in a PR maps to exactly one domain (the first matching path_globs wins — see "glob ordering" below). Domains let you say "the API package needs 80% test coverage; the docs folder needs none of that."

domains: [
  { name: "api",     path_globs: ["internal/api/**"], min_coverage: 0.80, approval_threshold: 2 }
  { name: "docs",    path_globs: ["docs/**", "*.md"], min_coverage: 0.0,  approval_threshold: 1 }
  { name: "rest",    path_globs: ["**/*"],            min_coverage: 0.60, approval_threshold: 1 }
]

Each domain carries a vector of thresholds (per internal/judge/governance):

Field Purpose
name Stable handle. Used in reputation scores, audit events, dashboard filters. Don't rename casually.
path_globs Which files belong to this domain. Doublestar syntax (** matches multiple path segments).
min_coverage Test-coverage floor (0.0–1.0). Coverage gate compares head-PR coverage to this.
max_cyclomatic_complexity Per-function complexity ceiling. Caliper gate rejects functions above it.
approval_threshold Reputation points the PR author needs in this domain before they can self-merge without an extra review.
supermajority_ratio Used for cross-domain consensus when a PR touches multiple domains (ADR-004).
criticality_multiplier Weights the domain's contribution to overall PR score. Boost it for security-sensitive areas.
restricted Marks the domain as needing elevated approval. The dashboard surfaces a yellow banner.
enforcement Per-domain override of the repo-wide enforcement mode — see "Enforcement modes" below.
self_merge "never" disables the reputation-based skip entirely: every PR in this domain takes the review path, regardless of the author's standing (and regardless of restricted). Default ("by-reputation") is the threshold behavior above.

Fields not set inherit Steward's defaults. You don't need to set all of them on day one.

Enforcement modes

Structural gates don't have to block. A top-level enforcement sets the repo-wide mode, and each domain can override it:

enforcement = "warn"          # repo-wide: advise, don't block
domains: [
  { name: "security", path_globs: ["internal/auth/**"], enforcement: "block" }
  { name: "rest",     path_globs: ["**/*"] }              # inherits "warn"
]
Mode What a violation does
observe Recorded in the audit trail + dashboard only. No PR comment, never blocks.
warn Advisory PR comment ("in block mode this PR would be rejected"). Never blocks.
block Rejects the PR — the default, and the behavior of every file written before this field existed.

When one gate result spans multiple domains, the strictest resolved mode wins (block > warn > observe).

This is the adoption ramp: set real thresholds on day one, run them in warn, watch the dashboard to see what would fail, then flip to block once the numbers say the bar is fair.

Every structural gate honors the mode. Domain-attributed gates (coverage, complexity, perf, Static Analysis Results Interchange Format (SARIF)) resolve per-domain overrides; repo-global gates (pinned dependencies, license allowlist, mission-drift, alternatives) take the top-level mode, since a go.mod belongs to no domain. In warn/observe the evaluation also keeps going after a violation instead of stopping at the first failed gate — one run surfaces everything that would block. The cla gate keeps its own independent enforcement field, and the escrow/reputation flow is not a structural gate.

Presets — start from a posture, own only your deltas

Instead of writing every section, a file can extend a version-pinned preset baked into Steward:

preset = "welcoming/v1"

manifesto {
  mission = "Human-friendly text serialization for protobuf schemas."
}
founders: [
  { handle: "your-handle", reputation_seed: { "everything": 2000 } }
]

That's a complete, working governance.pxf: the preset supplies the posture (real thresholds in repo-wide warn, the contributor on-ramp, Developer Certificate of Origin (DCO) sign-off at flag-only), and your file carries only what is yours — the mission and your founder seed.

Three rules to know:

  1. Overrides are section-wholesale. Any top-level section present in your file replaces the preset's section entirely — restating cla with two fields means the preset's exempt_logins are gone unless you restate them too. There is no field-level merging; partial merges plus proto defaults would make "did I override that or inherit it?" unanswerable.
  2. Versions are immutable. welcoming/v1 will behave the same forever — a Steward upgrade can never silently move rules you pinned (the build fails if a released preset's bytes change). Improvements ship as welcoming/v2; adopting one is a one-line change in your file, reviewed like any amendment.
  3. Unknown names fail loudly at load, listing the presets your Steward build knows. Presets cannot reference presets.

Available today:

  • welcoming/v1 — young projects optimizing for their first contributors: real thresholds in repo-wide warn, the contributor on-ramp, sign-off at flag-only.
  • disciplined/v1 — teams shipping internal code: gates block, self_merge = "never" in every domain (reputation never substitutes for review), pinned dependencies, no community ceremony.
  • vendor-led/v1 — company-backed open source: concentric domain rings (restricted staff territory, an open community playground), sign-off at block, supply-chain timelocks — and deliberately no amendment voting: rules stay the vendor's. Requires a founders override (the wizard emits it) — the restricted rings need seeded reputation to function.
  • constitutional/v1 — established community projects: everything on, including amendment voting (75% of the top-15 reputation holders, 14-day window) and slashing. Also requires a founders override; the 30-day decay dissolves the seed into a real handoff.

Every preset deliberately ships no manifesto — overrides are wholesale, and the mission is yours; each preset's header comments show the recommended manifesto block to pair with it.

Glob ordering matters

DomainForPath returns the first domain whose path_globs match. So put your specific domains first, your catch-all last:

# good — specific first
domains: [
  { name: "auth", path_globs: ["internal/auth/**"], ... }
  { name: "rest", path_globs: ["**/*"], ... }
]
# bad — catch-all swallows everything
domains: [
  { name: "rest", path_globs: ["**/*"], ... }
  { name: "auth", path_globs: ["internal/auth/**"], ... }  # unreachable
]

If you suspect a file is being assigned to the wrong domain, the fleet dashboard's per-PR view shows the resolved domain for every file in the diff.

Top-level sections beyond domains

domains is the most-edited section. Steward also reads:

Section What it controls
manifesto Mission statement (used by the mission-drift gate), perf-regression thresholds, blocked-module globs.
cla DCO requirement, CLA enforcement (block or flag), exempt logins, template path.
sarif Whether SARIF reports get ingested as gate findings.
caliper Whether the server-side complexity analyzer runs.
decay Reputation decay half-life — how fast inactivity erodes contributor authority.
escrow Sandbox-issue auto-generation (the contributor on-ramp).
amendments The governance-of-governance: how many reputation-weighted votes amending governance.pxf itself requires.
triage Issue auto-labeling (`priority/high
welcome First-PR welcome surface (template, who to assign).

The API reference lists every field; the Write your first governance.pxf guide walks through a real example for a small repo.

What Steward does with it on every PR

  1. Steward loads governance.pxf from the default branch.
  2. The PR's changed files are bucketed into domains.
  3. Each domain's thresholds become the gates the PR has to clear.
  4. Per-PR evaluation scores each of the five dimensions (see Evaluations + dimensions), weighted by criticality_multiplier.
  5. The result lands in the PR comment + the fleet dashboard.

If governance.pxf is missing, malformed, or empty, Steward falls back to a permissive baseline: every file goes into one implicit rest domain, every gate is set to its built-in default, and the dashboard surfaces a "no governance.pxf" badge so you remember to write one.

Amendments — changing the rules

Changes to governance.pxf itself can be subject to a voting rule (configured under amendments). Default-off: small repos just merge the PR like any other change. Larger projects flip on supermajority_ratio to require a fraction of top-N reputation holders to approve an amendment before it lands.

This is the "governance-of-governance" hatch. You probably don't need it on day one. Revisit when you have enough contributors that any one merging a governance.pxf change feels coercive.

What's next