For AI agents: this page as Markdown · llms.txt · JSON Schema
#Headless scan
Warning
In internal testing: in the code but not ready for public use, and may change or go without notice.
rerail scan without --session scans a checkout in its own process, so it runs in CI.
- Output:
--jsonprints onererail.scan/1document (below); otherwise one line per violation and a summary. - Remotes: a completed scan is queued for each remote, unless
--no-send.
What it does not need or touch
No daemon, no session and nothing set up first. It adds nothing to the Rerail database's session history. Its one write
outside its temporary folder: a checkout new to Rerail gets a clone id in Git's metadata folder
(<git common dir>/), as rerail start would.
rerail scan [--repo <dir>] [--scope repository|git-diff] [--base <ref>] [--rules-ref <ref>] [--pack <id>]...
[--path <p>]... [--paths-from <file>] [--json] [--fail-on-violations] [--no-send]| Option | Does |
|---|---|
--repo <dir> |
Git checkout to scan (any folder in it). Default: the current folder. |
--scope repository |
Default. Every file the rules read, or only the --path/--paths-from files. |
--scope git-diff |
Changed, staged and untracked files against HEAD, or against the merge base with --base <ref>. |
--rules-ref <ref> |
Run .rerail/rules/ at that Git ref, so a change cannot edit the rules judging it. |
--pack <id> |
Also run an installed pack. Repeatable. |
--json |
Print the report. |
--fail-on-violations |
Exit 3 on violations. |
--no-send |
Do not queue the report for this machine's remotes. |
Option details
--scope repositorywith--path/--paths-from: paths are relative to the checkout; missing ones are skipped.--scope git-diff: the merge base is of<ref>andHEAD, so--basegives a pull request's changes. Deleted files are not scanned. No changed files is a completed scan with nothing in it.--rules-ref: replaces the working tree's rules. Those rules run in Log until approved (see Which rules run).--pack: the pack must be installed in the Rerail home first (rerail packs add <id>). It takes an id (complexity) or package name (@neralabs/). A pack that is not installed is an error.rerail-pack-complexity --fail-on-violations: exits 3 only when the scan completed with violations.
Exit codes:
0: completed. Violations alone do not fail it.1: failed: an execution failure, or bad input such as an unknown ref.3: violations, with--fail-on-violations.
#Which rules run
The scan uses your Rerail home's configuration when it can, otherwise a throwaway one.
- Home: the repository's packs, rules, settings and approvals. Used when Rerail is set up here and no
--packor--rules-refis given. - Throwaway: the checkout's
.rerail/rules/or the rules at--rules-ref, plus every--pack.
Worktree, --rules-ref and non-npm pack rules run in Log until approved with rerail rules approve.
Exact conditions and approval policy
Home applies when Rerail is started and set up in this checkout on this machine. It runs the rules as a session there
would. rulesSource is {"kind":"home"}; a throwaway configuration gives {"kind":"worktree"}, or
{"kind":"ref","ref":…} with --rules-ref.
Session rule approvals apply. These run in Log until a person approves that exact content in
the Rerail home with rerail rules approve:
- worktree rules;
- rules read from
--rules-ref; - rules of packs Rerail did not publish from npm (third-party, or installed from a folder or tarball).
Approval binds to the content digest. Approving a rule in a base-branch checkout also covers the same content read with
--rules-ref, and nothing else. Rerail's own npm packs need no approval.
#In CI
A CI runner starts with an empty Rerail home. Install packs, approve from the base branch's content (never the change under review), then scan the change:
# Rerail's own packs from npm: no approval needed.
rerail packs add typescript complexity
# A pack kept in the repository: install it from the base branch's checkout, then approve that version.
rerail packs add ./base/packs/acme
rerail rules approve @acme/rerail-pack-acme
# The repository's own rules: approve each as the base branch has it (rerail rules approve --repo ./base lists them).
rerail rules approve no-todo api-boundary --repo ./base
# Scan the change, judged by the base branch's rules.
rerail scan --repo ./head --scope git-diff --base origin/main --rules-ref origin/main \
--pack typescript --pack complexity --pack acme --json > rerail-scan.json./base is a base-branch checkout; ./head is the change. Unapproved rules still run, reported with "mode": "log".
#The report: rerail.scan/1
--json prints one document in this shape; fields may be added, but removing or changing one makes a new schema.
{
"schema": "rerail.scan/1",
"scanId": "6f0c…", // a new UUID per scan
"tool": { "name": "rerail", "version": "<version>" },
"startedAt": 1793732129819, "finishedAt": 1793732131165, // milliseconds since the epoch
"repository": { "key": "remote:github.com/org/repo", "displayName": "repo" }, // or "clone:<id>" without a remote
"checkout": { "path": "/abs/checkout", "head": "<sha>|null", "ref": "refs/heads/main|null" },
"scope": "repository" | "git-diff",
"base": null | { "ref": "origin/main", "mergeBase": "<sha>" },
"paths": null | ["src/a.ts"], // the files scanned, when not the whole checkout
"rulesSource": { "kind": "home" } | { "kind": "worktree" } | { "kind": "ref", "ref": "origin/main" },
"status": "completed" | "failed",
"rules": [
{ "ruleId": "no-todo", "payloadHash": "sha256:…", "mode": "log" | "steer" | "block",
"source": { "kind": "pack" | "library_rule" | "rerail_rule" | "ref", "id": "…", "packId": "…|null", "ref": "…" } }
],
"violations": [
{ "ruleId": "no-todo", "payloadHash": "sha256:…", "mode": "log", "code": "TODO", "clauseId": "todo",
"path": "src/a.ts", "start": { "line": 3, "column": 5 }, "end": { "line": 3, "column": 9 },
"message": "…", "fingerprint": "e7b8bfeee1c3c67007fbdad77d7df6bb" }
],
"failures": [ { "code": "adapter-error", "message": "…", "path": null, "ruleId": null } ],
"summary": { "violations": 1, "failures": 0 }
}- Positions: 1-based lines and columns;
endis exclusive. mode: the rule's effective mode where the violation is. A scan never steers.payloadHash: digest of the exact rule text that produced the finding.fingerprint: stable across scans, so you can tell new findings from existing ones.failures: execution failures and coverage gaps, as an audit records them (reference).
Exact field semantics
- Positions:
startis the match's first character;endis just past its last. Both are null for a violation without a source span. payloadHash:sha256:of the rule's canonical JSON, the same digest approvals and audits use.fingerprint: 32 hex characters,sha256(, whitespace runs collapsed to one space. It is stable while the rule, path and text are, even if the text moves in the file. When one rule matches the same text more than once in a file, the second and later matches also hash their ordinal, so fingerprints are unique within a scan. The text is never in the report.ruleId \0 path \0 matched text)