Aggregate static scan reports. No telemetry. No external analyzers. No per-file leakage.
code-signal is a standalone Go CLI that scans a repository and reports aggregate code-quality signals: score, issue totals, issue categories, rule counts, detected languages/modules, and duplicate density. It is designed for local developer machines, CI jobs, and air-gapped environments.
The scanner deliberately does not invoke PMD, ESLint, Ruff, ShellCheck, Hadolint, SonarQube, or any other project-provided analyzer. Every rule is built into the binary and deterministic.
go install github.com/randomcodespace/code-signal/cmd/scanner@latestOr build from source:
git clone https://github.com/RandomCodeSpace/code-signal.git
cd code-signal
go build -trimpath -o scanner ./cmd/scanner# Scan the current repository
scanner scan .
# Emit aggregate JSON
scanner scan . --json
# Exclude well-known test files and test directories
scanner scan . --exclude-tests
# Detect languages and module roots
scanner detect .
# Compare complete local git snapshots
scanner diff --base main --head HEAD .
# Check offline readiness
scanner doctorCompleted scan, diff, and detect commands exit 0 after producing a report, even when the quality score is poor or a regression is detected. Non-zero exits are reserved for CLI usage errors, invalid configuration, local git/runtime errors, context cancellation, and output write failures.
Current ruleset: 0.5.0.
| Rule | Category | Severity | Signal |
|---|---|---|---|
generic.long-line |
style | warning | Lines over the configured maximum, default 120. |
generic.trailing-whitespace |
style | warning | Trailing spaces or tabs. |
generic.todo |
maintainability | info | TODO, FIXME, and HACK markers in comments. |
generic.duplicate-block |
maintainability | warning | Duplicate normalized 10-line logical windows. |
generic.deep-nesting |
complexity | warning | Python indentation nesting and brace-control nesting for C-like languages. |
generic.risky-shell |
security | error | Risky shell patterns such as `curl |
generic.merge-conflict |
bug | error | Unresolved git conflict markers. |
generic.parse-json |
bug | error | Invalid JSON. |
generic.parse-go |
bug | error | Invalid Go syntax. |
generic.go-complexity |
complexity | warning | Go cyclomatic complexity over 15. |
generic.generated-skip |
maintainability | info | Generated, minified, vendor, and build-output skip policy metadata. |
These are real checks, not placeholders. They are not intended to be SonarQube-compatible counts; they are code-signal's own deterministic quality signal.
code-signal detects and analyzes these languages with built-in lexical/parser checks:
go, javascript, typescript, python, ruby, rust, java, csharp, php, shell, dockerfile, json, toml, yaml.
Detection uses extensions, shebangs, and common manifests such as go.mod, package.json, pyproject.toml, Cargo.toml, pom.xml, Gradle files, .csproj, .sln, composer.json, Gemfile, Dockerfile, Containerfile, and *.dockerfile.
Scan JSON includes lines_scanned, blank_lines, code_lines, comment_lines, comment_only_lines, inline_comment_lines, and comment_density_percent. The same aggregate fields are reported for totals, by_language, and by_module; diff JSON includes before/after/delta values under totals_delta.
lines_scanned is physical scanned lines. code_lines excludes blank lines and comment-only lines, but keeps lines that contain code plus an inline comment. The score model uses code_lines when available and falls back to physical lines for older reports.
Comment detection is lexical and language-aware for supported languages: it recognizes //, #, /* ... */, Rust nested block comments, Ruby =begin/=end, and standalone Python triple-quoted doc/comment blocks where those forms are valid. It ignores common markers inside quoted strings/raw strings/template literals and JavaScript/TypeScript regex literals, and never emits per-file locations or source snippets.
Working-tree scans parse .gitignore, .ignore, and .git/info/exclude using gitignore-style rules before reading candidate files.
Pass --exclude-tests to scan or diff to skip well-known test-case paths from aggregate analysis. The built-in defaults cover common Go (*_test.go, testdata), Java (src/test/**, *Test.java, *Tests.java, *IT.java), Python (tests/**, test_*.py, *_test.py, conftest.py), TypeScript/JavaScript (__tests__/**, *.test.*, *.spec.*, cypress/**, playwright/**, e2e/**), and Rust (tests/**, benches/**, *_test.rs) conventions.
Built-in skips still apply for common dependency, generated, build, coverage, and minified paths such as node_modules, vendor, target, dist, build, .next, coverage, third_party, generated, gen, *.min.js, *.min.css, *.pb.go, and *_generated.go.
Configuration is optional. If present, scanner.json is loaded from the scanned repository root or from --config.
{
"scan": {
"default_timeout_seconds": 0,
"max_file_analysis_ms": 2000,
"max_file_bytes": 1048576,
"follow_symlinks": false,
"workers": 0,
"exclude_tests": false
},
"score": {
"fail_under": 75,
"error": 10,
"warning": 4,
"info": 1
},
"diff": {
"fail_on_score_drop": true,
"max_allowed_new_errors": 0,
"category_regression_threshold": 1
}
}Unknown config fields and trailing JSON values are rejected.
scan.default_timeout_seconds is disabled by default; use --timeout or set a
positive value when a whole-command emergency brake is needed. Files larger than
scan.max_file_bytes are skipped before content is read. Files whose built-in
analysis exceeds scan.max_file_analysis_ms are skipped after the bounded
attempt. These are included in totals.files_skipped_due_to_size or
totals.files_skipped_due_to_timeout. When this happens, scan and diff reports
set incomplete: true, so the score is clearly a quick optimistic signal over
the scanned subset.
The score is a bounded weighted issue-density signal, not a SonarQube debt rating:
weighted_density_per_kloc = round((errors*10 + warnings*4 + info*1) * 1000 / max(code_lines, 1000))
score = round(100 * 100 / (100 + weighted_density_per_kloc))
Error caps still apply after density scoring: any error caps the score at 89, and five or more errors cap it at 69. Bands are excellent for 90+, good for 75-89, needs work for 50-74, and poor below 50.
Reports are aggregate-only. Facts and report JSON do not include file paths, line/column coordinates, snippets, clone groups, per-file findings, or source text. The scanner reads local files and local git objects only; it performs no telemetry, update checks, remote rule downloads, package installs, or network calls.
go test ./...
go vet ./...
go run ./cmd/scanner scan .Main is protected. Feature work should use a branch and pull request. Required checks mirror the CI/security pattern used by RandomCodeSpace/codeiq: Go vet/test/static analysis, OSS security scanners, duplication gate, SBOM generation, perf/self-scan gate, and OpenSSF Scorecard.
MIT. See LICENSE.