Headless Mode
Free · open source

rigscore

Checks an AI development setup's configuration for security, consistency and governance problems

Release details

Published

Latest release 2.2.0 · July 2026

rigscore is a command-line tool that checks how an AI coding agent is configured. It reads a project’s governance documents (such as CLAUDE.md or AGENTS.md), MCP (Model Context Protocol) server configs, permissions, skill files, Docker settings and secrets handling, and compares what the project’s rules say with what the configuration allows. For example, it flags a CLAUDE.md that forbids access to /etc while the MCP config mounts /. It covers the clients in the supported-clients matrix, including Claude Code, Cursor, Codex CLI and Gemini CLI.

A scan runs 28 checks (13 scored, 15 advisory) and prints two independent 100-point grades, each A–F: Hygiene for security-relevant configuration and Practice for how the team sets up and governs its agents. A repo with no practice surface prints Practice: n/a instead of 0/100.

Install

Run this in a project directory (Node >= 18.17):

1npx github:Back-Road-Creative/rigscore

Fetching the package is a network step. After that, a default scan reads local files, needs no account or token, and makes no network calls; --online and --semantic are opt-in exceptions, described under network use. Release notes: github.com/Back-Road-Creative/rigscore/releases.


Documentation

The manual is on this page:

Scope. rigscore measures configuration hygiene, not runtime security. It reads files on disk (governance docs, MCP configs, Docker settings, skill files, permissions) and scores what they say. It does not observe the running agent. Use it alongside a runtime scanner and source-level static analysis; see known limits.

Two scores

Every scan prints Hygiene and Practice, scored independently, so neither moves the other. The grade bands for both are under Scoring.

Network use

A default scan of an installed copy makes no network calls and sends nothing off the machine. Four things involve the network or an outside process:

  • Installation. npx github:… downloads the package from GitHub, and npx or npm may fetch its two runtime dependencies. The Docker image and the release-verification commands also download from GHCR (GitHub Container Registry) and GitHub.
  • --online opts in to outbound HTTP: probes of the sites you list under sites in .rigscorerc.json, lookups of the npm registry entries for your MCP server packages, and the official MCP registry (registry.modelcontextprotocol.io), whose response is cached under ~/.cache/rigscore/ for 24 hours and used to extend the typosquat check. --refresh-mcp-registry forces a refetch and implies --online. Scored checks still run without --online, but their online sub-checks are skipped.
  • --semantic runs your own agent CLI as a local process (claude -p by default, or the command in semantic.command) once per MCP tool description. rigscore itself makes no API call and needs no API key, but each description is passed to that CLI, and what the CLI does with the text, including sending it to its model provider, is outside rigscore’s control. See Semantic tool-description judge.
  • Local files. A scan may write .rigscore-state.json (hashes of MCP server shapes), and --record-score writes .rigscore-history.json. Neither is sent anywhere.

Sample output

  rigscore v2.2.0

  [X]   MCP server configuration  [mechanical]  CRITICAL "filesystem" mounts /
  [OK]  Cross-config coherence    [keyword]     governance matches config
  [ADV] Semantic tool judge       [pattern]     advisory — run with --semantic

  HYGIENE 78/100 (B)   ·   Practice 71/100 (B)
  Grade: B

  Each row's [mechanical] / [pattern] / [keyword] tag shows how its points
  are earned (see the legend below).

Why rigscore

  • Governance claims are checked against configuration. The coherence check compares what your governance files say with what your configs allow, such as a CLAUDE.md that forbids /etc next to an MCP config that mounts /, or a “no shell” rule next to a shell server with filesystem access. It shares the heaviest scored weight (14 of 100, with MCP configuration), and a coherence CRITICAL costs an extra 10 points on top of zeroing its own sub-check.
  • A second axis. Practice scores loop governance, spec goals, workflow maturity and sandbox posture. These checks carry zero Hygiene weight by default, so they do not change the Hygiene number unless a custom weights: map promotes one into the scored lane.
  • One scan covers many surfaces. Instructions, permissions, MCP, skills, hooks, CI, Docker and environment files are read in a single run, which produces the Hygiene grade (with an embeddable badge) and the Practice score.

