Docs · v0.1.3
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.1.3 README and docs. Each section links to the full text on GitHub.
Install
Release v0.1.3 ships a signed, notarized macOS disk image and .tar.gz archives for macOS and Linux. Each archive holds sc, sc-mcp, LICENSE and README.md at the top level. sc-mcp is only needed for agents.
macOS disk image
sc-v0.1.3-universal-apple-darwin.dmg
Apple silicon and Intel in one image, signed with Developer ID and notarized. It holds the sc and sc-mcp command-line tools: copy them to a folder on your PATH, such as /usr/local/bin. 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.1.3/sc-v0.1.3-$(uname -m | sed s/arm64/aarch64/)-apple-darwin.tar.gz
tar -xzf sc-v0.1.3-*-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.1.3/sc-v0.1.3-$(uname -m)-unknown-linux-gnu.tar.gz
tar -xzf sc-v0.1.3-$(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.1.3/SHA256SUMS
shasum -a 256 -c --ignore-missing SHA256SUMSOn Linux, check with sha256sum instead:
sha256sum -c --ignore-missing SHA256SUMSFrom source
Rust 1.85 or newer.
git clone https://github.com/moonbase2090/Scorecard
cd Scorecard
cargo install --path crates/sc-cli
cargo install --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 .On a terminal, sc analyze prints the scorecard as plain text (--format pretty). A pipe or a file stays JSON unless --format is set. NO_COLOR turns color off and CLICOLOR_FORCE=1 turns it on. This is real sc 0.1.3 output for testdata/good_crate with --format pretty, color off.
sc 0.1.3 testdata/good_crate rust 70c3de0 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
duration: 1.2s
exit 0: 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:
PASSorFAIL. - 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 · examples/
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 | A small token set: AWS access keys, GitHub tokens, Slack tokens, Stripe live keys and private-key blocks | Yes (default) |
lint | The lint command exits cleanly. Rust: cargo clippy -- -D warnings | Yes (default) |
sca | Imports that aren't declared in the manifest (sca.hallucinated_import). 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: docs/config.md · docs/packs.md
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 | analyzer.toml in the tree, then ~/.config/sc/analyzer.toml |
| Exit | Meaning |
|---|---|
0 | Configured gates passed |
1 | A configured gate failed |
2 | Analyzer error (missing path, missing required toolchain, timeout on compile or tests) |
Skipping coverage, mutation or the LLM does not by itself exit 2.
Full text: docs/packs.md, Flags
Config
Copy analyzer.toml.example to analyzer.toml in the project you analyze, or to ~/.config/sc/analyzer.toml. --fail-on overrides gates.fail_on, and CLI flags override the matching settings. This is the v0.1.3 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
endpoint = "http://127.0.0.1:11434/v1"
model = "qwen2.5-coder"
[engines]
coverage = true
sca = true
[html]
enforce = "auto"
[links]
enforce = false
[a11y]
enforce = false
disable = []
[commands]
lint = "cargo clippy -- -D warnings"
- Lint:
commands.lintdefaults tocargo clippy -- -D warnings. 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. - LLM review (off by default):
--llm onsends the spec to an OpenAI-compatible/chat/completionsendpoint. The built-in endpoint ishttp://127.0.0.1:11434/v1. If that endpoint is unchanged andXAI_API_KEYis set, the call goes tohttps://api.x.ai/v1with modelgrok-4.5. The model may addspec.llm_gapwarnings and doesn't invent CRAP or mutation scores. A failed call skips the engine and doesn't fail the run.--intent TEXTis stored on the scorecard and sent with--llm on.
Full text: docs/config.md · 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 |
| 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 | .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. A missing report scores uncovered functions as coverage 0.
- Rust:
cargo check,cargo test, complexity,cargo llvm-cov, CRAP, hallucinated imports and a small secrets scan. 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. - Node:
node --check, andnpm testwhen a test script exists. Bash:bash -n, plusshellcheckorbatswhen installed. Go:go build,go test -coverprofileandgo vet. C++:g++ -fsyntax-only. 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
A composite action (plain bash steps) that installs sc from source with cargo install on the runner, runs it, and uploads SARIF when the format is sarif or all, so findings show up under code scanning.
- uses: moonbase2090/Scorecard/action@v0.1.3
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 |
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. Each error finding subtracts 0.25 and each warning subtracts 0.05, floored at 0. Correctness takes compile, test, config, lint and HTML findings. Maintainability takes complexity, coverage and CRAP. Efficiency takes perf findings. Security takes secrets and sca findings. a11y takes accessibility findings.
Full text: docs/crap.md