Docs · v0.2.1
Scorecard docs
sc is a local code-quality gate. It picks one language pack, runs that pack's tools, and prints a scorecard an agent can act on. This page summarizes the v0.2.1 README and docs. Each section links to the full text on GitHub.
Install
Release v0.2.1 ships a signed macOS installer package, a signed and notarized disk image, and .tar.gz archives for macOS and Linux. Each archive holds sc, sc-mcp, LICENSE and README.md at the top level. Install sc-mcp only if you use the MCP server.
macOS installer package
sc-v0.2.1-macos.pkg
The installer puts sc and sc-mcp in /usr/local/bin. It creates the console user config when needed and keeps an existing file.
macOS disk image
sc-v0.2.1-universal-apple-darwin.dmg
The universal image is signed with Developer ID and notarized. It contains Install Scorecard.pkg and INSTALL.txt. Open the package to install the commands. Requires macOS 11 or later on Apple silicon, or macOS 10.12 or later on Intel.
macOS tarball
curl -fsSLO \
https://github.com/moonbase2090/Scorecard/releases/download/v0.2.1/sc-v0.2.1-$(uname -m | sed s/arm64/aarch64/)-apple-darwin.tar.gz
tar -xzf sc-v0.2.1-*-apple-darwin.tar.gz sc sc-mcp
sudo install -d /usr/local/bin && sudo install -m 755 sc sc-mcp /usr/local/bin/Linux tarball
x86_64 and aarch64, glibc (*-unknown-linux-gnu). The command picks yours with uname -m.
curl -fsSLO \
https://github.com/moonbase2090/Scorecard/releases/download/v0.2.1/sc-v0.2.1-$(uname -m)-unknown-linux-gnu.tar.gz
tar -xzf sc-v0.2.1-$(uname -m)-unknown-linux-gnu.tar.gz sc sc-mcp
sudo install -m 755 sc sc-mcp /usr/local/bin/Verify the download
SHA256SUMS on the release lists every asset. Run this in the folder you downloaded into. --ignore-missing skips the assets you didn't download.
curl -fsSLO https://github.com/moonbase2090/Scorecard/releases/download/v0.2.1/SHA256SUMS
shasum -a 256 -c --ignore-missing SHA256SUMSOn Linux, check with sha256sum instead:
sha256sum -c --ignore-missing SHA256SUMSFrom source
Rust 1.88 or newer.
git clone https://github.com/moonbase2090/Scorecard
cd Scorecard
cargo install --locked --path crates/sc-cli
cargo install --locked --path crates/sc-mcpRust coverage also needs:
rustup component add llvm-tools
cargo install cargo-llvm-covOn older toolchains the component is named llvm-tools-preview. If either tool is missing, sc still runs. Function coverage is treated as 0, a coverage.missing warning is recorded, and CRAP is still computed. The process exits 2 only when a required gate (types or tests) cannot run.
Full text: README, Install
Quickstart
Run it at the root of a project:
sc analyze .In a terminal, sc analyze prints a plain-text scorecard (--format pretty). A pipe or a file stays JSON unless you set --format. NO_COLOR turns color off, and CLICOLOR_FORCE=1 turns it on. This sample was captured from sc 0.1.15 for testdata/good_crate, with color off.
sc 0.1.15 testdata/good_crate rust 2284db3 clean scope tree
PASS
gates
[ok] types enforced
[ok] tests enforced
[ok] crap enforced
[ok] sca advisory
[ok] secrets enforced
[ok] lint enforced
scores
correctness 1.00 [##########]
efficiency 1.00 [##########]
maintainability 1.00 [##########]
security 1.00 [##########]
a11y 1.00 [##########]
worst crap threshold 30
CRAP CC COV SYMBOL LOCATION
1 1 100% add src/lib.rs
findings
(none)
engines run: compile, tests, coverage, complexity, crap, sca, secrets, perf, lint
engines skipped: spec, mutation, llm, test_value.weakening
duration: 0.6s
exit 0: enforced gates passed
Reading the output
- First line: the
scversion, the path, the pack, the git commit and whether the tree is clean, and the scope. - Verdict:
PASS,FAIL, orREPORT ONLY. A pass with a failing advisory gate adds a note, such as1 advisory gate failing.REPORT ONLYmeans no gate was enforced and at least one failed. - gates:
[ok]passed and[xx]failed. Each gate saysenforcedoradvisory, and a failed gate adds its reason, such astest failures. See Gates. - scores: five dimensions from 0 to 1. See CRAP and scores.
- worst crap: the highest-scoring functions and the threshold.
- findings: each one has a rule, such as
test.failed, a location and a suggested fix. - engines run / skipped, the duration, and the exit code with its meaning.
With --out, the report is also written to a file. --format all --out sc-report writes sc-report.json, .md, .sarif and .html. --format html is a self-contained visual report that makes no network requests; see HTML reports.
Full text: README sample · report guide · troubleshooting
Gates
A gate either passes or fails. --fail-on (or gates.fail_on in analyzer.toml) lists the gates that fail the process. The default is types,tests,crap,secrets,lint. A gate with enforced: false is reported and does not fail the process.
| Gate | Checks | Fails the run |
|---|---|---|
types | The project compiles or type-checks. Rust: cargo check | Yes (default) |
tests | The test suite passes. Rust: cargo test | Yes (default) |
crap | No function is above the CRAP threshold (default 30), and no untested function at or above gates.new_fn_untested_cc. See CRAP. | Yes (default) |
secrets | Scans project files for AWS provider secret keys in Terraform, GitHub tokens, Slack webhooks, Stripe restricted live keys, and private-key material | Yes (default) |
lint | The configured lint command exits cleanly. Rust: cargo clippy --workspace | Yes (default) |
sca | An import that is undeclared, hallucinated, or not classified (sca.undeclared_dependency, sca.hallucinated_import, sca.import_unresolved). Python checks against pyproject.toml. std, core, alloc, crate, self and super are allowed. | No, advisory |
html | Web pack: the markup parses, has a doctype and a viewport, and has no unclosed or misnested tags. [html] enforce is auto, on or off. | Yes (default, web pack) |
links | Web pack: internal href and src paths exist in the tree | No, advisory unless --fail-on names it or [links] enforce = true |
a11y | Static WCAG 2.2 checks on HTML (web pack) and JSX or TSX (node pack). No browser is opened. | No, advisory unless --fail-on names it or [a11y] enforce = true |
spec | With --spec FILE: paths named in the file exist, and fn, struct, enum, trait, type and const names in it are public items | Only when asked |
mutation | With --mutation diff or full: runs cargo-mutants. Survivors are mutation.survivor. | Only when the mode is not off |
Enforced vs advisory
An enforced gate changes the exit code when it fails. An advisory gate is reported on the scorecard and does not. sca is advisory: an undeclared dependency is a strongly advised warning (disposition ask) that stays on the scorecard and does not fail the process. The terminal layout labels it advisory.
Before v0.1.1, the JSON and HTML reports marked a passing sca gate as enforced, even though it never changes the exit code. From v0.1.1 they mark it advisory; the HTML report says reported only.
Warnings, such as the undeclared-dependency advisory and perf.nested_loop or perf.clone_in_loop, don't fail the process on their own.
Full text: config · packs · accessibility checks
Flags and exit codes
sc analyze [PATH] [--diff [BASE]] [--diff-head REV] [--paths FILE] [--spec PATH]
[--format json|pretty|md|sarif|html|all] [--out PATH] [--fail-on LIST]
[--pack PACK] [--mutation off|diff|full] [--llm off|on] [--intent TEXT]
[--budget-seconds N] [--config PATH]
| Flag | Default |
|---|---|
PATH | . |
--format | pretty on a terminal, otherwise json. Also md, sarif, html, all. |
--fail-on | types,tests,crap,secrets,lint |
--pack | Detect one pack. rust, node, python, bash, go, java, csharp, php, cpp, web or command |
--mutation | off |
--llm | off |
--intent | none |
--budget-seconds | 120 |
--config | Project-root analyzer.toml, then ~/.config/sc/analyzer.toml. Parent and nested directories are not searched. |
| Exit | Meaning |
|---|---|
0 | No gate selected by --fail-on failed |
1 | A gate selected by --fail-on failed |
2 | Analyzer error (missing path, missing required toolchain, timeout on compile or tests) |
--fail-on controls the process exit code. The report still shows FAIL when an enforced gate fails outside that list. An empty list reports REPORT ONLY when gates fail. Skipping coverage, mutation or review does not by itself exit 2.
Full text: CLI reference
Config
Scorecard needs no config. Put analyzer.toml at the root of the project you analyze, or use sc config init to create ~/.config/sc/analyzer.toml. Project config takes precedence. Scorecard does not search parent or nested directories. The user config is left alone unless you pass --force; sc config path prints its path. CLI flags override matching settings. This is the v0.2.1 example, with its comments trimmed:
# pack = "rust" # rust, node, python, bash, go, java, csharp, php, cpp, web, or command
[gates]
fail_on = ["types", "tests", "crap", "secrets", "lint"]
crap_threshold = 30
new_fn_untested_cc = 15
[scope]
exclude = ["target/**", "generated/**"]
[mutation]
mode = "off"
max_mutants = 50
budget_seconds = 180
[llm]
enabled = false
backend = "ollama"
endpoint = "http://127.0.0.1:11434/v1"
base_url = "https://openrouter.ai/api/v1"
api_key_env = "OPENROUTER_API_KEY"
max_tool_rounds = 36
[engines]
coverage = true
sca = true
[html]
enforce = "auto"
[links]
enforce = false
[a11y]
enforce = false
disable = []
[commands]
lint = "cargo clippy --workspace"
- Lint:
commands.lintdefaults tocargo clippy --workspaceat a workspace root. A warning does not fail the gate. An empty value skips lint. A non-zero exit islint.failed, and it fails the process only whenlintis in--fail-on. - Mutation:
--mutation diffrunscargo mutants --in-diffagainst the same base as--diff(orHEAD~1), andfullruns the whole crate. Timeouts are counted and are not kills. Ifcargo-mutantsis missing, or there are more mutants thanmutation.max_mutants(default 50), the engine is skipped withengine.unavailable. - Spec review is off by default.
--llm oncan review a spec, or run from--intentalone when you omit--spec. Choose Ollama, Cursor, or an OpenAI-compatible service inanalyzer.toml. Ollama stays local by default. Cursor and OpenAI-compatible services receive the review text and any file text the review reads. The OpenAI-compatible backend defaults to OpenRouter and reads its key fromOPENROUTER_API_KEY. A completed review appears in terminal, Markdown and HTML. A skipped review explains why and does not fail the run. See the spec review setup guide.
Full text: Configure Scorecard · config reference · analyzer.toml.example
Language packs
sc detects one language pack from the tree. Two markers and no override is an error: set pack in analyzer.toml, or pass --pack. command is only an override: it runs secrets plus a lint command you set yourself.
| Pack | Marker | Coverage report |
|---|---|---|
| Rust | Cargo.toml | cargo llvm-cov |
| Node | package.json | .sc/coverage/coverage-final.json from c8 or nyc |
| Python | a Python manifest | pytest with pytest-cov, when available |
| Bash | a top-level, scripts/ or bin/ shell file, and no other marker | .sc/coverage/kcov Cobertura |
| Go | go.mod | go test -coverprofile |
| Java | pom.xml or Gradle | target/site/jacoco/jacoco.xml |
| C# | a root .csproj or .sln | .sc/coverage/csharp.cobertura.xml |
| PHP | composer.json | .sc/coverage/clover.xml from PHPUnit with pcov |
| C++ | CMakeLists.txt, or a Makefile or configure script with C/C++ source | .sc/coverage/cpp.info from lcov after CTest |
| Web | index.html or another root .html file, and no manifest | none |
The command pack has no coverage runner. If a pack produces no coverage report, Scorecard leaves unmeasured functions unscored and reports coverage.missing. The CRAP gate is advisory unless a measured function fails.
- Rust:
cargo check,cargo test, complexity,cargo llvm-cov, CRAP, dependency checks and a full-tree secrets scan. Non-ignored files over 64 MiB producesecrets.partial. A Cargo workspace is scored from each member'ssrcdirectory, found withcargo metadata. - Python:
python3 -m compileall, pytest when a test suite is present, Ruff, secrets and CRAP. Coverage retries withcoverage.pywhen pytest-cov writes no report. - Node:
node --checkfor JavaScript, TypeScript checks for every.tsand.tsxfile whentscis available, andnpm testwhen a test script exists. Bash:bash -n, plusshellcheckorbatswhen installed. Go:go build,go test -coverprofileandgo vet. C/C++: each source file is checked with supported build flags; code errors fail the types gate when the compile setup can be read. Java, C#, PHP: their compilers whenjavac,dotnetorphpis onPATH. - Web: no external tools. It parses HTML with
html5ever, checks internal links, runs thea11ychecks, and scores CRAP on.jsfiles and inline scripts. A root HTML file does not override a manifest such aspackage.json; pass--pack webfor a static site that has one. - Tools image: if a host tool is missing and the
scorecard-toolsimage is present, the same command runs in that image. Build it locally from a Scorecard checkout; no registry is required. A missing compiler and a missing image are reported and don't fail the process.
docker build -t scorecard-tools:latest docker/scorecard-toolsFull text: docs/packs.md
GitHub Action
The action installs the release that matches its tag, checks the archive against SHA256SUMS, and runs sc. If it cannot find a matching release asset or the checksum fails, it builds from source. Public repositories upload SARIF for sarif and all; html and all also upload a report artifact.
- uses: moonbase2090/Scorecard/action@v0.2.1
with:
fail-on: types,tests,crap,secrets,lint
format: sarif
| Input | Default | Notes |
|---|---|---|
spec | "" | Path to a spec or task file |
fail-on | types,tests,crap,secrets,lint | Comma-separated gates |
mutation | off | off, diff or full |
format | sarif | json, md, sarif, html or all |
diff | "" | Git base ref. Empty skips --diff |
version | "" | Uses the v-tagged action ref or the latest release |
build-from-source | false | Build from this checkout instead of installing a release |
The report is written to sc-results.sarif by default, or sc-results.md, .json or .html for those formats.
Full text: action/action.yml · README, GitHub Action
MCP server
sc-mcp speaks MCP over stdio. It serves four tools: analyze_paths, analyze_diff, explain and list_findings. explain and list_findings read .sc/last-scorecard.json from the last analyze.
sc setupsc setup makes the server visible to agents on this computer. It writes the skill to ~/.grok/skills/scorecard, ~/.claude/skills/scorecard, ~/.cursor/skills/scorecard and ~/.agents/skills/scorecard. It registers sc-mcp in ~/.grok/config.toml, ~/.cursor/mcp.json and ~/.claude.json when sc-mcp is on PATH. Run it again after you install or move the binary, then reload MCP servers in the agent.
Full text: docs/mcp.md
CRAP and scores
CRAP uses cyclomatic complexity, not cognitive complexity. For each function:
CRAP(m) = CC(m)^2 * (1 - cov(m))^3 + CC(m)
cov is that function's line coverage, from 0 to 1. The default threshold is 30 (gates.crap_threshold). A score equal to the threshold passes; only a score above it fails the crap gate (crap.over_threshold). At CC 5 and 0% coverage, CRAP is exactly 30, so the function passes. At CC 12 and 0% coverage, CRAP is 156.
| CC | Coverage needed to stay at or under 30 |
|---|---|
| ≤5 | 0% |
| 10 | ~42% |
| 15 | ~57% |
| 20 | ~71% |
| 25 | ~80% |
| ≥31 | Refactor; tests cannot save it |
gates.new_fn_untested_cc defaults to 15. In tree and --paths mode, every function in scope at or above that complexity with 0% coverage produces complexity.untested and fails the crap gate. With --diff, CRAP scores only changed functions, and complexity.untested scores only functions that are new relative to the base.
Scores
Five dimension scores start at 1.0. An error finding subtracts 0.25 and a warning subtracts 0.05, floored at 0. A dependency warning (sca) subtracts 0.01. coverage.missing and coverage.unmatched are reported and do not change the score. Correctness takes compile, test, config, lint and HTML findings. Maintainability takes complexity and CRAP. Efficiency takes perf findings. Security takes secrets and sca findings. a11y takes accessibility findings.
Full text: docs/crap.md