Back to directory
doraemonkeys avatar
doraemonkeys / sloc-guard

sloc-guard

๐Ÿ›ก๏ธ High-performance Rust CLI that enforces SLOC limits and directory structure rules to prevent code bloat โ€” unlike counters, sloc-guard enforces them

21

Stars

2

Forks

1

Watchers

Apache-2.0

License

sloc-guard

Guard your codebase against complexity.

sloc-guard is a high-performance command-line tool that enforces limits on Source Lines of Code (SLOC) and Directory Structure. Unlike passive counters that just tell you how big your project is, sloc-guard actively prevents code bloat and architectural decay by failing your build when thresholds are exceeded.

Crates.io Downloads License CI Test Coverage Rust PRs Welcome


โ“ Why sloc-guard?

Large files and messy directory structures are silent killers of codebase maintainability. By the time you notice, the damage is done.

sloc-guard enforces limits before code is merged:

  • ๐ŸŽฏ SLOC Limits โ€” Prevent files from exceeding line count thresholds (comments and blanks excluded by default)
  • ๐Ÿ“ Structure Guards โ€” Enforce directory organization (max files/dirs, naming conventions, sibling rules)
  • ๐Ÿ”„ Git-Aware โ€” Check only changed files (--diff, --staged) for fast CI integration
  • ๐Ÿ“Š Trend Tracking โ€” Monitor codebase growth over time with historical snapshots

How is it different from other tools?

Feature sloc-guard cloc tokei SCC
Enforce limits โœ… โ€” โ€” โ€”
Directory structure rules โœ… โ€” โ€” โ€”
Path-based rule overrides โœ… โ€” โ€” โ€”
Git diff mode โœ… โ€” โ€” โ€”
Baseline grandfathering โœ… โ€” โ€” โ€”
Trend tracking โœ… โ€” โ€” โ€”
SARIF output โœ… โ€” โ€” โ€”
Remote config inheritance โœ… โ€” โ€” โ€”

Other tools count lines. sloc-guard enforces them.

๐Ÿค– Perfect for AI-Assisted Development

In the age of AI coding assistants, telling AI "don't write spaghetti code" is futile โ€” it has no memory of your preferences. But hard constraints work: when sloc-guard fails the build, AI automatically responds by refactoring and splitting code.

Instead of endlessly reminding AI to keep files small, just let it hit the wall and fix itself.


Quick Start

Installation

From crates.io:

cargo install sloc-guard

From source

cargo install --git https://github.com/doraemonkeys/sloc-guard

Or download pre-built binary from GitHub Releases and add it to your PATH.

30-Second Setup

# 1. Initialize config with project type detection
sloc-guard init --detect

# 2. Check your codebase
sloc-guard check

# 3. See project statistics
sloc-guard stats summary

That's it! sloc-guard will enforce a 600-line limit per file by default.

  • HTML report
# (Optional) Generate a visual HTML report
sloc-guard check -f html -o output.html
# OR
sloc-guard stats report -f html -o report.html

Configuration

Create .sloc-guard.toml in your project root:

version = "2"

# Optional: inherit from presets or remote configs
# extends = "preset:rust-strict"

[scanner]
gitignore = true                             # Respect .gitignore (default: true)
exclude = [".git/**", "vendor/**", "dist/**"] # Exclude from scanning entirely

[content]
extensions = ["rs", "go", "py", "js", "ts"]  # Files to check
max_lines = 500                              # Max lines per file
warn_threshold = 0.8                         # Warn at 80% (400 lines)
warn_at = 450                                # Absolute threshold (takes precedence over warn_threshold)
skip_comments = true                         # Don't count comments (default: true)
skip_blank = true                            # Don't count blank lines (default: true)
exclude = ["**/*_test.go"]                   # Skip SLOC check (still visible to structure rules)

