linecheck
Stop your AI agent from turning one file into a monolith. linecheck enforces per-file line limits so bloated files get caught before they pile up.
Features
- Set per-file or per-glob line limits
- Configurable warn / error thresholds
- Inline ignore comments and config-level excludes
- Works as a CLI, in CI pipelines, and as a library
- Rust core (npm, pip, Go, and WASM bindings planned)
Installation
Rust / Cargo
npm, pip, and Go bindings are coming soon.
Usage
Check all files in the current directory using your config:
Override the line limit inline:
Example output:
src/main.rs: 450 lines (error threshold: 400)
src/utils.rs: 220 lines (warn threshold: 200)
When warn_message / error_message are set in the matching rule, the message is appended:
src/main.rs: 450 lines (error threshold: 400) — Too large to review easily; split this file now
src/utils.rs: 220 lines (warn threshold: 200) — Getting long — consider splitting into submodules
See which files are creeping toward their limit before they breach it:
src/main.rs 450 / 400 [ERROR]
src/utils.rs 220 / 200 [WARN]
src/lib.rs 180 / 200 90%
src/config.rs 45 / 200 22%
For scripting and CI dashboards, use --json. Without --status it outputs only violations:
Add --status to include all files regardless of their status:
Each object contains: file (path), lines (count), limit (threshold used), percent (lines × 100 / limit), status ("ok", "warn", or "error").
Presets
Use a preset flag to apply a built-in strictness level without writing a config file:
| Flag | Warn | Error |
|---|---|---|
--strict |
100 | 100 |
--default |
200 | 400 |
--loose |
400 | 400 |
--free |
— | — |
Files are flagged when their line count exceeds the threshold — a file with exactly N lines is fine; N+1 triggers the flag.
Preset flags are overridden by any linecheck.yml in scope.
Schema
A JSON Schema for linecheck.yml is published alongside the codebase at schema/linecheck.schema.json.
VS Code / any YAML Language Server editor — add a modeline at the top of your linecheck.yml for inline validation and autocompletion with no plugin configuration required:
# yaml-language-server: $schema=https://raw.githubusercontent.com/tupe12334/linecheck/main/schema/linecheck.schema.json
Alternatively, configure it project-wide via .vscode/settings.json:
Configuration
linecheck resolves configuration like .gitignore — a linecheck.yml applies to its directory and all subdirectories recursively. A nested config overrides the parent for everything inside it. If no config is found anywhere, it falls back to built-in defaults: warn when a file exceeds 200 lines, error when it exceeds 400 lines.
project/
├── linecheck.yml ← applies to everything
└── src/
├── linecheck.yml ← overrides for src/ and below
└── generated/
└── linecheck.yml ← can relax limits for generated code
Not sure where to start? 200 lines is a reasonable warn threshold for most source files — it's enough for a focused module but flags anything that's grown too broad.
Create a linecheck.yml at the root of your project to override the defaults:
# yaml-language-server: $schema=https://raw.githubusercontent.com/tupe12334/linecheck/main/schema/linecheck.schema.json
rules:
- pattern: "**/*.rs"
warn: 200
warn_message: "Getting long — consider splitting into submodules"
error: 400
error_message: "Too large to review easily; split this file now"
- pattern: "**/*.ts"
warn: 150
warn_message: "Consider breaking this into smaller components"
error: 300
error_message: "File exceeds the hard limit — split before merging"
exclude:
- "**/generated/**"
- "**/vendor/**"
Rules are evaluated in order — the first matching rule wins. Put more specific patterns before broader ones.
The optional warn_message and error_message fields set hints printed alongside violations at each severity level. Both are independent — you can set one, the other, or both. Use them to explain the intent of the limit or point to a team convention.
CLI flags override config file values. Run linecheck --help for all options.
Ignoring files
Exclude globs — add an exclude list to linecheck.yml (see above).
Inline ignore — add this comment anywhere in the file to exempt it entirely:
# linecheck:ignore
The file will be skipped regardless of its line count. There is no partial ignore — it's all-or-nothing.
Note: detection is a raw byte scan, so any file that contains the literal string
linecheck:ignoreanywhere (including in string literals or documentation) will be treated as ignored. If your source code references the marker as a string constant, write the colon as\x3ain the Rust/C literal so the raw sequence does not appear in the file.
Exit codes
| Code | Meaning |
|---|---|
0 |
All files within limits (warnings are printed but non-blocking) |
1 |
One or more files exceed the error threshold |
Library usage
Add linecheck to your Cargo.toml and call check_file directly:
[]
= "0.3"
use ;
use Path;
let result = check_file.unwrap;
match result.status
For walking a whole directory tree with config resolution, combine collect_files and ConfigResolver:
use ;
use PathBuf;
let files = collect_files;
let mut resolver = new;
let opts = default;
for path in &files
Full API docs at docs.rs/linecheck.
CI examples
See the examples/ folder for ready-to-use setups:
examples/ci/linecheck.sh— generic CI shell setup (any CI provider)examples/github/workflow.yml— GitHub Actions workflow (copy to.github/workflows/linecheck.yml)