Fix what it finds

rigscore . --fix dry-runs every auto-fixable issue — plus the starter packs that target your red checks — and writes nothing. --fix --yes applies the safe, file-level fixes to files you already have; --fix --yes --install-packs also scaffolds guard packs for the major AI clients wherever a check is red. To install a single pack on its own, run rigscore init --<pack>. The full flag ladder lives in the command reference.

What it checks

Scored checks (13 · 100 points)

AI-specific checks (MCP, coherence, skill files, governance docs) hold 48 of the 100 points; the rest cover secrets, container isolation, infrastructure, hygiene.

Advisory checks (15 · zero weight)

Advisory checks carry zero Hygiene weight; several score on the Practice axis instead.

CheckCategoryEnforcement
Agent output schemasgovernancemechanical
AI disclosuregovernancekeyword
CI agent capsprocesspattern
Documentation coverageprocessmechanical
Instruction effectivenessgovernancekeyword
Loop governanceprocesspattern
Memory hygienegovernancemechanical
Network exposureisolationmechanical
Sandbox postureisolationmechanical
Semantic tool-description judgesupply-chainpattern
Site securityisolationmechanical
Skill ↔ governance coherencegovernancekeyword
Spec goalsgovernancekeyword
Windows/WSL securityisolationmechanical
Workflow maturitygovernancekeyword

Scoring

ScoreGradeMeaning
90–100AStrong hygiene posture
75–89BGood foundation, some gaps
60–74CModerate risk, needs attention
40–59DSignificant gaps
0–39FCritical issues, fix immediately
  • CRITICAL zeros out its sub-check; a coherence CRITICAL costs an extra 10 points.
  • WARNING deducts 15 each (1 = 85, 2 = 70, 3 = 55); INFO deducts 2 each, floored at 50 with no WARNINGs.
  • PASS / SKIPPED: no impact.

Coverage scaling: unscannable checks are marked N/A and their weight redistributed; the score scales by min(1, W / 100) for applicable weight W.

The Practice score

Every scan prints a second 100-point axis. Hygiene asks is this rig safe? Practice asks does this team drive its agents well?

Practice checkWeight
Loop governance25
Spec goals20
Workflow maturity20
Sandbox posture15
CI agent caps10
Memory hygiene5
AI disclosure5

Practice checks contribute zero to Hygiene. A repo with no practice surface prints Practice: n/a, not an unfair 0/100; --json reports practiceScore (number or null). The coherence check and this second axis are covered in Why rigscore.

Enforcement-grade labels

Each check’s label shows how its points are earned; it is display-only.

  • [mechanical] — deterministic inspection of config and file state against known-bad constants, file modes or structural rules; changing prose does not change the result, and it sees only what it has a rule for. 15 of 28.
  • [pattern] — regex or structural scan; encoded or obfuscated content can evade it. 7 of 28.
  • [keyword] — phrase presence in governance prose, gameable by keyword-stuffing (see known limits). 6 of 28.

Scoring profiles

A profile is a weight map. Five ship built in:

ProfileUse-case
defaultBalanced AI dev environment audit
minimalSmoke test — AI-moat checks only
ciCI pipelines (identical to default today)
homeSingle-user dev boxes — infra/docker/windows off
monorepoMulti-project repos — hints --recursive --depth 3
npx github:Back-Road-Creative/rigscore --profile minimal

Resolution order: --profile, then project .rigscorerc.json, then ~/.rigscorerc.json, then default. Custom weights: promote an advisory check into the scored lane (non-zero) or demote a scored one (0).

Compliance report

--report compliance groups findings by framework control — deterministic text, diffable in CI or for an auditor:

