{"slug": "show-hn-pr-nutrition-a-local-rule-based-cli-for-pull-request-triage", "title": "Show HN: PR Nutrition, a local rule-based CLI for pull request triage", "summary": "PR Nutrition, a new local-first CLI tool for pull request triage, assigns deterministic review-readiness labels based on Git metadata and file paths, with risk scores capped at 100 and built-in eval passing 16/16 false-positive and 7/7 true-positive guards. The tool, available via npx pr-nutrition@latest, aims to help reviewers quickly identify risky areas and low-value files in AI-assisted code changes.", "body_md": "PR Nutrition is a local-first PR triage CLI.\n\nIt gives every pull request a simple review-readiness label.\n\nAI coding tools are making it easier than ever to generate code, open PRs, and ship changes quickly. That is useful, but it also creates a new problem: reviewers now have to read through more changes, more often, with less context.\n\nPR Nutrition helps with that.\n\nIt does not review your code for you. It does not guess whether the code is correct. It gives you a fast, deterministic label that answers:\n\n- What changed?\n- What looks risky?\n- What can probably be skimmed?\n- Where should a reviewer focus first?\n\n```\nnpx pr-nutrition@latest\n```\n\nThat is it. You get a Markdown or JSON report you can read locally, save in CI, or attach to a read-only pull request workflow.\n\n```\n# PR Nutrition\n\nRisk: Medium (40/100)\n\nScope\n- Total changes: 17 files\n- Reviewable: 15 files, 320 lines\n- Base: main\n- Head: HEAD\n\nReview focus\n- Review dependency or package metadata changes.\n- Review configuration and environment-sensitive paths.\n- Docs changed; verify examples match current behavior.\n\nLow review-value files\n- pnpm-lock.yaml\n- generated/client.ts\n```\n\nSee the full examples:\n\nModern development is changing.\n\nA lot of code is now written with AI assistance. Teams can generate features, refactors, tests, and boilerplate much faster than before. But reviewers still need to understand what actually changed.\n\nThat is where PRs start becoming painful:\n\n- Large PRs hide the important files.\n- Generated files make diffs noisy.\n- Lockfiles and build outputs distract from real logic.\n- Risky areas like auth, migrations, workflows, and APIs need attention first.\n- AI-generated changes can look polished while still being hard to trust.\n\nPR Nutrition is built for that moment before review starts.\n\nIt gives reviewers a small “nutrition label” for the PR so they can quickly decide:\n\n- Is this low-risk and easy to skim?\n- Is this touching sensitive areas?\n- Are tests or docs included?\n- Are there files that should not consume review time?\n- Where should I look first?\n\nThe goal is not to replace review. The goal is to make review less exhausting.\n\nThe built-in eval corpus currently passes `16/16`\n\nfalse-positive guards and `7/7`\n\ntrue-positive guards. These are curated regression cases, not statistical precision or recall on real-world pull requests. Run `pnpm eval`\n\nto regenerate the guard-case summary locally. See [eval/README.md](/Param-10/pr-nutrition/blob/main/eval/README.md).\n\nPR Nutrition uses Git metadata and file paths to classify changes.\n\nIt detects:\n\n- PR size\n- migrations\n- auth and security paths\n- CI and workflow changes\n- API and public contract files\n- dependency manifests and lockfiles\n- configuration and environment-sensitive paths\n- generated files\n- low-review-value files\n- renamed and binary files\n- changed tests and docs\n- repository evidence like package manager, test scripts, typecheck scripts, and CI workflow presence\n- an explicit Coverage section for what was checked and what was not\n\nRisk scores are deterministic and capped at `100`\n\n.\n\n```\nLow:    0–19\nMedium: 20–49\nHigh:   50–100\n```\n\nAn area contributes points once, no matter how many files matched it. API, dependency, and configuration points scale with how much changed in that area, so a one-line lockfile bump does not score like a dependency overhaul. Migrations, authentication, and CI always score their full value, because a single line in any of those can drop a table, invert a permission check, or weaken a required gate.\n\nArea scaling uses reviewable lines, so generated files and lockfiles do not inflate an area regardless of how large their diff looks.\n\nOverall size risk uses production files and lines: tests and docs still affect review guidance, but they do not make a documentation- or test-only PR risky. A production change at 10 files or 200 lines adds 20 points; at 30 files or 800 lines it adds 50 points. Tests and docs never subtract points from an independently risky change.\n\nUse it directly with `npx`\n\n:\n\n```\nnpx pr-nutrition\nnpx pr-nutrition --output pr-nutrition.md\n```\n\nOr install globally:\n\n```\nnpm install -g pr-nutrition\npr-nutrition\n```\n\nCurrent stable npm release: `pr-nutrition@0.4.0`\n\n.\nPrevious release: `pr-nutrition@0.3.0`\n\n.\n\n```\nnpx pr-nutrition@0.4.0\nnpx pr-nutrition@0.4.0 --help\nnpx pr-nutrition@0.4.0 doctor\npr-nutrition\npr-nutrition --json\npr-nutrition --format json\npr-nutrition --output pr-nutrition.md\npr-nutrition --base origin/main --head HEAD\npr-nutrition --config .pr-nutrition.json\npr-nutrition --no-config\npr-nutrition --explain\npr-nutrition --json --explain\npr-nutrition --focus-files\npr-nutrition --json --focus-files\npr-nutrition --fail-on medium\npr-nutrition check\npr-nutrition check --base main\npr-nutrition check --fail-on high\npr-nutrition doctor\npr-nutrition doctor --json\npr-nutrition doctor --base main --head HEAD\npr-nutrition doctor --config .pr-nutrition.json\npr-nutrition doctor --no-config\n```\n\nFull contract:\n\n```\npr-nutrition [--repo <path>] [--base <ref>] [--head <ref>]\n             [--format <markdown|json>] [--json] [--output <file>]\n             [--config <path>] [--no-config] [--explain] [--focus-files]\n             [--fail-on <low|medium|high>]\n\npr-nutrition check [--repo <path>] [--base <ref>] [--head <ref>]\n                   [--format <markdown|json>] [--json] [--output <file>]\n                   [--config <path>] [--no-config] [--explain] [--focus-files]\n                   [--fail-on <low|medium|high>]\n\npr-nutrition doctor [--repo <path>] [--base <ref>] [--head <ref>]\n                    [--json] [--config <path>] [--no-config]\n```\n\nOptions:\n\n| Option | Default | Description |\n|---|---|---|\n`--repo <path>` |\n`.` |\nRepository to analyze |\n`--base <ref>` |\n`main` |\nBase ref |\n`--head <ref>` |\n`HEAD` |\nHead ref |\n`--format <markdown|json>` |\n`markdown` |\nOutput format |\n`--json` |\n`false` |\nAlias for `--format json` |\n`--output <file>` |\nstdout | Write output to a file |\n`--config <path>` |\n`.pr-nutrition.json` |\nConfig file inside the repository |\n`--no-config` |\n`false` |\nDisable config loading |\n`--explain` |\n`false` |\nAdd deterministic classification explanations |\n`--focus-files` |\n`false` |\nAdd deterministic file review priority groups |\n`--fail-on <low|medium|high>` |\nunset | Exit `3` when risk level meets or exceeds the threshold |\n\nThe `--json`\n\nshortcut is available in the current stable `0.4.0`\n\nrelease.\n\nUse `pr-nutrition check`\n\nbefore opening or pushing a pull request. It runs the same analyzer as the default command, enables focus-file groups by default, and does not fail the process unless you pass `--fail-on`\n\n.\n\n```\npr-nutrition check\npr-nutrition check --base main\npr-nutrition check --fail-on high\npr-nutrition check --json --output pr-nutrition.json\n```\n\nExit codes:\n\n`0`\n\n— analysis succeeded and risk is below`--fail-on`\n\n(or`--fail-on`\n\nwas not set)`1`\n\n— usage / flag errors`2`\n\n— analysis, config, or output failures`3`\n\n— risk level meets or exceeds`--fail-on`\n\nConfiguration support is available in the current stable `0.4.0`\n\nrelease.\n\nPR Nutrition automatically looks for `.pr-nutrition.json`\n\nat the repository root. Configuration extends the built-in classification with repository-specific paths; it never weakens built-in protections, removes risk categories, hides files, or changes risk weights, thresholds, or scoring.\n\n```\n{\n  \"schemaVersion\": 1,\n  \"paths\": {\n    \"generated\": [\"src/generated/**\"],\n    \"lowReviewValue\": [\"snapshots/**\"],\n    \"tests\": [\"spec/**\"],\n    \"docs\": [\"handbook/**\"],\n    \"risk\": {\n      \"authentication\": [\"modules/identity/**\"],\n      \"api\": [\"contracts/**\"]\n    }\n  }\n}\n```\n\nRules:\n\n- Patterns are POSIX-style globs matched against repo-relative paths.\n`generated`\n\n,`lowReviewValue`\n\n,`tests`\n\n, and`docs`\n\nextend the built-in path classification.`risk.<area>`\n\nadds paths to the built-in risk areas (`migrations`\n\n,`authentication`\n\n,`ci`\n\n,`api`\n\n,`dependencies`\n\n,`configuration`\n\n).- Validation is strict: unknown keys, invalid globs, parent traversal, backslashes, symlinked config files, files over 64 KiB, and config paths outside the repository are rejected.\n`--config <path>`\n\noverrides discovery;`--no-config`\n\ndisables config loading; combining them is invalid usage (exit`1`\n\n). Invalid config exits`2`\n\n.\n\nExplain output is available in the current stable `0.4.0`\n\nrelease.\n\n`--explain`\n\nadds a deterministic account of why each file was classified. It works with both Markdown and JSON output and never changes default output when it is not passed.\n\n- Markdown gains a compact\n`## Explanation`\n\nsection (capped at the first 30 entries, then`...and N more`\n\n). - JSON gains an\n`explanations`\n\narray containing every explanation. - Explanations use only repo-relative paths. No file contents, patch contents, absolute paths, or environment values are included.\n- Explanations are sorted deterministically by path, kind, rule ID, and source.\n\nEach explanation carries a stable `ruleId`\n\nand a `source`\n\nof `builtin`\n\n, `config`\n\n, or `git`\n\n:\n\n| Rule ID | Meaning |\n|---|---|\n`builtin.path.migrations` / `.authentication` / `.ci` / `.api` / `.dependencies` / `.configuration` |\nBuilt-in risk-area path rule |\n`builtin.path.generated` |\nBuilt-in generated-file rule |\n`builtin.path.low-review-value` |\nBuilt-in low-review-value rule |\n`builtin.path.test` / `builtin.path.docs` |\nBuilt-in test / documentation rule |\n`builtin.git.binary` / `builtin.git.rename` / `builtin.git.copy` / `builtin.git.generated` |\nGit-derived binary, rename, copy, and linguist-generated signals |\n`config.paths.generated` / `.lowReviewValue` / `.tests` / `.docs` |\nConfig path classification |\n`config.paths.risk.<area>` |\nConfig risk-area path (uses the built-in `RiskAreaId` names) |\n\nWhen both a built-in and a config rule match a file's risk area, the explanation reports the winning rule under the existing deterministic priority and notes the rule it ranked above.\n\nJSON shape with `--json --explain`\n\n:\n\n```\n{\n  \"explanations\": [\n    {\n      \"path\": \"src/auth/session.ts\",\n      \"kind\": \"risk-area\",\n      \"area\": \"authentication\",\n      \"ruleId\": \"builtin.path.authentication\",\n      \"source\": \"builtin\",\n      \"reason\": \"Path matched the built-in authentication and security rule.\"\n    }\n  ]\n}\n```\n\nFocus file output is available in the current stable `0.4.0`\n\nrelease.\n\n`--focus-files`\n\nadds a compact reviewer workflow that separates changed files into:\n\n`Review first`\n\n`Review normally`\n\n`Skim / low-review-value`\n\nMarkdown gains a `## Focus files`\n\nsection. JSON gains a `focusFiles`\n\narray. Default output is unchanged unless `--focus-files`\n\nis passed.\n\nThe grouping uses existing deterministic classification data: risk areas, generated status, low-review-value status, binary status, and reviewable line counts. It does not read file contents, patch contents, absolute paths, or environment values.\n\nDoctor output is available in the current stable `0.4.0`\n\nrelease.\n\n`pr-nutrition doctor`\n\ndiagnoses whether PR Nutrition can run in the current repository. It checks Git availability, worktree detection, refs, merge-base availability, config loading, shallow repository status, and safe repository evidence.\n\n```\npr-nutrition doctor\npr-nutrition doctor --json\npr-nutrition doctor --base main --head HEAD\npr-nutrition doctor --config .pr-nutrition.json\npr-nutrition doctor --no-config\n```\n\nDoctor does not fetch history, call GitHub APIs, read patches, inspect `.env`\n\ncontents, execute package scripts, or read workflow contents.\n\nJSON output uses `schemaVersion: 1`\n\n, `command: \"doctor\"`\n\n, a top-level `status`\n\nof `ok`\n\n, `warning`\n\n, or `error`\n\n, and stable check IDs such as `git.repository`\n\n, `git.merge-base`\n\n, `config.validation`\n\n, and `evidence.package-manager`\n\n.\n\nExit codes:\n\n| Code | Meaning |\n|---|---|\n`0` |\nSuccess |\n`1` |\nInvalid CLI usage |\n`2` |\nRepository, ref, Git, or output failure |\n\nPR Nutrition uses pull-request-style three-dot comparison: it finds the merge base between `base`\n\nand `head`\n\n, then analyzes changes from that merge base to `head`\n\n.\n\nFor agents and scripts:\n\n- Markdown is the default human-readable output.\n- JSON output is available with\n`--json`\n\nor`--format json`\n\n. - JSON is written only to stdout unless\n`--output`\n\nis provided. - Errors are written to stderr.\n- Exit codes are stable:\n`0`\n\nsuccess`1`\n\ninvalid CLI usage`2`\n\nrepository, ref, Git, or output failure\n\n- JSON includes\n`schemaVersion: 1`\n\n.\n\nPR Nutrition can analyze any Git repository already on your machine; it does not need to be installed inside that project.\n\n```\npr-nutrition doctor --repo /absolute/path/to/project --base origin/main --head feature/my-change\npr-nutrition check --repo /absolute/path/to/project --base origin/main --head feature/my-change\n```\n\nUse exact base and head commit SHAs for historical pull requests, then save JSON reports to a private directory outside the analyzed repository. See the [real-world benchmark guide](/Param-10/pr-nutrition/blob/main/docs/real-world-benchmark.md) for active branches, historical GitHub PRs, privacy guidance, and the manual labeling format for the planned 25–50 PR corpus.\n\nCurrent Action tag: `Param-10/pr-nutrition@v0.4.0`\n\n.\n\nUse the released Action tag with a read-only token and full-history checkout:\n\n```\npermissions:\n  contents: read\n\nsteps:\n  - uses: actions/checkout@v6\n    with:\n      fetch-depth: 0\n\n  - id: nutrition\n    uses: Param-10/pr-nutrition@v0.4.0\n```\n\nThe Action is read-only, requires only `contents: read`\n\n, does not call the GitHub API, and does not post PR comments.\n\nInputs:\n\n| Input | Default | Description |\n|---|---|---|\n`repo-path` |\n`.` |\nRepository checkout to analyze. |\n`base-ref` |\nPull-request base SHA | Optional base ref. Must be provided with `head-ref` ; explicit refs override event metadata. |\n`head-ref` |\nPull-request head SHA | Optional head ref. Must be provided with `base-ref` ; explicit refs override event metadata. |\n`write-step-summary` |\n`true` |\nAppend the Markdown report to `$GITHUB_STEP_SUMMARY` . |\n`output-directory` |\n`$RUNNER_TEMP/pr-nutrition` |\nDirectory for report files. |\n`use-config` |\n`true` |\nLoad the repository `.pr-nutrition.json` when present. |\n`config-file` |\n`.pr-nutrition.json` |\nConfig file path resolved relative to `repo-path` . |\n\nConfig example:\n\n```\nwith:\n  use-config: true\n  config-file: .pr-nutrition.json\n```\n\nInvalid config files fail the Action clearly. Config loading never adds GitHub API calls, write permissions, or PR mutation.\n\nOutputs:\n\n| Output | Description |\n|---|---|\n`risk-score` |\nNumeric score from `0` to `100` . |\n`risk-level` |\n`low` , `medium` , or `high` . |\n`files-changed` |\nTotal changed files in the analyzed range. |\n`markdown-path` |\nPath to `pr-nutrition.md` . |\n`json-path` |\nPath to `pr-nutrition.json` . |\n\nFor non-pull-request events, provide both `base-ref`\n\nand `head-ref`\n\n. Providing only one is an error. The Action writes `pr-nutrition.md`\n\nand `pr-nutrition.json`\n\nunder `$RUNNER_TEMP/pr-nutrition`\n\n, appends Markdown to the job summary by default, and exposes the outputs listed above.\n\nThe Action does not fetch Git history, call GitHub APIs, create comments, or mutate pull requests. Missing history fails with guidance to use `fetch-depth: 0`\n\n.\n\nPR Nutrition is local-first and deterministic.\n\nIt does not:\n\n- read patch contents\n- read\n`.env`\n\nvalues - read arbitrary source file contents for analysis\n- execute repository scripts\n- call GitHub APIs\n- call LLMs\n- upload code anywhere\n- make network calls during analysis\n\nIt only uses Git metadata, file paths, selected safe repository metadata, and package/workflow presence checks.\n\nSee [Privacy Model](/Param-10/pr-nutrition/blob/main/docs/privacy.md) for the detailed rules.\n\nPR Nutrition is not:\n\n- an AI code reviewer\n- a bug detector\n- a security scanner\n- a PR summary bot\n- a noisy PR-comment bot\n- a replacement for human review\n- a tool that decides whether code is correct\n\nIt is a review-readiness label.\n\nIt helps you know what kind of PR you are about to review before you spend time reading the diff.\n\nPR Nutrition should never create work for reviewers. It should remove review noise before the review starts.\n\nActivate Node 24.17.0 from `.node-version`\n\n(or another supported Node version from 22.13 up to, but not including, 27) before running pnpm.\n\n```\ncorepack enable\npnpm install --frozen-lockfile\npnpm build\npnpm --filter pr-nutrition start -- --base main --head HEAD\n```\n\nRun checks:\n\n```\npnpm test\npnpm eval\npnpm typecheck\npnpm lint\npnpm policy:check\npnpm action:bundle-check\npnpm build\npnpm smoke\npnpm release:check\n```\n\nCurrent:\n\n- deterministic CLI\n- Markdown and JSON output\n- published npm package\n- release checks\n- secure staged-release automation\n- read-only GitHub Action\n- committed reproducible Action bundle\n- strict JSON configuration\n`--json`\n\n,`--explain`\n\n,`--focus-files`\n\n, and`doctor`\n\n- false-positive evaluation corpus with reported guard-case pass rates\n- segment-anchored risk rules and magnitude-scaled scoring\n- ranked and capped focus-file lists in Markdown\n- coverage section for what was and was not checked\n- local\n`check`\n\nworkflow and optional`--fail-on`\n\n- discoverable\n`check`\n\nand`doctor`\n\nsubcommands - PR authoring-policy enforcement and a supported local Node pin\n\nNext:\n\n- richer deterministic framework and infrastructure rules\n- additional generated-file ecosystems\n- a locally labeled real-world metadata corpus before claiming precision or recall\n\nLater:\n\n- PR split hints\n- optional PR comments only after repeated user demand\n- more CI evidence\n- optional LLM wording polish, never risk decisions\n\nSee [Roadmap](/Param-10/pr-nutrition/blob/main/ROADMAP.md).", "url": "https://wpnews.pro/news/show-hn-pr-nutrition-a-local-rule-based-cli-for-pull-request-triage", "canonical_source": "https://github.com/Param-10/pr-nutrition", "published_at": "2026-08-11 17:56:38+00:00", "updated_at": "2026-08-11 18:13:58.789421+00:00", "lang": "en", "topics": ["developer-tools", "ai-tools"], "entities": ["PR Nutrition"], "alternates": {"html": "https://wpnews.pro/news/show-hn-pr-nutrition-a-local-rule-based-cli-for-pull-request-triage", "markdown": "https://wpnews.pro/news/show-hn-pr-nutrition-a-local-rule-based-cli-for-pull-request-triage.md", "text": "https://wpnews.pro/news/show-hn-pr-nutrition-a-local-rule-based-cli-for-pull-request-triage.txt", "jsonld": "https://wpnews.pro/news/show-hn-pr-nutrition-a-local-rule-based-cli-for-pull-request-triage.jsonld"}}