Output formats
groundrule check reports its results in four formats: terminal for people, JSON for scripts, SARIF for code-scanning tools, and Markdown for pull-request comments and CI job summaries. This page shows each one with a real example and lists every field.
Choose the format with -f / --format, and write it to a file with -o / --output:
npx @groundrule/cli check # terminalnpx @groundrule/cli check -f json -o groundrule.jsonnpx @groundrule/cli check -f sarif -o groundrule.sarifnpx @groundrule/cli check -f markdown -o groundrule.mdnpx @groundrule/cli check --summary "$GITHUB_STEP_SUMMARY" # terminal, plus a Markdown summary| Format | For | Includes legacy findings | Includes excepted findings |
|---|---|---|---|
terminal |
People | Counted; listed with --verbose |
Counted; listed with --verbose |
json |
Scripts and dashboards | Yes, with isNew: false |
Yes, with suppressedBy |
sarif |
GitHub code scanning and other SARIF tools | Yes, with isNew: false |
Yes, marked as suppressed |
markdown |
PR comments and job summaries | Counted only | Counted only |
With legacy: ignore in the config, legacy findings are left out of every format. With -o, the report goes to the file and the CLI prints one line, for example Wrote sarif report to groundrule.sarif (failed). The exit code is the same in every format. See Exit codes.
Configuration warnings and errors go to standard error in the json, sarif and markdown formats, so they never corrupt the report. The terminal format prints them at the top.
All examples on this page come from one run: a change that adds a direct Stripe import (ACME-004, a blocker) and a console.log (TS-001, a warning), in a repository without a lockfile (SEC-005, already there before the change).
Terminal
Section titled “Terminal”The default. Written for people, with failing findings first and a fix on every finding.
groundrule check · 36 standards · 1 file changed
✕ ACME-004 Route all Stripe calls through the gateway BLOCKER · deterministic (regex) src/http/refunds.ts:1 Stripe imported outside the payments gateway 1: import Stripe from "stripe"; → Import from src/payments/gateway.ts and call its functions. → groundrule explain ACME-004
⚠ TS-001 No console.log in application code warning · deterministic (regex) src/http/refunds.ts:2 console.log in application code 2: console.log("refunding"); → Replace it with the project's logger, or remove it. → groundrule explain TS-001
○ 1 legacy finding not introduced by this change (show with --verbose)
Failed ✓ 20 passed ✕ 1 failed ⚠ 1 warning ◇ 14 guidance · 0.1s| Part | What it shows |
|---|---|
| Headline | The number of standards, and N files changed (with vs <base> when you passed --base), or N files (full audit) with --all. |
| Config lines | ✕ Config error and ! warnings from loading, with file, line and field. |
| One block per standard with findings | An icon, the ID and title; the severity and the source (deterministic (regex), static analysis (semgrep)); up to five locations, each with the message and up to two lines of evidence; the fix (→); and → groundrule explain <ID>. |
○ line |
Legacy findings and findings covered by exceptions that are hidden. --verbose lists them, tagged legacy or excepted by EX-1042. |
– lines |
Standards not evaluated or partly evaluated, with the reason, such as a missing tool. |
| Summary | Passed or Failed, then the counts, then the time taken. |
| Icon | Meaning |
|---|---|
✕ (severity in capitals) |
At least one finding fails the check. |
⚠ |
Findings that don’t fail: below failOn, legacy, or from a rule at Advise. |
? |
A possible finding: a concern, below the check’s minConfidence. |
| Summary count | Meaning |
|---|---|
✓ N passed |
Standards checked with no failing or warning findings. |
✕ N failed |
Standards with at least one failing finding. |
⚠ N warnings |
Standards with new findings that don’t fail. |
– N not evaluated |
Standards whose checks couldn’t run. |
◇ N guidance |
Standards with no checks. |
N not applicable |
Standards that don’t apply to this repository, or are disabled or not active. |
When a standard has more than five findings, the rest are summed up as … 12 more in 4 files (show all with --verbose). Colors follow NO_COLOR and FORCE_COLOR; see Environment and files.
A stable, machine-readable report. schemaVersion changes only on a breaking change.
{ "schemaVersion": 1, "tool": { "name": "groundrule", "version": "0.1.0" }, "passed": false, "context": { "mode": "changes", "files": 6, "changedFiles": 1, "languages": ["typescript"], "frameworks": ["fastify"], "durationMs": 64 }, "summary": { "standards": 3, "passed": 1, "failed": 1, "warned": 1, "notEvaluable": 0, "guidance": 0, "skipped": 0, "violations": 3, "concerns": 0, "suppressed": 0, "legacy": 1, "blocking": 1 }, "outcomes": [ { "id": "ACME-004", "title": "Route all Stripe calls through the gateway", "severity": "blocker", "violations": 1, "concerns": 0, "status": "failed" }, { "id": "SEC-005", "title": "Commit a dependency lockfile", "severity": "warning", "violations": 1, "concerns": 0, "status": "passed" }, { "id": "TS-001", "title": "No console.log in application code", "severity": "warning", "violations": 1, "concerns": 0, "status": "warned" } ], "findings": [ { "standardId": "ACME-004", "standardVersion": 1, "evaluator": "regex", "source": "deterministic", "status": "violation", "severity": "blocker", "confidence": "certain", "location": { "file": "src/http/refunds.ts", "startLine": 1 }, "message": "Stripe imported outside the payments gateway", "evidence": ["1: import Stripe from \"stripe\";"], "remediation": "Import from src/payments/gateway.ts and call its functions.", "isNew": true, "fingerprint": "d9a7534a9e17467c3eaa7bd3b33c27cd", "blocking": true }, { "standardId": "SEC-005", "standardVersion": 1, "evaluator": "files", "source": "deterministic", "status": "violation", "severity": "warning", "confidence": "certain", "message": "No dependency lockfile is committed", "evidence": ["No file matches **/package-lock.json", "No file matches **/pnpm-lock.yaml"], "remediation": "Run your package manager's install and commit the lockfile it creates.", "isNew": false, "fingerprint": "879a72640ddf11beba4aff6b71bfbe8f", "blocking": false } ], "diagnostics": []}This run used --only ACME-004,TS-001,SEC-005; the TS-001 finding is left out above, and the SEC-005 evidence is shortened.
Top level
Section titled “Top level”| Field | Type | Description |
|---|---|---|
schemaVersion |
number | 1. |
tool |
object | name (groundrule) and version (the CLI version). |
passed |
boolean | false when at least one finding fails the check. |
context |
object | What was checked. |
summary |
object | Counts. |
outcomes |
list | One entry per standard. |
findings |
list | One entry per finding, failing ones first, then by severity, file and line. |
diagnostics |
list | Configuration warnings and errors. |
context
Section titled “context”| Field | Description |
|---|---|
mode |
changes or all. |
base |
The --base ref, when given. |
files |
Files in the repository that checks could read. |
changedFiles |
Changed files (0 in all mode). |
languages, frameworks |
What the CLI detected. |
durationMs |
How long the run took. |
summary
Section titled “summary”| Field | Counts |
|---|---|
standards |
Standards considered. |
passed, failed, warned |
Standards by outcome. |
notEvaluable |
Standards whose checks couldn’t run. |
guidance |
Standards with no checks. |
skipped |
Standards not applicable, disabled, or not active. |
violations, concerns |
Findings not covered by an exception. |
suppressed |
Findings covered by exceptions. |
legacy |
Findings not introduced by the change. |
blocking |
Findings that fail the check. |
outcomes
Section titled “outcomes”| Field | Description |
|---|---|
id, title, severity |
The standard. severity reflects overrides and, in a connected repository, Advise (blockers become warnings). |
status |
passed, failed, warned, not-evaluable, guidance or skipped. |
reason |
Why it was skipped or not (fully) evaluated, for example Not applicable: framework react not found. or Disabled by config override: <reason>. |
violations, concerns |
Its findings not covered by exceptions. |
findings
Section titled “findings”Each finding follows the published finding.schema.json, plus blocking.
| Field | Type | Description |
|---|---|---|
standardId |
string | The standard’s ID. |
standardVersion |
number | The standard’s metadata.version. |
evaluator |
string | Which evaluator found it, for example regex. |
source |
enum | Where the verdict came from: deterministic, static-analysis, ai or external. |
status |
enum | violation (not met), concern (possibly not met, below the confidence needed), pass, or not-evaluable. |
severity |
enum | blocker, warning, advisory or info. |
confidence |
enum | low, medium, high or certain. |
location |
object | file (relative to the repository), startLine, and optionally endLine, startColumn, endColumn. Missing for repository-level findings, such as a missing file. |
message |
string | One sentence: what is wrong. |
evidence |
list of strings | Why the evaluator believes it, such as the matching line. |
remediation |
string | How to fix it, from the check or the standard. |
isNew |
boolean | true if introduced by the change, false if legacy. |
suppressedBy |
string | The ID of the exception that covers it, such as EX-1042. |
fingerprint |
string | A stable identity across runs, based on the standard, evaluator, file and code, not the line number. |
blocking |
boolean | true if this finding fails the check. |
diagnostics
Section titled “diagnostics”| Field | Description |
|---|---|
severity |
error or warning. |
file |
The file, relative to the repository when it is inside it. |
line, column |
Where, when known. |
path |
The field, for example spec.checks[0].pattern. |
message |
What is wrong. |
SARIF 2.1.0, the format GitHub code scanning and many other tools read. It holds every violation and concern, new and legacy.
{ "$schema": "https://json.schemastore.org/sarif-2.1.0.json", "version": "2.1.0", "runs": [ { "tool": { "driver": { "name": "Groundrule", "informationUri": "https://groundrule.dev", "semanticVersion": "0.1.0", "rules": [ { "id": "ACME-004", "name": "ACME004", "shortDescription": { "text": "Route all Stripe calls through the gateway" }, "fullDescription": { "text": "Never import stripe outside src/payments/gateway.ts. Call the gateway's functions, such as createPaymentIntent, instead." }, "help": { "text": "Never import stripe outside src/payments/gateway.ts. Call the gateway's functions, such as createPaymentIntent, instead.\n\nWhy: One place for retries, idempotency keys, and audit logging of payments.\n\nFix: Import from src/payments/gateway.ts and call its functions." }, "defaultConfiguration": { "level": "error" }, "properties": { "tags": ["groundrule", "payments"], "owner": "team:payments" } } ] } }, "originalUriBaseIds": { "%SRCROOT%": { "uri": "file:///" } }, "results": [ { "ruleId": "ACME-004", "ruleIndex": 0, "level": "error", "message": { "text": "Stripe imported outside the payments gateway\nFix: Import from src/payments/gateway.ts and call its functions." }, "locations": [ { "physicalLocation": { "artifactLocation": { "uri": "src/http/refunds.ts", "uriBaseId": "%SRCROOT%" }, "region": { "startLine": 1 } } } ], "partialFingerprints": { "groundrule/v1": "d9a7534a9e17467c3eaa7bd3b33c27cd" }, "properties": { "source": "deterministic", "evaluator": "regex", "confidence": "certain", "isNew": true, "blocking": true, "standardVersion": 1 } } ] } ]}How Groundrule maps to SARIF:
| SARIF | From |
|---|---|
rules[] |
One per standard with findings: id, name (the ID without dashes), the title, the requirement, help text (requirement, Why: intent, Fix: remediation), and properties.tags (groundrule and the standard’s category) and owner. |
defaultConfiguration.level, results[].level |
blocker → error, warning → warning, advisory and info → note. Concerns are always note. |
message.text |
The finding’s message, and Fix: with the remediation. |
locations |
The file and lines, relative to the repository root. A finding without a file points at line 1 of the standard’s file. |
partialFingerprints["groundrule/v1"] |
The finding’s fingerprint, so code scanning tracks it across commits. |
suppressions |
For a finding covered by an exception: kind: external, justification Groundrule exception EX-1042. |
properties |
source, evaluator, confidence, isNew, blocking, standardVersion. |
To show findings in GitHub code scanning, upload the file with GitHub’s upload-sarif action. The job needs the security-events: write permission:
- run: npx @groundrule/cli check --base origin/${{ github.base_ref }} -f sarif -o groundrule.sarif env: GROUNDRULE_TOKEN: ${{ secrets.GROUNDRULE_TOKEN }}- uses: github/codeql-action/upload-sarif@v3 if: always() with: sarif_file: groundrule.sarifif: always() uploads the report even when the check step fails. See Run it in CI.
Markdown
Section titled “Markdown”A short summary for a pull-request comment or a CI job summary. It lists only new findings that aren’t covered by an exception.
### Groundrule · ✕ 1 standard failed
| | Standard | Finding | Where | Source ||---|---|---|---|---|| ✕ | **ACME-004** Route all Stripe calls through the gateway | Stripe imported outside the payments gateway<br>**Fix:** Import from src/payments/gateway.ts and call its functions. | `src/http/refunds.ts:1` | deterministic || ⚠ | **TS-001** No console.log in application code | console.log in application code<br>**Fix:** Replace it with the project's logger, or remove it. | `src/http/refunds.ts:2` | deterministic |
✓ 1 passed · 1 legacy finding
<sub>Groundrule 0.1.0 · run `groundrule explain <ID>` for details</sub>| Part | What it shows |
|---|---|
| Headline | ✕ N standards failed, ⚠ Passed with N warnings, or ✓ All standards passed. |
| Table | One row per new finding, up to 50: an icon (✕ fails, ⚠ doesn’t, ? concern), the standard, the message and fix, the location (repository when there is no file), and the source (deterministic, static analysis, or AI · <confidence>). After 50 rows, a last row says how many more there are. |
| Notes | Counts that apply: passed, guidance, not evaluated, not applicable, legacy findings, and findings covered by exceptions. |
| Not fully evaluated | A collapsed list of standards whose checks couldn’t all run, with the reason. |
| Footer | The CLI version and a pointer to explain. |
Two ways to use it:
- A job summary.
--summary <file>appends the Markdown to a file, in addition to the main report. In GitHub Actions, pass$GITHUB_STEP_SUMMARYand the summary appears on the run’s page. You can combine it with any--format. - A pull-request comment. Write it with
-f markdown -o groundrule.md, and post the file with your CI’s tools. Groundrule doesn’t post pull-request comments or checks itself yet.