npx github:Back-Road-Creative/rigscore --report compliance .
FrameworkStatusCoverage
OWASP Top 10 for Agentic Applications 2026Finalfull
OWASP MCP Top 10Beta (pilot)partial
NIST AI RMF 1.0Finalfull
EU AI Act — Regulation (EU) 2024/1689In force, phasedfull

This is a mapping of checks to framework controls, not a certification, audit result or statement of compliance. A check is listed under a control only where it produces evidence for it; controls no check supports print NOT EVIDENCED, and checks with no fitting control print UNMAPPED. “Full” coverage means every scored check is mapped, not that every control is satisfied. rigscore evidences technical controls in a repository; it cannot evidence your risk-management process, log retention or end-user disclosures. Muted findings (suppress: / --ignore) are disclosed by count and id. Not available with --recursive.

Limitations

rigscore checks whether configuration is present and well-formed; it does not enforce anything. Read this before using the score as a governance quality signal.

  • Semantic reversal bypasses keyword checks. The governance checks (governance docs + coherence, 24 of the 100 scoring points) only confirm your file mentions concepts like “path restrictions”; stuffed headers over a body that dismantles them still pass. See test/keyword-gaming.test.js for the bypass list.
  • Injection detection is pattern-based. Unicode-normalized patterns catch common prompt-injection; encoded payloads, rephrasings, and homoglyphs can evade them.
  • Config-shape pinning only, not runtime tool descriptions. rigscore hashes each MCP server’s configured shape — {command, args, envKeys} — and warns on change (CVE-2025-54136 / MCPoison class), but does not hash the tool descriptions a running server advertises. The mcp-hash / mcp-pin / mcp-verify workflow pins those operator-side.
  • Secret scanning covers named config files in the project root. Use --deep for recursive source, or a dedicated git-history secret scanner for git history.
  • Point-in-time snapshots only. No continuous monitoring, no git-history scan.
  • Score depends on project shape. rigscore ships 28 checks; an npm package legitimately sees most as N/A. rigscore itself is a package, not an agent workspace — no committed MCP config, no .claude/skills/, no per-client rule sets — so only a minority apply. See Dogfooding for the exact self-score.

Dogfooding

rigscore runs on rigscore in CI.

  • Self-score 37/100 (Grade F). As an npm package only 10 of its 28 apply (weight 46/100), the rest N/A.
  • CI threshold --fail-under 30. The baseline (37) minus a 7-point buffer; the public default is 70.
  • .rigscorerc.json disables four checks (infrastructure-security, skill-coherence, workflow-maturity, agent-output-schemas) needing artifacts rigscore doesn’t ship.

CI integration

GitHub Actions

1- uses: Back-Road-Creative/rigscore@v2.2.0
2  with:
3    fail-under: 70
4    upload-sarif: true

Or run directly:

- run: npx github:Back-Road-Creative/rigscore --ci --fail-under 70

Pin to a released tag (the action rejects @main-style refs); tags through v2.2.0 are available.

SARIF

rigscore emits SARIF v2.1.0: npx github:Back-Road-Creative/rigscore --sarif > results.sarif, uploaded via github/codeql-action/upload-sarif.

Baseline gate

Gate on new findings, not an absolute score: the first run writes the baseline; later runs report only findings not in it and exit 1 if any exist:

npx github:Back-Road-Creative/rigscore --baseline .rigscore-baseline.json

Commit the baseline: the gate reads the HEAD copy, so a deleted or corrupt working-tree baseline fails closed. Refresh with --baseline-refresh.

State file and MCP-shape gate

With a repo-level .mcp.json, a scan writes .rigscore-state.json: a SHA-256 pin of each MCP server’s {command, args, envKeys} shape (env keys only, never values). A changed pin flags a silent swap of a trusted server (the MCPoison class, CVE-2025-54136); an uncommitted pin detects nothing.

npx github:Back-Road-Creative/rigscore --verify-state

--verify-state is the read-only CI gate: it reads the pin at HEAD (a fresh pin can’t satisfy it) and exits 1 on drift, 2 if missing or corrupt, 0 if all match. --no-state-write skips the write on a borrowed checkout, flagging the lost coverage.

