Mainfast
Sections

Install Mainfast

Each product installs on its own, in a few minutes, from your repository. Do the part under Before you start once, then the chapter for each product you want.

Before you start

  • Using a coding agent? Point it at /llms.txt: it has the one-line install, the JSON commands and the MCP setup.
  • A GitHub repository where you can add workflow files under .github/workflows/.
  • GitHub Actions enabled. The checks run as Actions in your own workflows with your own GITHUB_TOKEN. Mainfast Pro is the hosted GitHub App instead: one install, no workflow files.
  • Each workflow grants only the permissions its check needs (see the product pages). No administration permission is ever needed.
  • Mainfast Intact, Mainfast Migrations and the pull_request job of Mainfast Evidence need a checkout with fetch-depth: 0. Mainfast Rollcall and Mainfast Owners need no checkout.
  • Optional: .mainfast.yml (or .mainfast.yaml) at the repository root. An unknown top-level key is an error, so a typo never silently switches a check back to defaults.
  • Optional: add the JSON Schema to your editor from https://raw.githubusercontent.com/mainfast/mainfast/main/schema/mainfast.schema.json.
  • Only Mainfast Owners has an optional extra: an org-token with Organization, Members: read, for org membership and team checks.
  • Third-party actions in the examples are pinned to full commit SHAs. The CLI of Mainfast Intact needs Node 20+ and git.
  • The Mainfast actions in the examples use the moving tag @v0, which follows each new release. To stay on one exact version and choose when to update, replace @v0 with a full commit SHA.

Mainfast Intact Free, MIT

Prove that a merge commit did not silently drop changes from main.

  1. GitHub Actions workflow
    GitHub Actions workflowyaml
    name: Mainfast Intact
    on:
      pull_request:
      push:
        branches-ignore: [main]
    permissions:
      contents: read
      checks: write
    jobs:
      intact:
        runs-on: ubuntu-latest
        steps:
          - uses: actions/checkout@fbc6f3992d24b796d5a048ff273f7fcc4a7b6c09 # v5.1.0
            with:
              fetch-depth: 0
              ref: ${{ github.event.pull_request.head.sha || github.sha }}
          - uses: mainfast/intact@v0
  2. CLI, from a clone of the suite repository
    CLI, from a clone of the suite repositorysh
    git clone https://github.com/mainfast/mainfast
    # from the cloned suite root:
    npm ci && npm run build -w intact
    ln -s "$PWD/intact/dist/cli.cjs" ~/.local/bin/mainfast
    mainfast check                       # every merge commit in <main>..HEAD
    mainfast check --range origin/main..feature
    mainfast check --json --fail-on error
  3. Optional config
    Optional configyaml
    version: 1
    intact:
      ignore:                      # gitignore-style globs
        - "dist/"
      severity:                    # first match wins: error, warning, notice, off
        "docs/**": notice
        "migrations/**": error

It needs

  • Needs only GITHUB_TOKEN, with contents: read and checks: write.
  • With checks: write it posts a check run with annotations. Without it (fork PRs) it writes the job summary and annotations instead.
  • The Action reads .mainfast.yml from the base of the change, so a pull request cannot ignore its own dropped change. The CLI reads your working tree.
  • The CLI needs Node 20+ and git. The Action unshallows a shallow checkout automatically; fetch-depth: 0 is faster.
  • Reading a private shared config with extends needs a config-token input; GITHUB_TOKEN cannot read other private repositories.

Mainfast Migrations Free, MIT

