Fast, language-agnostic linter for repository shape, files, and content.
Declare the shape your repo should have (required files, naming conventions,
content patterns, values inside package.json / Cargo.toml
/ GitHub workflows, cross-file relationships) in a single .alint.yml.
alint enforces it. One static Rust binary, any language, any repo.
Cross-file relations, conditional when: rules, structured
queries over JSON / YAML / TOML, and an agent-aware output format make
polyglot trees declaratively enforceable.
30 working configs ship as case studies
(kubernetes, rust, go, NixOS, flutter, dotnet, protobuf, and more),
each with a writeup of what alint catches that the
repo's existing tooling misses.
# Linux / macOS / Windows tarballs
curl -sSL https://raw.githubusercontent.com/asamarts/alint/main/install.sh | bash
# macOS / Linuxbrew
brew tap asamarts/alint
brew install alint
# npm (project-local or global)
npm install --save-dev @asamarts/alint
# Container
docker run --rm -v "$PWD:/repo" ghcr.io/asamarts/alint:latest See alint in action
A polyglot tree (Rust, Node, Python) checked end to end. One shared
.alint.yml extends five bundled rulesets plus a custom
TODO rule. Colourful grouped output by directory, severity glyphs,
per-rule policy links. alint finds what's missing,
suggests what to add, auto-fixes what can be fixed.
Pick a stack. Drop in a .alint.yml. Done.
alint ships twenty-one bundled rulesets that cover most repos with one line of config. Layer them; override one or two rules; add your own.
README, LICENSE, SECURITY.md, hardened CI workflows.
version: 1
extends:
- alint://bundled/oss-baseline@v1
- alint://bundled/hygiene/no-tracked-artifacts@v1
- alint://bundled/ci/github-actions@v1 Cargo manifests, monorepo layout, Trojan-Source defense.
version: 1
extends:
- alint://bundled/oss-baseline@v1
- alint://bundled/rust@v1
- alint://bundled/monorepo@v1
rules:
# Lock every Cargo.toml to edition 2024.
- id: rust-edition-2024
kind: toml_path_equals
paths: "crates/*/Cargo.toml"
path: "$.package.edition"
equals: "2024"
level: error pyproject.toml shape, lockfile, snake_case modules.
version: 1
extends:
- alint://bundled/python@v1
- alint://bundled/ci/github-actions@v1
rules:
# Require pyproject.toml to declare a Python floor.
- id: require-python-floor
kind: toml_path_matches
paths: pyproject.toml
path: "$.project['requires-python']"
matches: '^>=3\.\d+$'
level: warning What alint covers
Eight differentiators plus the composition depth behind them. One static Rust binary, zero network at runtime, every card linked to the doc that explains the underlying primitive.
- 79 rule kinds
- 21 bundled rulesets
- 12 fix ops
- 9 subcommands
- 8 output formats
- 273 ms on NixOS
-
Fast at scale
273 ms on NixOS/nixpkgs (39,101 files): faster than
See benchmarks →git statuson the same repo on a cold cache. ~1.1 s on a 100K-file workspace, ~12 s at 1M files. Numbers regenerate on every release on a known hardware fingerprint. -
79 rule kinds, 13 families
Existence, content, naming, structured query, text hygiene, security / Unicode sanity, encoding, structure, portable metadata, Unix metadata, git hygiene, cross-file, plugin tier. The shape of a repository, decomposed.
Rule catalogue → -
Structured queries
RFC 9535 JSONPath over JSON / YAML / TOML. Validate against full JSON Schema documents. Lock
JSON / YAML / TOML rules →package.jsonshape, pin workflow permissions, requireCargo.tomledition: 2024. -
Cross-file relations
Cross-file rules →pair,for_each_dir,every_matching_has,unique_by,dir_contains. Enforce invariants like "every package has a README", "every workflow has a matching catalog entry", or "every Markdown link resolves to a real file" declaratively. -
Conditional rules
Facts &when:gates rules on facts evaluated once per run:has_rust,has_node,count_files,any_file_exists, customcommandfacts. Bundled rulesets skip cleanly when the ecosystem is absent.when:→ -
Agent-aware
Agent-friendly linter →--format agentemits LLM-shaped JSON with a per-violationagent_instruction.export-agents-mdkeepsAGENTS.mdin sync with the active rule set. Two bundled rulesets (agent-hygiene,agent-context) for AI-touched repos. -
21 bundled rulesets
Bundled rulesets →oss-baseline, language sets (rust,node,python,go,java,dotnet),ci/github-actions, three workspace overlays, hygiene, tooling, compliance,apache/governance.extends:composes them from local paths, SRI-pinned HTTPS, oralint://bundled/…. Built into the binary, no network round-trip. -
Auto-fix & CI-native
12 fix ops, previewable with
GitHub Action & integrations →--dry-run. 9 subcommands (check,fix,init,suggest,explain,list,facts,validate-config,export-agents-md). 8 output formats: SARIF, GitHub PR annotations, JUnit, GitLab Code Quality, Markdown, agent JSON. Official GitHub Action, pre-commit hook, distroless Docker image.--changedfor incremental PR checks. -
Composition & tooling
Configuration reference →# yaml-language-server: $schema=…wires any YAML LSP into the published JSON Schema for.alint.ymlautocomplete and inline validation. Thecommandrule kind shells out to any CLI for plugin-tier rules, trust-gated to the top-level config.nested_configs:discovers per-subtree.alint.ymlfor layered monorepo policy;scope_filter:narrows per-file rules to a closest-ancestor manifest. Compose team policy viaextends:with field-level overrides,only:/except:filters,{{vars.X}}rule templates, and.alint.d/drop-ins.
Why a separate tool
ESLint and Clippy lint your code. Semgrep lints semantics. Repolinter (archived) and OpenSSF Scorecard lint policy. alint sits between code and policy, at the repository's filesystem shape: which files exist, what they're called, what's inside them, how they relate to each other. As coding agents land in more repos, the same shape rules double as the structural backstop the agent reads and self-corrects against.
That sounds narrow until you try to enforce it. "Every package has a
README." "All Rust source files have a copyright header." "GitHub
workflows pin actions to commit SHAs." "Cargo.toml declares
edition 2024." Every one of those is a one-line rule in alint
and a gnarly shell pipeline without it.
Filesystem shape doesn't live in any AST, isn't per-language, and crosses language boundaries, so no host tool has a natural home for it. Bazel, Nx, and Turborepo orchestrate builds; pre-commit and husky run hooks; per-language linters see only their slice of the tree. None of them know what to assert about the repository's structure. alint is the layer that does. See how it compares to the closest alternatives, or read more about the project →
Ready?
The shortest useful .alint.yml is three lines. Most
users start there.