Fast, language-agnostic linter for repository structure, files, and content. Declare the shape your repo should have (required files, filename conventions, content patterns, values inside package.json / Cargo.toml / GitHub workflows, cross-file relationships) in a single .alint.yml. alint enforces it.
agent output format with per-violation agent_instruction strings; bundled agent-hygiene and agent-context rulesets for AI-touched repos.when: gates over per-run facts, and extends: composition with SRI-pinned URLs.Working .alint.yml configs for 30 OSS repos (single-language workspaces, polyglot monorepos, scale stress-tests) live under examples/, each with a writeup of what alint catches that the repo's existing tooling misses.
# Install (Linux + macOS + Windows tarballs):
curl -sSL https://raw.githubusercontent.com/asamarts/alint/main/install.sh | bash
# Initialise a config in the current repo (uses bundled oss-baseline + auto-detected ecosystem rulesets):
cat > .alint.yml <<'YAML'
version: 1
extends:
- alint://bundled/oss-baseline@v1
- alint://bundled/rust@v1 # auto-skips when not a Rust repo
- alint://bundled/ci/github-actions@v1
YAML
# Check:
alint check
# Auto-fix what's mechanically fixable (preview first):
alint fix --dry-run
alint fix
Bundled rulesets are gated by ecosystem facts (has_rust, has_node, has_python, …), so listing one for an ecosystem you don't have is a silent no-op. See docs/rules.md for the full rule catalogue and alint.org for narrative docs.
command shellout). Full reference: docs/rules.md.oss-baseline (a strict superset of Repolinter's default ruleset for users migrating from that tool, archived 2026-02), language sets (rust, node, python, go, java, dotnet, php), ci/github-actions, monorepo overlays (cargo-workspace, pnpm-workspace, yarn-workspace), hygiene (no-tracked-artifacts, lockfiles), tooling (editorconfig), docs (adr), compliance (reuse, apache-2), apache/governance (Apache TLP governance discipline), agent (hygiene, context). Built into the binary, no network round-trip; ecosystem-gated, so listing one for an absent ecosystem is a silent no-op.alint fix --dry-run. Configurable fix_size_limit (default 1 MiB) skips oversize files rather than rewriting them.when: expression language (boolean logic, comparisons, matches, in) gates rules on facts evaluated once per run (any_file_exists, all_files_exist, count_files).extends: pulls in other configs by local path, HTTPS URL (SRI-pinned), or alint://bundled/<name>@<rev>. Children override field-by-field. Monorepos can opt into nested_configs: true for auto-discovered subtree-scoped .alint.yml files.check (default; supports --changed for PR-fast-path linting), fix, init (auto-detect ecosystem + scaffold), validate-config (parse-only; for editor LSP / pre-commit / fail-fast CI), explain <rule>, list, suggest (scan for antipatterns and propose rules), facts (debug when: clauses), export-agents-md (sync AGENTS.md from active rules), lsp (language server over stdio for editor integrations).human, json (stable schema), sarif (GitHub Code Scanning), github (inline PR annotations), markdown (PR comments), junit (CI test reports), gitlab (Code Quality), agent (LLM-shaped JSON with agent_instruction per violation).schemas/v1/config.json for editor autocomplete; report shapes at schemas/v1/check-report.json and schemas/v1/fix-report.json for downstream tooling.extends: https://... URLs (SRI-pinned). Reproducible builds (Cargo.lock committed, pinned toolchain). See SECURITY.md for the threat model.asamarts/alint@v0.13.0.alint isn't trying to be everything to everyone. The validation pass across 30 OSS repos surfaced five distinct shapes of project where alint earns its keep:
build/hygiene.ts → ~75% covered declaratively).meta-updater plugin), facebook/react, nodejs/node.publish = false discipline), prettier, helm, dotnet/runtime (~2,300 XML manifests with structural invariants no existing tool covers).lintrunner.toml adapters are structural; alint sits beneath, lintrunner keeps the AST-aware tail), bazel (alint replaces the structural subset of bazel's hand-rolled CI scripts)..github/workflows/, zero Makefile, zero .golangci.yml; the 31-rule alint config encodes the project's structural contract for the first time anywhere).Polyglot wins as a sixth shape: when a single tree spans languages or platforms (apache/arrow's 6 languages, vercel/next.js's TS+Rust, NixOS/nixpkgs at 39k files, flutter's Dart-framework-with-6-native-embedders, protobuf's 11 language bindings), no per-language linter sees the cross-cutting conventions; alint is the layer that does.
If your repo doesn't match one of these shapes, alint is probably still useful (the rule catalogue is broad), but you may want to start by reading the closest case study above to see what a working config looks like in your shape.
alint is deliberately not:
Scope is the filesystem shape and contents of a repository, not the semantics of the code inside it.
curl -sSL https://raw.githubusercontent.com/asamarts/alint/main/install.sh | bash
Detects platform (Linux / macOS, x86_64 / aarch64), downloads the matching tarball, verifies the SHA-256, and installs to $INSTALL_DIR (default ~/.local/bin). Windows users download the Windows tarball from the Releases page.
brew tap asamarts/alint
brew install alint
The asamarts/homebrew-alint tap is auto-updated on every alint release. The formula downloads the matching pre-built binary, verifies its SHA-256, and installs to the Homebrew cellar.
cargo install alint
# project-local
npm install --save-dev @asamarts/alint
npx alint check
# global (puts `alint` on PATH)
npm install -g @asamarts/alint
alint check
The @asamarts/alint package is a thin shim that downloads the matching pre-built binary at install time, verifies its SHA-256 against the same .sha256 companion install.sh and Homebrew use, and stages it under the package's bin-platform/. The package itself ships zero JS runtime behaviour. Set ALINT_SKIP_INSTALL=1 to suppress the postinstall network hop in CI environments that snapshot node_modules.
git clone https://github.com/asamarts/alint
cd alint
cargo build --release -p alint
./target/release/alint --help
A distroless multi-arch image (linux/amd64, linux/arm64) is published to ghcr.io on each release:
# Lint the current directory:
docker run --rm -v "$PWD:/repo" ghcr.io/asamarts/alint:latest
# Pin to an exact version:
docker run --rm -v "$PWD:/repo" ghcr.io/asamarts/alint:v0.13.0 check
The image runs as the distroless nonroot user (UID 65532); host files must be world-readable. To apply fixes and preserve host ownership, pass -u:
docker run --rm -u $(id -u):$(id -g) -v "$PWD:/repo" ghcr.io/asamarts/alint:latest fix
Also published: :<major>.<minor> (e.g. :0.10) and the raw git tag (:v0.13.0).
The fastest on-ramp is alint init. It scans your repo for the obvious markers (Cargo.toml, package.json, pnpm-workspace.yaml, …) and writes a .alint.yml with the right extends: lines:
alint init # ecosystem-aware (rust@v1, node@v1, …)
alint init --monorepo # plus workspace overlays for Cargo / pnpm / Yarn
For an existing repo with prior debt, follow up with alint suggest. It scans for *.bak files, scratch docs at root, console.log residue in production source, and TODO markers older than 180 days, then proposes the bundled rulesets and rule entries that would catch them. Output is review-only; suggest never edits your config:
alint suggest # human-readable proposal table
alint suggest --format yaml # paste-ready config snippet
alint suggest --format json # stable shape for agent consumption
alint suggest --explain # show file-level evidence per proposal
For agent-driven workflows where AGENTS.md / CLAUDE.md / .cursorrules carries the directives the agent reads at session start, alint export-agents-md renders the active rule set as a markdown directive block. alint becomes the single source of truth, and the agent reads what alint enforces:
alint export-agents-md # to stdout
alint export-agents-md --inline --output AGENTS.md # splice between alint markers
--inline writes only between / markers; everything else in AGENTS.md is human-owned prose. Re-runs are idempotent (when the on-disk content already matches, no write happens), and missing markers auto-init with a stderr warning so the second run splices cleanly.
The generated file is editable: start there, override or extend as needed. If you'd rather hand-roll, the minimum viable shape is:
# .alint.yml
# yaml-language-server: $schema=https://raw.githubusercontent.com/asamarts/alint/main/schemas/v1/config.json
version: 1
extends:
- alint://bundled/oss-baseline@v1 # README/LICENSE/SECURITY.md, merge markers, hygiene
Then run:
``bash
alint check # run all rules against the current directory
alint fix --dry-run # preview the auto-fixes that would be applied
alint fix # apply every fixable violation in place
alint list # list effective rules (useful after extends / overrides)
alint explain <id> # show a rule's full, resolved definition
alint facts # evaluate facts against the repo; debugwhen:clauses
alint init [--monorepo] # scaffold a.alint.yml` based on detected ecosystem + workspace shape
alint suggest # scan for known antipatterns and pr
$ claude mcp add alint \
-- python -m otcore.mcp_server <graph>