[structure]
max_files = 30                               # Max files per directory
max_dirs = 10                                # Max subdirectories
max_depth = 8                                # Max nesting depth
warn_threshold = 0.8                         # Warn at 80% of limits
warn_files_at = 25                           # Absolute threshold (takes precedence)
warn_dirs_at = 8                             # Absolute threshold (takes precedence)
count_exclude = ["*.md", ".gitkeep"]         # Don't count these toward limits (path-qualified
                                             # globs like "web/**/*_test.go" also work)
deny_extensions = [".exe", ".dll", ".bak"]   # Forbidden file types
deny_files = [".DS_Store", "Thumbs.db"]      # Forbidden files

[sarif]
min_level = "error"                          # error|warning|note - severity floor for SARIF/Code Scanning.
                                             # Default "error" keeps approaching-limit warnings out of the
                                             # GitHub Security tab (report-only; does not affect exit codes).

[baseline]
ratchet = "warn"                             # warn|auto|strict - violations can only decrease

[trend]
max_entries = 100                            # Keep last N snapshots
max_age_days = 90                            # Delete older entries
min_interval_secs = 3600                     # At most one entry per hour
min_code_delta = 10                          # Ignore changes < N lines
auto_snapshot_on_check = false               # Auto-record on successful check

[check]
warnings_as_errors = false                   # Treat warnings as errors
fail_fast = false                            # Stop on first failure

Features

Content Rules (SLOC Limits)

Override line limits for specific paths (last match wins):

[[content.rules]]
pattern = "src/generated/**"
max_lines = 2000
reason = "Auto-generated code"

[[content.rules]]
pattern = "**/*_test.rs"
max_lines = 800
skip_comments = false                        # Override: count comments for tests
reason = "Test files need more space"

# Temporary exemption with expiration
[[content.rules]]
pattern = "src/legacy/parser.rs"
max_lines = 1500
reason = "Refactoring in progress - JIRA-1234"
expires = "2025-06-01"

Structure Rules (Directory Organization)

Override structure limits and enforce naming conventions:

[[structure.rules]]
scope = "src/components/**"
max_files = 50
count_exclude = ["*.css"]                    # Styles don't count toward this rule's limits
file_naming_pattern = "^[A-Z][a-zA-Z0-9]*\\.(tsx|css)$"
allow_extensions = [".tsx", ".css"]          # Only these extensions allowed
reason = "React components: PascalCase required"

[[structure.rules]]
scope = "src/features/**"
max_files = -1                               # -1 = unlimited
max_depth = 3
relative_depth = true                        # Depth relative to scope, not project root
siblings = [
    { match = "*.tsx", require = "{stem}.test.tsx" }
]
reason = "Feature modules: max 3 levels deep, every component needs a test"

[[structure.rules]]
scope = "tests/"                             # Trailing / = tests itself plus its whole subtree
max_files = -1
max_dirs = -1
reason = "No limits for test directories"

scope selects directories: dir (exact match), dir/* (direct children), dir/** (descendants only), dir/ (the directory plus its whole subtree).

Rules follow last match wins. Rule-level count_exclude:

  • The winning rule defines the counting caliber together with the limits โ€” even when its limit fields fall back to global values. Superseded rules contribute nothing.
  • Unioned with the global structure.count_exclude, with the same semantics: config-root-relative globs, bare names match by basename, applies to both file and dir counts.
  • Excluded entries are only exempt from counting โ€” allowlist/deny/naming checks still apply.
  • No rule needed for simple cases: global count_exclude accepts path-qualified globs like web/**/*_test.go.

Run sloc-guard explain <dir> to see the winning rule, raw vs effective counts, and which children each pattern excludes. Counts come from a scan under the configured excludes and gitignore โ€” the same roster check counts โ€” though check-time CLI flags such as --exclude are not visible to explain.

Git Integration

Check only what changed for fast CI:

# Check files changed since main branch
sloc-guard check --diff main

# Check only staged files (pre-commit hooks)
sloc-guard check --staged

# Check specific commit range
sloc-guard check --diff v1.0..v2.0

Note: --diff compares committed trees only (e.g., main..HEAD). Unstaged working directory changes are not checked. To catch uncommitted violations, stage your changes and use --staged.