Runtime tool pinning

The state file above pins each MCP server’s configured shape. The tool descriptions a running server advertises are pinned separately, on demand — rigscore never launches the server itself (running it would execute code from the server you are trying to vet), so it uses a print-and-paste workflow:

1npx -y <mcp-server-package> | rigscore mcp-hash | xargs rigscore mcp-pin <server>   # pin
2npx -y <mcp-server-package> | rigscore mcp-verify <server>                          # verify later

rigscore mcp-hash canonicalizes and hashes a tools/list JSON read from stdin; mcp-pin stores it in .rigscore-state.json; mcp-verify re-compares. Verify exits 0 on a match, 3 when nothing is pinned for that server, and 4 on drift — a tool description that silently changed under a trusted server (the CVE-2025-54136 rug-pull class). Each server also gets a zero-weight INFO during a normal scan showing whether its runtime hash is pinned.

Exit codes

CodeMeaning
0At or above --fail-under (baseline: no new findings)
1Below --fail-under, or new findings vs baseline
2Config error — bad .rigscorerc.json, unknown --profile, or corrupt baseline
3rigscore mcp-verify <server> with no runtime hash pinned
4rigscore mcp-verify <server> drift — the piped tools/list no longer matches the pinned runtime hash

Command reference

Scoring, compliance mapping and CI gates are above; this section covers the working-session commands and packaging.

Auto-fix and starter packs

--fix identifies safe, reversible remediations — and offers the starter packs that target your red checks. Consent is layered: dry run by default, --yes unlocks file-level edits to files you already have, --install-packs additionally allows scaffolding new files:

1npx github:Back-Road-Creative/rigscore --fix                        # dry run: lists auto-fixes AND installable packs, writes nothing
2npx github:Back-Road-Creative/rigscore --fix --yes                  # applies auto-fixes; packs are offered, not installed
3npx github:Back-Road-Creative/rigscore --fix --yes --install-packs  # also installs the packs targeting your red checks

--fix never rewrites governance content, and a pack install never overwrites an existing file — it is reported skipped (exists) and left byte-for-byte alone. To install one specific pack, or overwrite deliberately:

1npx github:Back-Road-Creative/rigscore init --list-packs             # what ships, and which checks each pack targets
2npx github:Back-Road-Creative/rigscore init --<pack> [dir] [--force] # install one pack directly
The packs that ship

Seven guard packs ship with rigscore. Each targets a specific failing check:

PackTurns greenWhat it installs
guardsClaude settings · git hooksdeny rules, an expiring permissions manifest, and a working pre-commit secret scan
docsgovernance docsone vendor-neutral AGENTS.md agent contract plus a CLAUDE.md that defers to it
containerDocker security · network exposurea devcontainer with an egress-proxy allowlist — the agent reaches only the hosts you list
cursor-guardssandbox posturea narrow Cursor terminal/MCP allowlist with no auto-run wildcard
codex-guardssandbox posturea least-privilege Codex CLI baseline — always-prompt approvals, a workspace-write sandbox, network off
gemini-guardssandbox posturea Gemini CLI baseline where every tool call prompts instead of auto-approving edits or shell
opencode-guardssandbox posturean opencode ask/deny permission block so no shell, edit, or fetch auto-runs without approval
Hardening an existing config

By default a pack install never touches a file you already have — an existing config is reported skipped (exists) and left byte-for-byte alone. To fold a pack’s keys into an existing JSON or YAML config instead of scaffolding a new one, add a merge mode:

1npx github:Back-Road-Creative/rigscore init --<pack> --<mode>   # <mode>: merge (alias: harden)

In merge mode, absent keys are added, arrays are unioned, and existing values, comments, and key order are all preserved — it is idempotent, so re-running changes nothing. Merge is mutually exclusive with --force (which overwrites); when both are supplied, merge wins.

Recursive / monorepo mode

