mcpField
P
preflight

preflight

github.com/rheged-studioTesting & quality046 installsUpdated 6d ago
Repository

About preflight

preflight is a repository skill for change-scoped linting. It checks relevant categories and paths in a branch diff, and distinguishes new violations from pre-existing ones for development teams.

Key features

  1. 01Run lint on branch-changed paths
  2. 02Separate new from pre-existing violations
  3. 03Support ESLint, markdownlint, and actionlint
  4. 04Provide scoped lint-fix scripts
  5. 05Drive checks through exit codes

Use cases

  1. 01Check branch lint before committing
  2. 02Add a lint gate to a ship flow
  3. 03Identify new issues versus existing debt

Install

Copy the command and run it in a terminal.

$npx skills add https://github.com/rheged-studio/agent-skills --skill preflight

After installing, type/preflightin Claude Code to confirm it loaded.

Bundled files

References and scripts installed along with SKILL.md.

config.example.json
package.json
README.md
scripts/
classify-lint.mjs
lint-fix.mjs
preflight.mjs
scripts/lib/
diff-lines.mjs
paths.mjs
scope.mjs
scripts/lib/vendor/
base-branch.mjs

Details

From the project README

preflight

Change-gated, branch-scoped lint preflight. It lints only the categories relevant to origin/<base>...HEAD, on changed paths only — not a whole-repo pnpm lint — then classifies each violation as introduced (on a line this branch added or changed) or pre-existing (already there, in a file the branch happens to touch).

This skill is the single source of truth for the preflight loop. It is invoked two ways:

  • Standalone (/preflight) — a quick "will my branch pass scoped lint?" check, leaving any fixes in the working tree.
  • Inside a ship flow (e.g. /send-it) — the lint gate that runs after commits and before the changelog/push steps.

All bundled scripts use only Node built-ins — no npm install, no build step. They operate on the consumer repo's root (run them from the repo root, where git resolves the branch diff).

Running it

  1. Make sure the base branch is up to date: git fetch origin <base> (the base is auto-detected — see Configuration).
  2. Run the preflight: node skills/preflight/scripts/preflight.mjs (append --dry-run to report categories and scoped file lists without classifying violations). --dry-run is a true preview — every linter reports would-run and nothing is written, including .preflight-summary.json. Before anything else, the script checks that the active Node major matches the repo's pin — an exact engines.node pin (24.x, 24.18.0) or, failing that, the .nvmrc major — and exits 1 with a switch hint (nvm use / fnm use / mise use) if it does not, so ESLint never runs under the wrong Node. A >= / ^ / ~ engines range is not a pin; a repo with neither is unchecked.
  3. Read .preflight-summary.json for the categories run and the violation counts (passed, deferred, blocking). Written only on a real run, not under --dry-run. It is a transient scratch artefact, never committed — consumer repos gitignore it (the rheged-skills-setup skill adds the entry when it reconciles a repo).

The script's exit code drives the loop:

  • Exit 0 — pass. No introduced violations and every linter ran cleanly. Continue.
  • Exit 1 — introduced violations (blocking). Run node skills/preflight/scripts/lint-fix.mjs on the branch-scoped paths, then re-run preflight. Repeat until introduced violations clear or the user aborts. (Inside a ship flow, commit the fixes; standalone, leave them in the working tree for the user to review and commit.) Only introduced errors block by default — introduced ESLint warnings are reported as a non-blocking notice and don't fail the gate, matching pnpm lint / CI (which exit 0 on warnings). Set blockOnWarnings: true to gate on them too (see Configuration).
  • Exit 2 — pre-existing violations only. Show the list and ask the user to choose:
    • Fix now — apply the fixes, (commit if shipping), re-run preflight.
    • Defer — open a debt issue in Linear (see Debt-issue create below). After creating (or refusing), decide whether to continue or abort.

Exit 1 can also signal a linter that failed to run (non-zero exit with no parseable violations) — inspect its stderr; this is blocking too — or a Node major mismatch (see step 2): switch Node and re-run, don't treat it as a lint failure.

Categories

Each category is gated on what the branch changed (mirrors CI path triggers, narrower scope):