Baseline & Grandfathering

Adopt sloc-guard in existing projects without fixing everything at once:

# Create baseline from current violations
sloc-guard check --update-baseline

# Violations in baseline are "grandfathered" (pass with note)
sloc-guard check --baseline

# Ratchet mode: violations can only decrease over time
sloc-guard check --baseline --ratchet strict

Stats Subcommands

Analyze your codebase with focused subcommands:

# Project-level summary
sloc-guard stats summary

# Top files by code lines
sloc-guard stats files --top 10 --sort code

# Language or directory breakdown
sloc-guard stats breakdown                   # By language (default)
sloc-guard stats breakdown --by dir --depth 2

# Trend comparison with history
sloc-guard stats trend                       # vs. last entry
sloc-guard stats trend --since 7d            # vs. 7 days ago

# View historical snapshots
sloc-guard stats history --limit 20

# Comprehensive report (combines all above)
sloc-guard stats report --format html -o report.html

Record a snapshot manually:

sloc-guard snapshot                          # Record current state to history

Output example (stats trend --since 7d):

Trend (vs 7 days ago):
  Code:     +127 lines (+0.4%)  โ†‘
  Comments:  -12 lines (-0.3%)  โ†“
  Files:      +3               โ†‘

  Previous: 2024-12-22 @ abc123f (main)
  Current:  2024-12-29 @ def456a (main)

Split Suggestions

When a file exceeds limits, get actionable suggestions:

sloc-guard check --suggest

Output:

โœ— src/parser.rs: 723 lines (limit: 500)
  
  Split suggestion:
  โ”œโ”€โ”€ parse_expression() (lines 45-180, 135 lines)
  โ”œโ”€โ”€ parse_statement() (lines 182-340, 158 lines)
  โ””โ”€โ”€ parse_block() (lines 342-520, 178 lines)

Multiple Output Formats

sloc-guard check --format text      # Human-readable (default)
sloc-guard check --format json      # Machine-readable
sloc-guard check --format sarif     # IDE integration (VS Code, GitHub)
sloc-guard check --format markdown  # Documentation
sloc-guard check --format html      # Rich reports with charts

Explain Command

Debug which rules apply to a path:

sloc-guard explain src/components/Button.tsx

Output:

Path: src/components/Button.tsx
Matched Rule: [[content.rules]] #2
  Pattern: src/components/**
  Reason: "React components"
Effective Limit: 400 lines
Warn At: 320 lines (80%)

Config Inheritance

Share configuration across projects:

# Built-in presets: rust-strict, node-strict, python-strict, monorepo-base
extends = "preset:rust-strict"

# Or remote URL with optional integrity check
extends = "https://example.com/team-config.toml"
extends_sha256 = "abc123..."

# Local values override inherited ones
[content]
max_lines = 600

# Arrays are merged (parent + child). Use "$reset" to start fresh:
# exclude = ["$reset", "only-this/**"]

Supported Languages

sloc-guard ships with built-in comment-aware parsing for the following languages:

Language Extensions
Rust rs
Go go
Python py, pyi
JavaScript js, mjs, cjs
TypeScript ts, mts, cts, tsx
JSX jsx
Vue vue
C c, h
C++ cpp, hpp, cc, cxx, hxx
C# cs
Java java
Kotlin kt, kts
Swift swift
Dart dart
PHP php
Ruby rb, rake
Scala scala, sc
Lua lua
SQL sql
Shell sh, bash, zsh
Move move

Nested block comments are correctly handled for Rust and Swift. Need a language not listed? Define it below.

Custom Languages

Define comment syntax for unsupported languages:

[languages.hcl]
extensions = ["tf", "hcl"]
single_line_comments = ["#", "//"]
multi_line_comments = [["/*", "*/"]]

CLI Reference

Usage: sloc-guard [OPTIONS] <COMMAND>