--recursive discovers project subdirectories (any recognizable marker file: package.json, pyproject.toml, Dockerfile, CLAUDE.md, …) and scans each independently, four at a time. The overall score is the average across discovered projects; each project’s own .rigscorerc.json is honored.

1npx github:Back-Road-Creative/rigscore . --recursive
2npx github:Back-Road-Creative/rigscore . -r --depth 2   # two levels, e.g. workspace/_active/svc-foo

Suppressing findings

Mute a finding by its stable ID via the flag or .rigscorerc.json:

1npx github:Back-Road-Creative/rigscore --ignore "env-exposure/env-not-gitignored,skill-files/shell-exec"
1{ "suppress": ["env-exposure/env-not-gitignored"] }
Pattern forms

Each suppress entry is matched one of three ways (all case-insensitive):

  • Exact ID — a full <check-id>/<slug> such as env-exposure/env-not-gitignored; a bare <check-id> such as skill-files mutes every finding from that check.
  • Glob — any entry containing * is a glob against the finding ID: skill-files/* mutes that check’s findings, **/shell-exec matches the slug across every check (* stays within a path segment, ** spans /).
  • Regex — an entry that begins re:/…/ is a regular expression tested against both the finding ID and its title, e.g. re:/inject|exfil/.

A plain word that is neither an exact ID nor a glob falls back to a case-insensitive substring match on the finding title — handy, but broad: token mutes every finding whose title contains “token”. Prefer an ID or a re:/…/ form when you need precision.

Suppression is never silent: the terminal report, JSON (suppressed: { count, ids }), and SARIF all disclose how many findings were muted and which. IDs follow <check-id>/<slug>, are stable within a major version, and a bare <check-id> mutes a whole check. Full catalog: docs/FINDING_IDS.md.

Semantic tool-description judge

Static regex checks match known prompt-injection phrasings; a tool description that paraphrases the same intent can slip past them. The opt-in --semantic judge adds a model-backed second look:

1npx github:Back-Road-Creative/rigscore --semantic

It runs only when you pass --semantic. For each tool description (read from the tools/list snapshot files listed under paths.mcpToolsSnapshot in .rigscorerc.json, the same JSON you pipe into rigscore mcp-hash), it asks your own agent CLI to classify the text as benign or suspicious: claude -p by default, or the command set in semantic.command (gemini, codex exec, and so on). The classification prompt, with the description inside it, is passed to that CLI as its final argument. rigscore uses no API key and no SDK client, but the text is processed by whatever model your CLI uses, so this is not an offline check. Each description is wrapped in a data-only frame and the judge is told to treat it as data. That framing reduces the chance that a crafted description steers the verdict; it does not rule it out, and a model’s verdict can be wrong in either direction. If the configured binary isn’t on PATH, the check skips with no finding. It scores on the advisory (zero-weight) lane; enforcement grade pattern.

CycloneDX AI-BOM export

--cyclonedx prints a CycloneDX 1.6 BOM of the AI components a scan discovers: every repo-level MCP server as a component (with version + purl when the package is stably pinned), AI client configs and governance files with SHA-256 content digests, and a dependency graph. AI facts (transport, launch command, declared env-var names, config-shape hash) ride on properties rows.

1npx github:Back-Road-Creative/rigscore --cyclonedx . > ai-bom.json

Repo-scoped on purpose — home-dir client configs never land in a shippable BOM. Not combinable with --recursive.

Docker image

Every v*.*.* release tag publishes an image to GHCR. It runs as a non-root user and scans /workspace by default:

1docker run --rm -v "$PWD:/workspace" ghcr.io/back-road-creative/rigscore:<tag>

Explain a finding

rigscore explain <findingId> prints the docs page for the check behind a finding, jumping to the finding-specific section when one exists:

1npx github:Back-Road-Creative/rigscore explain skill-files/indirect-injection

Watch mode

--watch re-runs rigscore when relevant files change — governance files, MCP configs, .env, Docker Compose files, git hooks, .rigscorerc.json — debounced at 500ms:

1npx github:Back-Road-Creative/rigscore --watch

