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

Download the .dmg

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 SHA256SUMS

On Linux, check with sha256sum instead:

sha256sum -c --ignore-missing SHA256SUMS

From 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-mcp

Rust coverage also needs:

rustup component add llvm-tools cargo install cargo-llvm-cov

On 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 sc version, the path, the pack, the git commit and whether the tree is clean, and the scope.
  • Verdict: PASS or FAIL.
  • gates: [ok] passed and [xx] failed. Each gate says enforced or advisory, and a failed gate adds its reason, such as test 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.

GateChecksFails the run
typesThe project compiles or type-checks. Rust: cargo checkYes (default)
testsThe test suite passes. Rust: cargo testYes (default)
crapNo function is above the CRAP threshold (default 30), and no untested function at or above gates.new_fn_untested_cc. See CRAP.Yes (default)
secretsA small token set: AWS access keys, GitHub tokens, Slack tokens, Stripe live keys and private-key blocksYes (default)
lintThe lint command exits cleanly. Rust: cargo clippy -- -D warningsYes (default)
scaImports 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
htmlWeb 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)
linksWeb pack: internal href and src paths exist in the treeNo, advisory unless --fail-on names it or [links] enforce = true
a11yStatic 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
specWith --spec FILE: paths named in the file exist, and fn, struct, enum, trait, type and const names in it are public itemsOnly when asked
mutationWith --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]
FlagDefault
PATH.
--formatpretty on a terminal, otherwise json. Also md, sarif, html, all.
--fail-ontypes,tests,crap,secrets,lint
--packDetect one pack. rust, node, python, bash, go, java, csharp, php, cpp, web or command
--mutationoff
--llmoff
--intentnone
--budget-seconds120
--configanalyzer.toml in the tree, then ~/.config/sc/analyzer.toml
ExitMeaning
0Configured gates passed
1A configured gate failed
2Analyzer 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.lint defaults to cargo clippy -- -D warnings. An empty value skips lint. A non-zero exit is lint.failed, and it fails the process only when lint is in --fail-on.
  • Mutation: --mutation diff runs cargo mutants --in-diff against the same base as --diff (or HEAD~1), and full runs the whole crate. Timeouts are counted and are not kills. If cargo-mutants is missing, or there are more mutants than mutation.max_mutants (default 50), the engine is skipped with engine.unavailable.
  • LLM review (off by default): --llm on sends the spec to an OpenAI-compatible /chat/completions endpoint. The built-in endpoint is http://127.0.0.1:11434/v1. If that endpoint is unchanged and XAI_API_KEY is set, the call goes to https://api.x.ai/v1 with model grok-4.5. The model may add spec.llm_gap warnings and doesn't invent CRAP or mutation scores. A failed call skips the engine and doesn't fail the run. --intent TEXT is 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.

PackMarkerCoverage report
RustCargo.tomlcargo llvm-cov
Nodepackage.json.sc/coverage/coverage-final.json from c8
Pythona Python manifestpytest with pytest-cov, when available
Basha top-level, scripts/ or bin/ shell file, and no other marker.sc/coverage/kcov Cobertura
Gogo.modgo test -coverprofile
Javapom.xml or Gradletarget/site/jacoco/jacoco.xml
C#a root .csproj or .sln.sc/coverage/csharp.cobertura.xml
PHPcomposer.json.sc/coverage/clover.xml from PHPUnit with pcov
C++CMakeLists.txt.sc/coverage/cpp.info from lcov after CTest
Webindex.html or another root .html file, and no manifestnone

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's src directory, found with cargo metadata.
  • Python: python3 -m compileall, pytest when a test suite is present, Ruff, secrets and CRAP.
  • Node: node --check, and npm test when a test script exists. Bash: bash -n, plus shellcheck or bats when installed. Go: go build, go test -coverprofile and go vet. C++: g++ -fsyntax-only. Java, C#, PHP: their compilers when javac, dotnet or php is on PATH.
  • Web: no external tools. It parses HTML with html5ever, checks internal links, runs the a11y checks, and scores CRAP on .js files and inline scripts. A root HTML file does not override a manifest such as package.json; pass --pack web for a static site that has one.
  • Tools image: if a host tool is missing and the scorecard-tools image 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-tools

Full 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
InputDefaultNotes
spec""Path to a spec or task file
fail-ontypes,tests,crap,secrets,lintComma-separated gates
mutationoffoff, diff or full
formatsarifjson, 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 setup

sc 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.

CCCoverage needed to stay at or under 30
≤50%
10~42%
15~57%
20~71%
25~80%
≥31Refactor; 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