Fail a PR whose migrations would fork the history once merged into main.

  1. GitHub Actions workflow
    GitHub Actions workflowyaml
    name: Mainfast Migrations
    on:
      pull_request:
      push:
        branches: [main]
    permissions:
      contents: read
      pull-requests: write   # sticky comment + stale label
      statuses: write        # the blocking mainfast/migrations commit status
    jobs:
      migrations:
        runs-on: ubuntu-latest
        steps:
          - uses: actions/checkout@fbc6f3992d24b796d5a048ff273f7fcc4a7b6c09 # v5.1.0
            with:
              fetch-depth: 0
          - uses: mainfast/migrations@v0
  2. Make it block merges
    Make it block mergestext
    After the first run, add mainfast/migrations under
    Settings > Branches > main > Require status checks to pass
    (or the ruleset equivalent).
  3. Optional config
    Optional configyaml
    migrations:
      frameworks: auto          # or [alembic, django, prisma, rails, flyway, drizzle]
      ignore: [legacy/**]
      outOfOrder:               # per framework; or one value for all: error | warning | off
        rails: error
        prisma: off
      label: "mainfast: migrations stale"
  4. CLI
    CLIsh
    npx mainfast-migrations check --main origin/main --head HEAD          # exit 1 on errors
    npx mainfast-migrations check --format md

It needs

  • contents: read: fetch main and refs/pull/<n>/head. Without it the check cannot run.
  • pull-requests: write: the sticky PR comment and the stale label. Without it they are skipped with a warning; summary and annotations still carry the result.
  • statuses: write: the mainfast/migrations commit status. Without it there is no status, so nothing blocks the merge.
  • Only the commit status blocks a merge, and only once branch protection or a ruleset requires it. The comment and label only tell people.
  • On fork PRs the token is read-only: comment, label and status are skipped with a warning and the job summary carries the result.
  • The status is on by default; status: false turns it off (comment and label only, then nothing blocks).

Mainfast Rollcall Free, MIT

Find required checks that protect nothing: never ran, skipped, renamed or filtered.

  1. GitHub Actions workflow (no checkout needed)
    GitHub Actions workflow (no checkout needed)yaml
    name: Mainfast Rollcall
    on:
      schedule:
        - cron: "17 6 * * 1"   # weekly
      workflow_dispatch:
      branch_protection_rule:
      push:
        branches: [main]
        paths: [".github/workflows/**", ".mainfast.yml"]
    permissions:
      contents: read
      pull-requests: read
      statuses: read
      checks: write
      issues: write
    jobs:
      rollcall:
        runs-on: ubuntu-latest
        steps:
          - uses: mainfast/rollcall@v0
  2. CLI (read-only, exit 1 on an error-level finding)
    CLI (read-only, exit 1 on an error-level finding)sh
    GITHUB_TOKEN=... npx mainfast-rollcall audit --github-repo owner/name --pulls 30 --open-pulls 10 --format md
    npx mainfast-rollcall audit --snapshot snap.json --format json        # offline

It needs

  • contents: read: config, workflow files and classic required checks. Without it the run stops on the config read.
  • pull-requests: read: merged and open PRs to sample. Without it the run stops.
  • statuses: read: commit statuses on each sampled head. Without it statuses are treated as empty and noted.
  • checks: write: read check runs and post the result. issues: write: the tracking issue. Without them a warning annotation is shown.
  • No administration permission is needed. Rulesets come from the metadata-read endpoints; the admin endpoint is only a fallback, and a 403 becomes a note.
  • A ruleset's bypass_actors are only returned with write access to the ruleset, so Rollcall does not read them.

Mainfast Owners Free, MIT

Catch CODEOWNERS drift: unowned files, departed owners, missing teams, dead patterns.

  1. GitHub Actions workflow (no checkout needed)
    GitHub Actions workflow (no checkout needed)yaml
    name: Mainfast Owners
    on:
      pull_request:
      schedule:
        - cron: "23 6 * * 1"   # weekly audit
      workflow_dispatch:
    permissions:
      contents: read
      pull-requests: write
    jobs:
      owners:
        runs-on: ubuntu-latest
        steps:
          - uses: mainfast/owners@v0
            with:
              org-token: ${{ secrets.MAINFAST_OWNERS_ORG_TOKEN }}   # optional
  2. CLI
    CLIsh
    npx mainfast-owners lint --repo .                                   # offline, no token
    GITHUB_TOKEN=... npx mainfast-owners audit --github-repo owner/name [--ref main]
    GITHUB_TOKEN=... npx mainfast-owners pr --github-repo owner/name --pr 42 [--comment]

It needs

  • contents: read: CODEOWNERS and .mainfast.yml at the base/default branch and PR head, the git tree, and GitHub's CODEOWNERS errors. Without it the run stops.
  • pull-requests: write: reads the PR's changed files and posts the one sticky comment. With read only there is no comment but the result stands.
  • Optional org-token with Organization permission Members: Read-only (a fine-grained token or a GitHub App). Store it as the MAINFAST_OWNERS_ORG_TOKEN secret.
  • Without the org-token, org membership, team existence and team access are skipped with one note; teams count as valid and users are still checked.
  • GITHUB_TOKEN cannot have any organization permission, so it can never see private org membership or teams.
  • Dormancy uses the search API (30 requests a minute), at most 100 requests per run by default.

Mainfast Evidence Free, MIT

Proof, not review, for pull requests written by coding agents.

  1. GitHub Actions workflow (two jobs)
    GitHub Actions workflow (two jobs)yaml
    name: Mainfast Evidence
    on:
      pull_request:
        types: [opened, synchronize, reopened, edited, labeled, unlabeled, ready_for_review]
      workflow_run:
        workflows: [CI]
        types: [completed]
    permissions: {}
    jobs:
      pr:   # same-repository PRs, every push
        if: github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name == github.repository
        runs-on: ubuntu-latest
        permissions:
          contents: read
          checks: write
          pull-requests: write
          statuses: read
        steps:
          - uses: actions/checkout@fbc6f3992d24b796d5a048ff273f7fcc4a7b6c09 # v5.1.0
            with:
              fetch-depth: 0
              ref: ${{ github.event.pull_request.head.sha }}
          - uses: mainfast/evidence@v0
            with:
              wait-for-checks: "600"
      ci:   # after CI finishes; also the only job that sees fork PRs. No checkout.
        if: github.event_name == 'workflow_run'
        runs-on: ubuntu-latest
        permissions:
          contents: read
          checks: write
          pull-requests: write
          statuses: read
          actions: read
        steps:
          - uses: mainfast/evidence@v0
            with:
              local-diff: "false"
  2. Optional policy
    Optional policyyaml
    evidence:
      apply_to: agents            # or all
      test_checks: ["test", "/integration/"]
      required_checks: [test]
      coverage:
        files: [coverage/lcov.info]
        min_changed_lines: 80
      flags:
        touched_lockfiles: off
        required_check_failed: fail
  3. CLI
    CLIsh
    mainfast-evidence local --base main [--head HEAD] [--body-file pr.md] [--coverage lcov.info]
    mainfast-evidence pr --repo owner/name --pr 42 [--post]
    mainfast-evidence flags

It needs

  • contents: read (both jobs): PR files and commits, the policy at the base commit, classic required checks and rulesets.
  • checks: write (both jobs): create or update the check run on the head sha, and read other check runs.
  • pull-requests: write (both jobs): the sticky comment, and finding a fork PR by head sha.
  • statuses: read (both jobs): commit statuses count as checks. Without it a status-only test or required check reads as missing.
  • actions: read (workflow_run job only): to download the coverage artifact from the CI run.
  • No administration permission is needed. If the token cannot post, the job fails and the card goes to the job summary.