Pre-commit hooks

Two ways to run rigscore before every commit:

  • Built-in — rigscore --init-hook writes a git pre-commit hook that runs a scan with --fail-under 70.
  • pre-commit.com framework — rigscore ships a .pre-commit-hooks.yaml, so a repo already using the pre-commit framework adds it as a hook:
1repos:
2  - repo: https://github.com/Back-Road-Creative/rigscore
3    rev: v2.2.0
4    hooks:
5      - id: rigscore

Sharing one config across repos

A .rigscorerc.json can inherit another config with extends, so a team maintains one hardened baseline and each repo layers its own overrides on top:

1{
2  "extends": "../shared/.rigscorerc.json",
3  "suppress": ["env-exposure/env-not-gitignored"]
4}

extends takes a local path or an array of them (later entries win); the file that declares extends outranks the base it inherits, so a repo always overrides the shared defaults. Bases are resolved recursively and cycles are rejected. Values are read from disk only — an http(s):// target is refused, never fetched, so extends never adds egress.

Plugins

rigscore auto-discovers rigscore-check-* packages (scoped @org/rigscore-check-* too) from node_modules and runs them as extra checks — no core changes needed. Plugins default to weight 0 (advisory); give one scoring weight via .rigscorerc.json:

1{ "weights": { "my-custom": 5 } }

An invalid plugin warns to stderr and is skipped — it never crashes the scan.

More flags

FlagWhat it does
--badgeGenerate a markdown score badge for your README
--badge-format <f>Badge format: markdown (default, shields.io image snippet), endpoint (shields.io Endpoint Badge JSON, for a README badge that updates itself), or svg (self-contained, no network)
--check <id>Run a single check; an N/A check reports n/a and exits 0, not a red 0/100
--code-qualityOutput a GitLab Code Quality report (CodeClimate JSON)
--junitOutput JUnit XML — one testcase per check, for Jenkins, Azure Pipelines and GitLab
--quiet / -qSummary-only output: score, grade, posture and finding counts. For pre-commit hooks and terse CI logs
--record-scoreAppend this scan’s score to .rigscore-history.json (opt-in)
--trendPrint the recorded score history and deltas, then exit — read-only; --record-score is what writes it
--cta / --no-ctaShow (--cta) or hide (--no-cta) the promotional call-to-action footer after a terminal scan — off by default; --ci implies --no-cta
--include-home-skillsAlso scan the home-scope skill, command, and prompt directories of every registered client — ~/.claude/skills, ~/.claude/commands, ~/.codex/prompts, ~/.gemini/commands, and the rest — instead of project scope only
--init-hookInstall a pre-commit hook that runs rigscore with --fail-under 70 before each commit
--refresh-mcp-registryForce refetch of the MCP registry cache (implies --online, bypasses the 24h TTL)

Troubleshooting & FAQ

  • Which clients does rigscore scan? See the supported-clients matrix — every governance file, MCP config, sandbox, and skill directory rigscore reads, listed per client.
  • Why is my score capped below Grade A? Without a --deep scan, a Dockerfile, and infrastructure paths, the reachable weight ceiling is 80, so a repo missing those surfaces tops out at Grade B even with every check passing. That is by design — the absent checks are N/A (weight redistributed via min(1, W / 100)), not failing.

For deeper issues — config parse errors, unexpected exit codes, CI setup — see the product TROUBLESHOOTING guide.

Supported clients

rigscore reads one client registry and scans, scores and pins whichever of these surfaces exist in your repo. No flag turns a client on; if the file is there, it is scanned.

Each row lists only the surfaces a client has: its instruction file (CLAUDE.md, AGENTS.md, GEMINI.md, …); its MCP config (a committed repo config is what a pull request can mutate, so it’s exactly what the CVE-2025-54136 rug-pull pin covers — a ~/ home config is scanned but never pinned); its sandbox boundary; and its skill dirs (slash-command / skill / prompt directories scanned for hijack and exfil, with home dirs gated behind --include-home-skills).

