Critiq team
- guides
Inline PR comments from Critiq: dedupe, severity, and noise control
Use critiq-action for inline PR comments: dedupe across reruns, fail-on-severity gates, and when to block merge vs comment only.
Inline PR comments from Critiq: dedupe, severity, and noise control content
Pull request review works best when feedback sits on the line you changed, not buried in a log file three tabs away. The Critiq GitHub Action runs critiq check on your PR diff and posts inline review comments so rule-backed findings show up where authors already look. That only helps if reruns do not spam the thread, severities map to merge policy, and you can tell when a comment is enough versus when the job should fail.
This guide walks through a practical setup: add the action, read how deduplication keeps PRs quiet across pushes, tune fail-on-severity for merge gates, and reduce noise when comments alone are the right signal. Everything here uses the open source critiq-dev/critiq-action composite on GitHub Actions. You do not need a Critiq Cloud account or a paid product.
If you already run critiq check locally, the Action is the same engine with GitHub-native delivery. The difference is where results land: terminal and JSON on your machine, inline threads and optional check failure on the PR.
What the action does on a pull request
On pull_request, the action installs @critiq/cli (from your package.json when declared, otherwise a pinned npm prefix install), runs critiq check against the PR base and head SHAs, writes JSON to the runner, and, unless you turn comments off, posts GitHub review comments on flagged lines that appear in the diff. GitHub only allows inline comments on diff lines; Critiq's default diff-scoped scan matches that constraint.
After the scan and comment step, a separate fail-on-severity step can fail the job when findings meet your threshold. Comments still post when comment-mode is enabled, even if the job ends red. That ordering matters: authors see feedback on the diff before merge policy blocks them.
Start with a minimal workflow
Create .github/workflows/critiq.yml in the repository you want to scan. Checkout needs full history so diff mode can resolve base and head; the job needs pull-requests: write when you use inline comments.
name: Critiq
on:
pull_request:
permissions:
contents: read
pull-requests: write
jobs:
critiq:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Run Critiq
uses: critiq-dev/critiq-action@v1
with:
fail-on-severity: offOpen a pull request and confirm the workflow on the Actions tab. With defaults (comment-mode: inline, fail-on-severity: off), you get review comments on the diff and a green job unless critiq check itself errors. Pin @v1 for a major tag or a commit SHA if your org requires supply-chain pinning. Full input reference: https://github.com/critiq-dev/critiq-action#inputs
Inline comments and comment-mode
comment-mode controls how findings reach GitHub. The default inline posts one review comment per finding on the PR head commit, on the file and line from the JSON report when that line is in the PR diff.
- inline (default), review comments on the diff only
- inline+summary, inline comments plus one sticky issue comment with finding counts
- off, scan and outputs only; no GitHub comments (useful for SARIF or custom transformers)
Each Critiq comment includes the rule id, severity, message, and remediation text from the catalog, the same fields you see locally in pretty or JSON output. That keeps PR feedback aligned with critiq check on your laptop.
- name: Run Critiq
uses: critiq-dev/critiq-action@v1
with:
comment-mode: inline+summary
fail-on-severity: offHow deduplication works
Without dedupe, every push would add duplicate comments for the same finding, and resolved threads would reappear after a fix-and-push cycle. critiq-action applies four rules so reruns and human resolves do not spam the PR.
- Marker, Each comment embeds a hidden HTML marker tied to fingerprints.primary from the scan JSON. That stable fingerprint is the identity of the finding across runs.
- Same line, If any review comment already exists on the same path + line at the PR head commit, Critiq does not add another comment there.
- Resolved threads, If that fingerprint appears in a resolved review thread (GraphQL), Critiq skips posting that finding again.
- Open threads, If the fingerprint already exists in an unresolved thread, the finding is skipped rather than duplicated.
Practical effect: when an author fixes an issue and resolves the thread, a later push does not resurrect the same comment. When two rules would fire on one diff line, you still get at most one comment on that line per head commit. When a finding cannot be placed on the diff (no line in the PR patch), it is skipped for inline posting, not silently dropped from the JSON report.
The action exposes review-comments-created and review-comments-skipped outputs after the post step. Skipped counts include dedupe hits and findings missing location or fingerprint data. Use them in a follow-up step when you are tuning noise:
- name: Run Critiq
id: critiq
uses: critiq-dev/critiq-action@v1
- name: Comment stats
run: |
echo "Created: ${{ steps.critiq.outputs.review-comments-created }}"
echo "Skipped: ${{ steps.critiq.outputs.review-comments-skipped }}"
echo "Findings: ${{ steps.critiq.outputs.finding-count }}"Severity gating with fail-on-severity
Inline comments inform; fail-on-severity enforces. The input runs after scan and post, and fails the job when any finding is at or above the level you choose. Severity order is low → medium → high → critical; each threshold includes that level and every more severe one.
- off (default), never fail for finding severity; comments still run when enabled
- low, fail on low, medium, high, or critical
- medium, fail on medium, high, or critical
- high, fail on high or critical only
- critical, fail only on critical findings
Platform teams often start with fail-on-severity: off so authors learn the catalog without blocked merges, then move to high once high-severity rules are trusted. Security-sensitive repos may use medium for a stricter gate. The exit code from critiq check still reflects the scan; fail-on-severity is an additional policy layer on top of the JSON findings.
- name: Run Critiq
uses: critiq-dev/critiq-action@v1
with:
fail-on-severity: high
comment-mode: inlineReducing noise without turning Critiq off
Noise on a PR is usually a policy problem, not a comment-format problem. These levers keep signal high while staying on deterministic rules.
Tune the catalog in the repo
Add .critiq/config.yaml when you need stricter presets, path ignores, or catalog tuning. The action loads it automatically from working-directory. Disabling a noisy rule by id is preferable to muting the whole check, the rule id in the comment matches what you change in config. CLI reference: https://github.com/critiq-dev/critiq-core/blob/main/docs/reference/cli.md
Scope monorepo packages
In a monorepo, set working-directory to the package root where dependencies install and target to the subtree you want analyzed (for example apps/web). That limits findings to the surface area the PR actually touches, which cuts unrelated comments on unchanged packages.
- name: Run Critiq
uses: critiq-dev/critiq-action@v1
with:
working-directory: apps/web
target: apps/web
fail-on-severity: highChoose summary vs inline-only
inline+summary adds one sticky issue comment with counts. Some teams like a single rollup for managers; others find it redundant with inline threads. If the issue comment feels noisy, stay on inline and rely on Actions logs plus finding-count.
Pin CLI and rules versions
When the root package.json does not declare @critiq/cli, the action installs cli-version and rules-version (default latest) under RUNNER_TEMP. Pin semver tags in the workflow when you want CI to match a known catalog release and avoid surprise new rules on unrelated PRs.
with:
cli-version: "0.9.0"
rules-version: "0.9.0"
fail-on-severity: highWhen to use comments vs a failing check
Comments and check failure solve different problems. Use both deliberately.
- Comments only (fail-on-severity: off), Feedback for authors without blocking merge. Good for adoption, experimental rules, or repos where another policy gate already exists.
- Comments + soft gate (medium or high), Inline context on the diff plus a red check when severity crosses your bar. Authors see why before the branch protection rule fires.
- Check without comments (comment-mode: off), Machine-readable json-path and finding-count for dashboards, SARIF pipelines, or custom bots. Pair with fail-on-severity when humans do not need GitHub-native threads.
- Separate secret gate, critiq-action runs critiq check, not critiq audit secrets. If credential-shaped literals must block merge, add a dedicated audit secrets step; do not assume check exit code alone enforces secrets.
Branch protection should reference the Critiq job name you use in the workflow. If fail-on-severity is off, a green Critiq job means "no scan failure," not "zero findings." Inspect finding-count and the JSON artifact path when you need zero-findings policies without changing fail-on-severity.
Reusable workflow for many repos
Org-wide consistency is easier with the reusable workflow shipped in critiq-action. Caller workflows stay small; you centralize checkout depth, permissions, and inputs once.
name: Critiq
on:
pull_request:
jobs:
critiq:
uses: critiq-dev/critiq-action/.github/workflows/reusable-critiq.yml@v1
secrets: inheritPass the same inputs as the composite action (cli-version, rules-version, working-directory, target, comment-mode, fail-on-severity) through the reusable workflow inputs when you need overrides. The reusable job checks out only the caller repository, no Critiq Cloud clone. Repositories that depend on a local critiq-core file: dependency should use a custom workflow that builds core first; see the critiq-action README monorepo and reusable sections.
Troubleshooting common symptoms
- No review comments, Confirm pull-requests: write, comment-mode is not off, and findings map to lines in the PR diff. Secrets-only paths outside the diff will not get inline comments.
- Duplicate comments after dedupe, Usually a new fingerprint (rule or engine change) or a different path/line. Compare fingerprints.primary in json-path output across runs.
- Job fails unexpectedly, Lower fail-on-severity, set it to off temporarily, or fix findings; read exit-code and finding-count outputs.
- Diff scan misses files, Use fetch-depth: 0 on checkout so base and head SHAs exist locally.
- Comments but you need SARIF, Set comment-mode: off and consume json-path in a follow-up step or run critiq check --format sarif yourself.
Privacy and what runs where
Scanning runs on your GitHub Actions runner in your account. Critiq does not operate a backend that receives your source or scan JSON from this action. GITHUB_TOKEN is used only to post PR comments when comment-mode allows it, within the permissions you declare. npm is contacted to install @critiq/cli and @critiq/rules (or your declared dependencies). Details: https://github.com/critiq-dev/critiq-action/blob/main/PRIVACY.md
Next steps
- GitHub Action repo and README, https://github.com/critiq-dev/critiq-action
- Marketplace listing, search critiq-dev/critiq-action on GitHub Marketplace
- OSS CLI and rules, https://critiq.dev/products/oss
- Documentation, https://docs.critiq.dev/
- GitHub Actions integration page, https://critiq.dev/integrations/github-actions
Start with inline comments and fail-on-severity: off, watch review-comments-skipped on a few PRs, then raise the severity gate when the team trusts the catalog. Dedupe and severity are the difference between a bot that nags and a check that behaves like infrastructure you operate, the kind your reviewers actually resolve instead of ignoring.
More from the blog

- philosophy
The trust gap in AI-assisted coding, and what inspectable feedback looks like
Developers use AI assistants daily but often distrust review feedback. Inspectable rules, evidence, and local checks close that gap.
Read article
- philosophy
What evidence over vibes means in code review
Review comments should be defensible: tied to a rule, a line, severity, and references, not just confident prose.
Read article
- philosophy
Why we open-sourced the rules engine (and what stays in the catalog)
Critiq ships the rule engine, DSL, and 435+ OSS catalog rules in the open. Here is what you get locally, what Pro adds, and how to inspect rules yourself.
Read article