Commands:
  check     Check files against line count thresholds
  stats     Display statistics without checking thresholds
  snapshot  Record a statistics snapshot to trend history
  init      Generate a default configuration file
  config    Configuration file utilities
  explain   Explain which rules apply to a path
  help      Print this message or the help of the given subcommand(s)

Options:
  -v, --verbose...
          Increase output verbosity (-v, -vv for more)
  -q, --quiet
          Suppress non-essential output
      --color <COLOR>
          Control color output [default: auto] [possible values: auto, always, never]
      --no-config
          Skip loading configuration file
      --no-extends
          Skip resolving extends in configuration (ignore remote/local inheritance)
      --extends-policy <EXTENDS_POLICY>
          Remote config fetch policy for `extends` URLs. - normal: use cache if within 1h TTL, otherwise fetch (default) - offline: use cached only, error on cache miss - refresh: skip cache, always fetch fresh [default: normal] [possible values: normal, offline, refresh]
  -h, --help
          Print help (see more with '--help')
  -V, --version
          Print version

Stats Subcommands

Subcommand Description Key Flags
summary Project totals (files, code, comments, blanks) --format
files File list with sorting --top, --sort, --format
breakdown Group by language or directory --by, --depth, --format
trend Delta comparison with history --since, --format
history List historical snapshots --limit, --format
report Comprehensive report --format, -o, --exclude-section

Pre-commit Hook

Add to .pre-commit-config.yaml:

repos:
  - repo: https://github.com/doraemonkeys/sloc-guard
    rev: master
    hooks:
      - id: sloc-guard

The hook uses --staged mode for fast incremental checks.


Advanced Usage

CI Integration

See GitHub Action README for copy-paste GitHub Actions workflows plus GitLab CI, Jenkins, Azure Pipelines, and CircleCI examples.

Docker

docker run --rm -v $(pwd):/workspace -w /workspace ghcr.io/doraemonkeys/sloc-guard check

Monorepo & More Examples

See Recipes & Examples for configuration patterns including:

  • Monorepo setup
  • React/Next.js projects
  • Rust/Go/Python projects
  • Temporary exemptions
  • Remote config inheritance

Performance

sloc-guard is designed for speed:

  • Parallel processing via Rayon โ€” utilizes all CPU cores
  • Intelligent caching โ€” skips unchanged files (mtime + size + hash)
  • Git-aware scanning โ€” respects .gitignore by default
  • Incremental mode โ€” --diff and --staged check only changed files

๐Ÿ›ก๏ธ Project Quality

  • 90%+ test coverage enforced by CI
  • Strict Clippy lints (pedantic + nursery)
  • Comprehensive integration tests
  • Dependency injection for testability
  • Well-documented internal architecture

See ENGINEERING_GUIDELINES.md for coding standards.

Exit Codes

Code Meaning
0 All checks passed
1 Threshold exceeded (or warnings in --strict mode)
2 Configuration error

License

Apache-2.0 โ€” see LICENSE for details.

Releases

Jul 27, 2026

Download .zip

Highlights

Strict configuration schemas now reject unknown fields and report the originating file and location, preventing silent configuration mistakes. Structure rules support rule-level count_excl...

Jul 10, 2026

Download .zip

Highlights

Discover the nearest .sloc-guard.toml from the invocation directory up to the Git repository boundary. Keep configuration-file patterns stable and relative to the configuration root across...

Jun 25, 2026

Download .zip

What's Changed Commits

style: adopt sort_by_key/map_or to satisfy clippy in stats tests (13386b1) test: pin initial branch to master in git diff test repo (0eeb102) style: apply rustfmt to SARIF seve...

Feb 26, 2026

Download .zip

What's Changed Commits

chore: bump version to 0.3.3 (b0fb84e) feat: add Svelte language support, improve presets, and add Supported Languages section to README (7f854df) feat: add Move language suppo...

Jan 10, 2026

Download .zip

What's Changed Commits

chore: bump version to 0.3.2 (b4ca2a0) Add support for Go strict preset: Implement rules for test files, structure, and exclusions. Update existing presets to include Go langua...