The registry

ClientInstruction fileMCP configSandboxSkill / command dirs
Claude CodeCLAUDE.md.mcp.json (repo), ~/.claude.json.claude/settings.json, .claude/settings.local.json.claude/commands, .claude/skills (repo + home)
Claude Desktop—~/.claude/claude_desktop_config.json——
Cursor.cursorrules.cursor/mcp.json (repo + home).cursor/permissions.json—
Windsurf.windsurfrules~/.windsurf/mcp.json——
Cline.clinerules~/.cline/mcp_settings.json——
Continue.continuerules~/.continue/config.json——
GitHub Copilotcopilot-instructions.md, .github/copilot-instructions.md.vscode/mcp.json (repo)——
Codex CLIAGENTS.mdin .codex/config.toml (TOML).codex/config.toml (repo + home)~/.codex/prompts
Aider.aider.conf.yml———
Gemini CLIGEMINI.md.gemini/settings.json (repo + home).gemini/settings.json.gemini/commands (repo + home)
opencodeAGENTS.mdopencode.json (repo), ~/.config/opencode/opencode.jsonopencode.json / home config.opencode/commands, ~/.config/opencode/commands
Amp—~/.amp/mcp.json——
Zed—~/.config/zed/settings.json——
Amazon Q Developer.amazonq/rules/ (dir).amazonq/mcp.json, .amazonq/default.json (repo + ~/.aws/amazonq)——
Roo Code.roorules.roo/mcp.json (repo)——
Cody—.vscode/settings.json (cody.mcpServers)——
JetBrains Junie.junie/guidelines.md.junie/mcp/mcp.json (repo + home)——
Goose.goosehintsin ~/.config/goose/config.yaml (YAML)——
Warp—.warp/.mcp.json (repo + home)——
Kiro.kiro/steering/ (dir).kiro/settings/mcp.json (repo + home)——
Qwen CodeQWEN.md.qwen/settings.json (repo + home)——
CrushCRUSH.md.crush.json / crush.json (repo), ~/.config/crush/crush.json——
OpenClaw—~/.openclaw/openclaw.json (mcp.servers)——
AntigravityAGENTS.md~/.gemini/antigravity/mcp_config.json——

A dash means the client has no such surface, or none at a stable path rigscore can resolve. Codex and Goose keep their MCP servers in TOML and YAML respectively, so the JSON MCP reader doesn’t parse them — their servers surface through the sandbox and credential readers instead.

Directory-form rule sets