CategoryRuns whenSkipped when
ESLintBranch diff includes lintable code or eslint/tsconfig config pathsMarkdown-only or non-lintable changes
markdownlintBranch diff includes .md / .mdx (respecting repo ignores)No markdown changes; warns and skips if the markdownlint-cli2 binary is missing
actionlintBranch diff includes .github/workflows/*.yml or .github/actionlint.yamlNo workflow changes; config-only changes lint all tracked workflows; warns and skips if actionlint binary missing

ESLint runs per workspace (via pnpm --filter), plus a root/scripts bucket. Typecheck, tests, and framework checks (e.g. astro check) are not part of preflight — they stay in CI.

Standalone vs inside a ship flow

  • Standalone (/preflight) does the lint preflight and the exit-code loop, then reports. On introduced violations it may run node skills/preflight/scripts/lint-fix.mjs and re-run, but it leaves fixes in the working tree — it never commits, writes a changelog, pushes, or opens a PR.
  • Inside /send-it the same loop runs as the lint gate (after commits, before changelog work); fixes are committed so the branch is clean before the changelog is written. The changelog and its validation are separate gates owned by the ship flow — they are not part of this skill.

Configuration

The two repo-specific inputs are auto-detected — a consuming repo edits nothing in the common case:

  • Linted workspaces are derived from pnpm-workspace.yaml plus each package's package.json: a workspace is included only if it declares a lint script. This auto-excludes intentionally-unlinted workspaces and non-package directories without a hand-maintained list.
  • Base branch is detected from origin/HEAD (e.g. main, master, develop), falling back to main when that symbolic ref is absent.

To override either, add a preflight.config.json at the consumer repo root (a config.example.json ships beside this file as a template):

{
  "baseBranch": "main",
  "blockOnWarnings": false,
  "workspaces": {
    "web": { "filter": "@acme/web", "prefix": "apps/web/" }
  },
  "linearTeamName": "",
  "debtProject": ""
}

Any key may be supplied on its own; the others are still auto-detected/defaulted. Use the override for non-pnpm repos, deliberate exclusions, or nested workspace globs the detector does not expand.

  • blockOnWarnings (default false) — whether introduced ESLint warning-severity findings block the gate. Off by default, preflight blocks only on introduced errors (and linters that fail to run); introduced warnings are surfaced non-blockingly, matching pnpm lint / CI semantics. Set true for repos that want warn-level findings the branch adds to gate as well. markdownlint/actionlint findings always block — the warn/error split is ESLint-only.
  • linearTeamName / debtProject — agent-facing keys for the Exit 2 Defer path (the lint scripts ignore them). Both must be non-empty to mint a debt issue; see Debt-issue create. Empty disables debt-create (tell the user to set them, or choose Fix now) — never file with no project.
Debt-issue create

When the user chooses Defer on Exit 2, mint a Linear debt issue only when both linearTeamName and debtProject are set in the repo-root preflight.config.json (read that file; empty / missing keys mean debt-create is disabled). Fail closed:

  1. If either key is empty, or the Linear MCP server is unavailable → do not call save_issue. Tell the user to set linearTeamName + debtProject (or choose Fix now). Skip silently only when MCP is unavailable and they still want to continue without tracking.
  2. Resolve the team by name (linearTeamName) and the project via list_projects (debtProject as name, id, or slug). On a miss → do not call save_issue; fail loudly with the unresolved value.
  3. On a hit → call save_issue with team, project (always), a title/description covering the pre-existing violations, assignee = the maintainer, and a link to the branch/PR context. Never omit project.

Implementation

The bundled scripts live beside this file under scripts/ and are invoked directly with node — no pnpm aliases, no npm install:

  • scripts/preflight.mjs — the change-gated preflight and exit-code contract.
  • scripts/lint-fix.mjs — scoped eslint --fix / markdownlint-cli2 --fix on the branch-changed paths.
  • scripts/classify-lint.mjs — parse + classify violations as introduced vs pre-existing.
  • scripts/lib/{scope,diff-lines,paths}.mjs — shared helpers (workspace/base-branch detection, diff-line mapping, path normalisation).

They have no external npm dependencies (Node built-ins only).

Arguments

$ARGUMENTS

Comments

Markdown supported