Reads a project’s AI configuration — governance docs, MCP server configs, permissions, skill files — and checks it against what the project’s own rules claim, so drift between “written down” and “actually enforced” gets caught instead of assumed away.
One local command runs 28 checks — 13 scored plus 15 advisory — over MCP configs, skill files, governance docs, secrets, container isolation and infrastructure, and prints two independent 100-point grades, each A–F: Hygiene, the security axis, and Practice — does this team drive its agents well? Most scanners grade the config; rigscore also grades the workflow.
Requires Node >= 18.17. Fully offline: no token, no account, no data leaves the machine unless you
pass --online. Release notes: github.com/Back-Road-Creative/rigscore/releases.
Documentation
The full manual, on this page: what it checks, scoring, fixing what it finds, known limits, CI integration, the command reference, the supported-clients matrix and the release-verification recipe.
Scope. rigscore measures configuration hygiene, not runtime security: it reads the files on disk — governance docs, MCP configs, Docker settings, skill files, permissions — and scores what they say. Pair it with a runtime scanner and source-level SAST; see known limits and verify rigscore.
Two scores
One local command runs 28 checks — 13 scored plus 15 advisory — and prints two independent 100-point scores, each A–F: the Hygiene score (the security axis) and Practice. Fully offline: no token, no data leaves the machine.
npx github:Back-Road-Creative/rigscoreRequires Node >= 18.17. --online adds site probes and MCP supply-chain checks.
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
- The only cross-config coherence pass. rigscore reads your governance claims and checks them against your actual configuration, catching contradictions single-surface scanners miss — a
CLAUDE.mdthat forbids/etcwhile the MCP config mounts/, a “no shell” rule sitting next to a shell server with filesystem access. A config that is honestly insecure scores better than one that lies about its posture. - A second axis nobody else scores. Alongside Hygiene, every scan prints a Practice score — does this team drive its agents well? — from loop governance, spec goals, workflow maturity, and sandbox posture. Most scanners grade the config, rigscore also grades the workflow.
- Full power offline, whole surface, one score. Every scored check runs with no token, no account, and no data leaving the machine (
--onlineonly adds optional probes) — and instructions, permissions, MCP, skills, hooks, CI, Docker, and env all fold into one A–F grade and an embeddable badge, not a single-tool silo.
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)
| Check | Weight | Category |
|---|---|---|
| Cross-config coherence | 14 | governance |
| MCP server configuration | 14 | supply-chain |
| Governance documentation | 10 | governance |
| Skill file safety | 10 | supply-chain |
| Claude settings safety | 8 | governance |
| Deep source secrets | 8 | secrets |
| Secret exposure | 8 | secrets |
| Credential storage hygiene | 6 | secrets |
| Docker security | 6 | isolation |
| Infrastructure security | 6 | process |
| Permissions hygiene | 4 | process |
| Unicode steganography | 4 | governance |
| Git hooks | 2 | process |
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.
| Check | Category | Enforcement |
|---|---|---|
| Agent output schemas | governance | mechanical |
| AI disclosure | governance | keyword |
| CI agent caps | process | pattern |
| Documentation coverage | process | mechanical |
| Instruction effectiveness | governance | keyword |
| Loop governance | process | pattern |
| Memory hygiene | governance | mechanical |
| Network exposure | isolation | mechanical |
| Sandbox posture | isolation | mechanical |
| Semantic tool-description judge | supply-chain | pattern |
| Site security | isolation | mechanical |
| Skill ↔ governance coherence | governance | keyword |
| Spec goals | governance | keyword |
| Windows/WSL security | isolation | mechanical |
| Workflow maturity | governance | keyword |
Scoring
| Score | Grade | Meaning |
|---|---|---|
| 90–100 | A | Strong hygiene posture |
| 75–89 | B | Good foundation, some gaps |
| 60–74 | C | Moderate risk, needs attention |
| 40–59 | D | Significant gaps |
| 0–39 | F | Critical 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 check | Weight |
|---|---|
| Loop governance | 25 |
| Spec goals | 20 |
| Workflow maturity | 20 |
| Sandbox posture | 15 |
| CI agent caps | 10 |
| Memory hygiene | 5 |
| AI disclosure | 5 |
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 cross-config coherence pass and this second axis are what set rigscore apart — see Why rigscore.
Enforcement-grade labels
Each check’s label shows how its points are earned; it is display-only.
[mechanical]— deterministic config inspection, ungameable by wording. 15 of 28.[pattern]— regex/structural scan, evadable only by novel obfuscation. 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:
| Profile | Use-case |
|---|---|
default | Balanced AI dev environment audit |
minimal | Smoke test — AI-moat checks only |
ci | CI pipelines (identical to default today) |
home | Single-user dev boxes — infra/docker/windows off |
monorepo | Multi-project repos — hints --recursive --depth 3 |
npx github:Back-Road-Creative/rigscore --profile minimalResolution 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 .| Framework | Status | Coverage |
|---|---|---|
| OWASP Top 10 for Agentic Applications 2026 | Final | full |
| OWASP MCP Top 10 | Beta (pilot) | partial |
| NIST AI RMF 1.0 | Final | full |
| EU AI Act — Regulation (EU) 2024/1689 | In force, phased | full |
The table only claims what it can prove: controls with no supporting check print NOT EVIDENCED, and unmapped checks print UNMAPPED. Muted findings (suppress: / --ignore) are disclosed by count and id. Not with --recursive.
Limitations
rigscore is a configuration presence checker, not an enforcement tool. Read this before relying on 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.jsfor 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. Themcp-hash/mcp-pin/mcp-verifyworkflow pins those operator-side. - Secret scanning covers named config files in the project root. Use
--deepfor 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). The real score: 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.jsondisables 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 70Pin 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.jsonCommit 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 (that would hand code execution to the thing you distrust), 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
| Code | Meaning |
|---|---|
0 | At or above --fail-under (baseline: no new findings) |
1 | Below --fail-under, or new findings vs baseline |
2 | Config error — bad .rigscorerc.json, unknown --profile, or corrupt baseline |
3 | rigscore mcp-verify <server> with no runtime hash pinned |
4 | rigscore 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 in the box. Each turns a specific red check green:
| Pack | Turns green | What it installs |
|---|---|---|
guards | Claude settings · git hooks | deny rules, an expiring permissions manifest, and a working pre-commit secret scan |
docs | governance docs | one vendor-neutral AGENTS.md agent contract plus a CLAUDE.md that defers to it |
container | Docker security · network exposure | a devcontainer with an egress-proxy allowlist — the agent reaches only the hosts you list |
cursor-guards | sandbox posture | a narrow Cursor terminal/MCP allowlist with no auto-run wildcard |
codex-guards | sandbox posture | a least-privilege Codex CLI baseline — always-prompt approvals, a workspace-write sandbox, network off |
gemini-guards | sandbox posture | a Gemini CLI baseline where every tool call prompts instead of auto-approving edits or shell |
opencode-guards | sandbox posture | an 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 asenv-exposure/env-not-gitignored; a bare<check-id>such asskill-filesmutes every finding from that check. - Glob — any entry containing
*is a glob against the finding ID:skill-files/*mutes that check’s findings,**/shell-execmatches 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 catch known prompt-injection phrasings; an attacker who paraphrases the same intent into a natural-sounding MCP tool description slips past them. The opt-in --semantic judge closes that gap:
1npx github:Back-Road-Creative/rigscore --semantic
It runs only when you pass --semantic — a default scan makes zero external calls from it. 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 first-party agent CLI to classify the text benign or suspicious: your claude CLI in print mode by default, or whatever you set in semantic.command (gemini, codex exec, …). No API key, no SDK client. Each description is wrapped in a data-only frame and the judge is told to treat it as data, not instructions, so a poisoned description can’t hijack the judge. If the configured binary isn’t on PATH, the check skips cleanly — no finding, no crash. 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-hookwrites 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
| Flag | What it does |
|---|---|
--badge | Generate 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-quality | Output a GitLab Code Quality report (CodeClimate JSON) |
--junit | Output JUnit XML — one testcase per check, for Jenkins, Azure Pipelines and GitLab |
--quiet / -q | Summary-only output: score, grade, posture and finding counts. For pre-commit hooks and terse CI logs |
--record-score | Append this scan’s score to .rigscore-history.json (opt-in) |
--trend | Print the recorded score history and deltas, then exit — read-only; --record-score is what writes it |
--cta / --no-cta | Show (--cta) or hide (--no-cta) the promotional call-to-action footer after a terminal scan — off by default; --ci implies --no-cta |
--include-home-skills | Also 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-hook | Install a pre-commit hook that runs rigscore with --fail-under 70 before each commit |
--refresh-mcp-registry | Force 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
--deepscan, 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 viamin(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 a single client registry — one source of truth for every AI coding tool it knows about — and scans, scores, and rug-pull-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 genuinely 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
| Client | Instruction file | MCP config | Sandbox | Skill / command dirs |
|---|---|---|---|---|
| Claude Code | CLAUDE.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 Copilot | copilot-instructions.md, .github/copilot-instructions.md | .vscode/mcp.json (repo) | — | — |
| Codex CLI | AGENTS.md | in .codex/config.toml (TOML) | .codex/config.toml (repo + home) | ~/.codex/prompts |
| Aider | .aider.conf.yml | — | — | — |
| Gemini CLI | GEMINI.md | .gemini/settings.json (repo + home) | .gemini/settings.json | .gemini/commands (repo + home) |
| opencode | AGENTS.md | opencode.json (repo), ~/.config/opencode/opencode.json | opencode.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 | .goosehints | in ~/.config/goose/config.yaml (YAML) | — | — |
| Warp | — | .warp/.mcp.json (repo + home) | — | — |
| Kiro | .kiro/steering/ (dir) | .kiro/settings/mcp.json (repo + home) | — | — |
| Qwen Code | QWEN.md | .qwen/settings.json (repo + home) | — | — |
| Crush | CRUSH.md | .crush.json / crush.json (repo), ~/.config/crush/crush.json | — | — |
| OpenClaw | — | ~/.openclaw/openclaw.json (mcp.servers) | — | — |
| Antigravity | AGENTS.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
Modern clients read a directory of rule files rather than one file. rigscore scans these by default, so a repo governed only by, say, .cursor/rules/*.mdc still counts as governed:
| Directory | Read by | Files |
|---|---|---|
.cursor/rules/ | Cursor | *.mdc |
.windsurf/rules/ | Windsurf | any non-dotfile |
.clinerules/ | Cline | any 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 any signed tag.
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. Why verify
rigscore inspects your AI agent’s configuration for supply-chain risk. If the tool itself has supply-chain risk, you’re auditing one black box with another. Every signed release ships with:
- A Sigstore-backed build-provenance attestation generated by GitHub Actions, tying the artifact to a specific commit and workflow on this repo.
- A CycloneDX SBOM listing every dependency, runtime and transitive.
- A public bypass-test catalog documenting cases rigscore intentionally does NOT catch.
2. Tag signature
1git verify-tag v2.2.0
Tag signing is opt-in for rigscore maintainers. The authoritative signal is the build attestation in step 3: generated by GitHub Actions on a clean runner, it binds the artifact to a specific workflow run rather than to whoever holds a signing key.
3. Provenance attestation (the canonical check)
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
A green result means: this exact tarball was built by GitHub Actions on Back-Road-Creative/rigscore, at the commit pointed to by v2.2.0, by the workflow .github/workflows/release-provenance.yml, and signed via Sigstore keyless OIDC against the GitHub Actions identity.
What this rules out:
- A maintainer cannot silently publish a tarball built on a laptop.
- A release asset cannot be swapped post-hoc — the hash in the attestation is bound to a Sigstore-signed certificate.
- A release cannot be backdated. The Rekor entry is timestamped at signing.
4. SBOM review
Every release bundles a CycloneDX 1.6 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, full stop:
chalk— terminal coloringyaml— 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))"
A two-dependency runtime surface is intentional: the attack surface for a rigscore install is the smaller of GitHub itself and those two well-known packages.
5. Reproducible bundle hash
Rebuild the tarball locally and compare bytes:
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, trust the attestation — the hash recipe is a sanity check, not the primary signal. Note also that the published digest and the tarball both come from GitHub, so this step establishes reproducibility, not independence; step 3 is what binds the artifact to a build.
6. Public bypass tests
We publish the cases rigscore intentionally does NOT catch:
test/keyword-gaming.test.js— checks that match on string presence rather than semantics.test/mcp-evasion.test.js— MCP server configurations that slip past typosquat / scope checks.test/injection-evasion.test.js— prompt-injection patterns the unicode and skill-file checks do not flag.test/ansi-injection.test.js— ANSI-control-sequence injection in governance files.
They lock the current behavior — a future PR that closes one of these gaps flips the corresponding characterization test into a positive assertion. Do not assume rigscore catches anything that is not asserted in the test suite.
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
- GitHub: github.com/Back-Road-Creative/rigscore
- Releases: github.com/Back-Road-Creative/rigscore/releases
- Command reference — auto-fix, packs, monorepo, AI-BOM, watch, plugins
- Supported clients — every governance file, MCP config, sandbox, and skill dir rigscore reads, per client
- Install:
npx github:Back-Road-Creative/rigscore· License: MIT