Concepts
The Concepts section is the conceptual foundation that the rest of the docs assume. Skim it once; come back when something downstream confuses you.
Everything here is one idea seen from six angles. You declare rules (fact-gated, and composed from other configs); alint targets each rule at a set of files, evaluates them (per file and across files), and emits a report whose exit code gates CI; then fix, baseline, and an agent surface carry it into a real repo. This map is the whole section in one picture, and every box below is a page in the sidebar:
What alint is
Section titled “What alint is”alint is a static Rust binary that lints the shape of a repository. Where ESLint lints code and Semgrep lints semantics, alint lints the things in between: required files (READMEs, LICENSEs, SECURITY.md), filename conventions, content patterns, the values inside package.json / Cargo.toml / GitHub workflows, and cross-file relationships like “every package has a README” or “every header has a matching source file.”
How this section is organized
Section titled “How this section is organized”The section is six groups, each a stage of the mental model above. Read it start to finish for the whole picture, or jump to the group that owns your question:
- Start here is the model itself: how a run works, the config model, the kinds, families, and categories a rule draws on, and how severity maps to exit codes.
- How rules target files covers what a rule sees: the walker and git, scoping with
paths:,when:, andscope_filter:, and changed mode for diffs. - Composition and trust is how configs combine: extends and the trust boundary, the bundled rulesets you inherit, and config layering with drop-ins and nested configs.
- Beyond single files is the relational half: cross-file rules and structured-config queries into JSON, YAML, TOML, and five more formats.
- Adoption and fixing lands alint on a real repo: auto-fix and baselines that grandfather existing debt.
- Working with agents is the agent surface: the same rules become an agent’s standing instructions and its fix loop.
The rest of this page is a quick tour of the load-bearing ideas; each links into the group that covers it in depth.
The rule model
Section titled “The rule model”Every rule has:
id: a stable, kebab-case identifier. Required. Used to override or disable the rule from a child config.kind: which built-in rule implementation to invoke (e.g.file_exists,json_path_equals,for_each_dir). Required.level:error,warning,info, oroff. Required.paths: a glob, list of globs, or{include, exclude}pair selecting which files the rule applies to. Required for most kinds.when: an expression gating the rule on facts or vars. Optional.fix: a fix-op declaration that turns this rule into an auto-fixable one. Optional.message/policy_url: display fields shown when the rule fires. Optional.
Plus kind-specific options. For example, file_min_lines takes min_lines: <int>; json_path_matches takes path (a JSONPath) and matches (a regex).
Composition
Section titled “Composition”alint configs compose via extends:. A config can inherit from local files, HTTPS URLs (with SRI hashes), or alint://bundled/<name>@<rev>. Children override inherited rules field-by-field by id. You only declare the fields that change. only: / except: filters narrow the inherited rule set further. nested_configs: true opts in to discovering .alint.yml files in subdirectories and auto-scoping their rules to the subtree they live in.
extends: is also a trust boundary: a fetched or bundled ruleset can tighten your checks but is barred from declaring process-spawning rules, custom: facts, allow_out_of_root, or a baseline, so adopting someone’s ruleset can never make your machine run their code.
See the Cookbook for composition patterns in practice.
Facts and when: expressions
Section titled “Facts and when: expressions”Facts evaluate properties of the repo once per run and surface them as named values:
facts: - id: has_rust any_file_exists: [Cargo.toml]Rules reference facts in when: to gate themselves conditionally:
- id: rust-snake-case when: facts.has_rust kind: filename_case paths: "src/**/*.rs" case: snake level: errorThe when: grammar supports boolean logic (and / or / not), comparison (== != < <= > >=), in (list / substring), matches (regex), literal types, and facts.X / vars.X / iter.X / env.X identifiers. It’s deliberately bounded: no arbitrary code, no dynamic evaluation.
Auto-fix
Section titled “Auto-fix”Rules that opt in declare a fix: block. Twelve ops cover content edits (trim whitespace, append newline, normalize line endings, strip BOM / bidi / zero-width, collapse blank lines) and path-level changes (create / remove / rename / prepend / append).
- id: trim-trailing-whitespace kind: no_trailing_whitespace paths: "**/*.md" level: info fix: file_trim_trailing_whitespace: {}Preview with alint fix --dry-run; apply with alint fix. Content-editing ops honour fix_size_limit (default 1 MiB) and skip oversize files rather than rewriting them.
Output formats
Section titled “Output formats”Eight formats: human (default; colorized; grouped by file), json (stable schema), sarif (SARIF 2.1.0 for GitHub Code Scanning), github (::error:: / ::warning:: workflow commands for inline PR annotations), markdown (PR-comment tables), junit (CI test-report shape), gitlab (Code Quality), agent (LLM-shaped JSON with per-violation agent_instruction).
alint check --format json --compactThe --compact flag flips human output to one line per violation, suitable for piping to editors / grep / wc -l.