Some clients read a directory of rule files rather than one file. rigscore scans these by default, so a repo governed only by .cursor/rules/*.mdc, for example, still counts as governed:

DirectoryRead byFiles
.cursor/rules/Cursor*.mdc
.windsurf/rules/Windsurfany non-dotfile
.clinerules/Clineany non-dotfile
.github/instructions/GitHub Copilot*.instructions.md
.amazonq/rules/Amazon Q*.md
.kiro/steering/Kiro*.md

Example configs

Starter configurations for the common clients live in the product repo under docs/examples/ — ready-to-copy baselines for claude, cursor, cline, continue, copilot, windsurf, aider, and a vendor-neutral agents-md. For opinionated, check-targeting baselines you can install in place, use the guard packs (rigscore init --list-packs).

Verify rigscore

Below is the full verification recipe for the current release, v2.2.0. Substitute the tag you are checking.

The canonical reference for these commands lives in the rigscore README — see the Verify this tool section. This section mirrors it for readers who land here first.

1. What a release includes

Each release built by the signed-release workflow (.github/workflows/release-provenance.yml) carries:

  • A Sigstore-backed build-provenance attestation generated by GitHub Actions for the tarball and the SBOM.
  • A CycloneDX SBOM (software bill of materials) listing dependencies, runtime and transitive.

The repository also publishes a bypass-test catalog of cases rigscore does not catch (see step 6). The recipe below checks that a downloaded file matches what the release workflow produced; it does not review the source code.

2. Tag signature

1git verify-tag v2.2.0

Tag signing is optional for maintainers, so this command can fail on a tag that was not signed. The attestation in step 3 is the main check.

3. Provenance attestation

Two commands:

1gh release download v2.2.0 --repo Back-Road-Creative/rigscore --pattern '*.tgz'
2gh attestation verify rigscore-2.2.0.tgz --owner Back-Road-Creative

One-liner equivalent (downloads, verifies, cleans up):

1scripts/verify-release.sh v2.2.0

As written, gh attestation verify ... --owner Back-Road-Creative passes when the file’s hash has a valid Sigstore attestation issued to a workflow in the Back-Road-Creative GitHub organization. The attestation certificate also records the repository, workflow and commit, but this command does not require particular values for them. The release workflow itself runs on any v* tag push or manual dispatch. The recipe has not been tested here against a stricter gh invocation, so treat the repository, workflow and ref as recorded in the certificate rather than enforced by this command.

What a result tells you:

  • Pass: the file has an attestation from that organization’s GitHub Actions, and its hash matches the attested one.
  • Fail: the file does not match an attestation, for example because it was altered or built elsewhere.
  • Neither case shows that the source at the tag is free of malicious changes, or that the maintainers cannot publish an attested release.

4. SBOM review

Every release bundles a CycloneDX SBOM:

1gh release download v2.2.0 --repo Back-Road-Creative/rigscore --pattern 'sbom.cdx.json'
2cat sbom.cdx.json | jq '.components[].name' | sort -u

rigscore has two runtime dependencies:

  • chalk — terminal coloring
  • yaml — YAML parsing for governance files

The SBOM lists ~50 components total because it includes the dev/test transitive graph (vitest, esbuild, chai). Everything not listed under dependencies in package.json is dev-only — present at build time, absent at run time. To see the runtime-only set:

1node -e "const p=require('./package.json');console.log(Object.keys(p.dependencies))"

The runtime dependency list is intentionally short, which keeps the set of packages to review small.

5. Reproducible bundle hash

Rebuild the tarball locally and compare hashes:

1git clone https://github.com/Back-Road-Creative/rigscore.git
2cd rigscore && git checkout v2.2.0
3nvm use 20      # match the Node version the release workflow used
4npm ci          # package-lock.json is the anchor
5npm pack
6sha256sum rigscore-2.2.0.tgz

Ask the release what the published digest is, rather than trusting a hash typed on this page:

1gh release view v2.2.0 --repo Back-Road-Creative/rigscore \
2  --json assets --jq '.assets[] | select(.name | endswith(".tgz")) | "\(.digest | sub("^sha256:";""))  \(.name)"'

GitHub records the digest on the asset itself, and that --jq prints it in exactly sha256sum format — so the two outputs compare line for line, and there is no number here to go stale. Or download the asset and hash it yourself:

1gh release download v2.2.0 --repo Back-Road-Creative/rigscore --pattern '*.tgz'
2sha256sum rigscore-2.2.0.tgz

Caveats. npm pack is reproducible across the same Node minor version when package-lock.json is committed (it is); cross-minor or different npm versions can shift tar headers. If your local hash differs but the step-3 attestation verifies, the attestation is the stronger signal and the hash recipe is a sanity check. The published digest and the tarball both come from GitHub, so this step shows the build can be reproduced, not that it is independent of GitHub; step 3 is what ties the artifact to a workflow build.

6. Public bypass tests

The rigscore repository publishes tests that record cases rigscore does not catch:

They record current behavior: a change that closes one of these gaps turns the matching test into a positive assertion. Treat anything the test suite does not assert as not caught.

7. Threat model

The full attack-surface and out-of-scope catalog lives in the rigscore repo:

  • THREAT-MODEL.md — what rigscore inspects, what it doesn’t, and the trust boundaries.
  • docs/known-limits.md — concrete examples of attacks rigscore will not detect, with pointers to tools that will.

If you need a check rigscore does not implement, file an issue with a fixture.

Source and releases

← All software