Use cases

An agent-friendly linter: findings your coding agent can act on

Coding agents run the checks you give them and fix what those checks report. alint gives them your repository's rules: each finding comes with an instruction, and with the command that fixes it where there is one.

Two bundled rulesets cover the context files agents read and what their sessions leave behind: plans at the root, copies of files, debug output, TODOs they signed.

The loop an agent runs

  1. After its change, it runs alint check --format agent --fail-on-warning.
  2. It runs each fix_command in the report.
  3. It fixes the other findings by hand, following each agent_instruction.
  4. It runs the check again, and stops when alint exits with status 0.

--fail-on-warning makes it stop at the right time: without it, alint exits with 0 when it finds only warnings, and every finding in the run below is a warning. A section in AGENTS.md tells the agent to run the loop:

AGENTS.md
## Before you finish a task

Run `alint check --format agent --fail-on-warning`. Run each
`fix_command` it lists as `alint <args>`, fix the other findings by
hand, and run the check again until it exits with status 0.

Before and after the loop

A small TypeScript repository set up the way an agent session often leaves one, checked with the config on this page. The tree marks each of the 9findings of alint check on the file it's about.

  • storefront/9 findings of alint check, marked on the files
  • .alint.yml✓
  • .github/
  • .github/workflows/
  • .github/workflows/ci.yml

    warning gha-workflow-contents-read

    Workflow grants (or defaults to) write access to the GITHUB_TOKEN. Restrict it: declare permissions: contents: read (or read-all, or {}) at the workflow level, or set per-job permissions:, so a compromised step can't push to the repo.

    warning gha-pin-actions-to-sha

    Third-party action is not pinned to a commit SHA. Pin with @<40-char-sha> # v4.1.1 (or docker://img@sha256:... for a Docker action) so a compromised tag can't silently change what runs. Local ./ action references are allowed.

  • AGENTS.md

    warning agents-md-paths-exist

    backticked path src/checkout.ts doesn't resolve to a file or directory

  • PLAN.md

    warning agent-no-scratch-docs-at-root

    Scratch / planning documents should not be committed at the repo root. Move the content into a real doc (CHANGELOG, ADR, design doc, README) or delete it once the work is done.

  • README.md✓
  • package.json✓
  • src/
  • src/cart.ts

    warning agent-no-console-log

    console.log / .debug / .trace left in non-test source. Route through the project logger or remove before merge.

    warning ts-no-trailing-whitespace fixable

    A line in a TypeScript file ends with spaces

  • src/cart_old.ts

    warning agent-no-versioned-duplicates

    Filename looks like a versioned duplicate (e.g. app_old.js, api_FINAL.py, utils_copy.ts). Replace the original instead of keeping a parallel copy.

  • src/coupons.ts

    warning agent-no-model-todos

    Agent-attributed TODO marker. Resolve, convert to a tracked issue, or remove the model attribution. These outlive the session that wrote them.

    warning ts-final-newline fixable

    A TypeScript file doesn't end with a newline

  • tests/
  • tests/cart.test.ts✓
Summary (9 violations):
  ⚠︎ 9 warnings
  17 passing · 9 failing · 2 auto-fixable

  → run `alint fix` to resolve 2 fixable violations.
alint check --format agent --fail-on-warningexit status 1
{  "schema_version": 1,  "format": "agent",  "summary": {    "total_violations": 9,    "by_severity": {      "error": 0,      "warning": 9,      "info": 0    },    "fixable_violations": 2,    "passing_rules": 17,    "failing_rules": 9  },  "violations": [    {      "rule_id": "agents-md-paths-exist",      "severity": "warning",      "file": "AGENTS.md",      "line": 7,      "column": 22,      "human_message": "backticked path `src/checkout.ts` doesn't resolve to a file or directory",      "agent_instruction": "warning: backticked path `src/checkout.ts` doesn't resolve to a file or directory. To resolve: edit AGENTS.md:7:22.",      "fix_available": false    },    {      "rule_id": "ts-final-newline",      "severity": "warning",      "file": "src/coupons.ts",      "human_message": "A TypeScript file doesn't end with a newline",      "agent_instruction": "warning: A TypeScript file doesn't end with a newline. To resolve: edit src/coupons.ts (or run `alint fix --only ts-final-newline` to apply the auto-fix).",      "fix_available": true,      "fix_command": [        "fix",        "--only",        "ts-final-newline"      ],      "proposed_edit": [        {          "path": "src/coupons.ts",          "region": {            "start_line": 2,            "start_column": 37,            "end_line": 2,            "end_column": 37          },          "inserted": "\n"        }      ]    } 7 more findings  ]}

The same run as one JSON document for the agent: a summary, then each finding with its file, line and severity. agent_instruction is the rule's message, then where to edit, then the alint fix command when the rule has a fix.

fix_command holds those arguments on their own, so the agent runs alint fix --only ts-final-newline instead of editing the file.

alint fix
 7 more findings warning [ts-final-newline]:  ✓ appended final newline to src/coupons.ts warning [ts-no-trailing-whitespace]:  ✓ trimmed trailing whitespace in src/cart.ts 2 applied, 0 skipped, 7 unfixable.
 7 more findings warning [ts-final-newline]:  ✓ appended final newline to    src/coupons.ts warning [ts-no-trailing-whitespace]:  ✓ trimmed trailing whitespace in    src/cart.ts 2 applied, 0 skipped, 7 unfixable.

alint fix applies every fix at once; each report entry's fix_command applies one rule's. The other 7 findings need an edit. The second run follows the edits an agent following each agent_instruction would make: deleted PLAN.md and src/cart_old.ts, took out the console.log and the TODO signed by a model, pointed AGENTS.md at src/cart.ts, and pinned the workflow's checkout action and made its token read-only.

alint check --format agent --fail-on-warningexit status 0
{  "schema_version": 1,  "format": "agent",  "summary": {    "total_violations": 0,    "by_severity": {      "error": 0,      "warning": 0,      "info": 0    },    "fixable_violations": 0,    "passing_rules": 26,    "failing_rules": 0  },  "violations": []}

No findings, and alint exits with status 0: here an agent would stop.

The config

For a TypeScript repository, and the one every run above used. For another language, change the paths of the last two rules.

.alint.yml
version: 1
extends:
  - url: alint://bundled/agent-context@v1
    except: [agent-context-no-stale-paths]
  - alint://bundled/agent-hygiene@v1
  - alint://bundled/hygiene/no-tracked-artifacts@v1
  - alint://bundled/ci/github-actions@v1

rules:
  - id: agents-md-paths-exist
    kind: markdown_paths_resolve
    paths: ["AGENTS.md"]
    prefixes: ["src/", "tests/"]
    level: warning

  - id: ts-final-newline
    kind: final_newline
    paths: "src/**/*.ts"
    level: warning
    message: "A TypeScript file doesn't end with a newline"
    fix:
      file_append_final_newline: {}

  - id: ts-no-trailing-whitespace
    kind: no_trailing_whitespace
    paths: "src/**/*.ts"
    level: warning
    message: "A line in a TypeScript file ends with spaces"
    fix:
      file_trim_trailing_whitespace: {}
.alint.yml
version: 1
extends:
  - url: alint://bundled/agent-context@v1
    except: [agent-context-no-stale-paths]
  - alint://bundled/agent-hygiene@v1
  - alint://bundled/hygiene/no-tracked-artifacts@v1
  - alint://bundled/ci/github-actions@v1

rules:
  - id: agents-md-paths-exist
    kind: markdown_paths_resolve
    paths: ["AGENTS.md"]
    prefixes: ["src/", "tests/"]
    level: warning

  - id: ts-final-newline
    kind: final_newline
    paths: "src/**/*.ts"
    level: warning
    message: "A TypeScript file doesn't end with a newline"
    fix:
      file_append_final_newline: {}

  - id: ts-no-trailing-whitespace
    kind: no_trailing_whitespace
    paths: "src/**/*.ts"
    level: warning
    message: "A line in a TypeScript file ends with spaces"
    fix:
      file_trim_trailing_whitespace: {}
  1. Lines 2 to 7

    Four rulesets that ship with alint: the context files agents read, what their sessions leave behind, files that shouldn't be tracked and the basics of GitHub Actions workflows. The path hint in agent-context is off, because the next rule checks paths exactly.

  2. Lines 10 to 14

    Every backticked path under src/ or tests/ in AGENTS.md has to exist (markdown_paths_resolve). Agents rename files; context files don't follow.

  3. Lines 16 to 30

    Two rules alint can fix, a final newline and no trailing whitespace. Their messages are what the agent reads.

What makes the agent run it

The section in AGENTS.md is a request, and an agent can skip it, more often late in a long session (Chroma found models get less reliable as their input grows). These three run the same check whether the agent remembers or not.

.github/workflows/ci.ymlthe alint step
- uses: asamarts/alint@c08c68be72e0c3a3a02051bd15f4a7d768fa5cbe # v0.18.2
  with:
    version: v0.18.2
    fail-on-warning: true

The GitHub Action fails the pull request until the findings are fixed. The step is pinned to the release's commit, and version: keeps the binary at the same release.

.pre-commit-config.yaml
repos:
  - repo: https://github.com/asamarts/alint-pre-commit
    rev: v0.18.2
    hooks:
      - id: alint
        args: [--fail-on-warning]

The pre-commit hook checks every commit, the agent's included, and refuses the commit while there are findings.

.claude/settings.json
{ "hooks": { "Stop": [{ "hooks": [{ "type": "command", "command": "alint check --format agent --fail-on-warning >&2 || exit 2" }] }] } }

In Claude Code, a Stop hook runs when the agent is about to finish. Exit status 2 keeps the session going and gives the agent the report. A finding the agent can't fix keeps it going too, so use it with rules an agent can act on.

AGENTS.md from your config

alint export-agents-md turns the rules in your config into a section for AGENTS.md, one line per rule, from each rule's message. With --inline it writes the section into the file, between its start and end markers, and leaves the rest of the file alone:

alint export-agents-md --inline --output AGENTS.md
AGENTS.md
<!-- alint:start -->

## Lint rules enforced by alint

Generated from `.alint.yml` by `alint export-agents-md`. Re-run after editing the lint config - these directives must stay in sync with what alint blocks at commit time. Manual edits inside this section are overwritten.

### Errors (commit will fail)

- **`agent-no-debugger-statements`**: `debugger;` / `breakpoint()` must not be committed. These halt execution at runtime. Remove before merge.
- **`hygiene-no-cargo-target`**: dir_absent rule on **/target
- **`hygiene-no-env-files`**: Environment files containing real values must not be committed. Use `.env.example` (or similar) for shared non-secret defaults.
- **`hygiene-no-macos-junk`**: macOS Finder metadata must not be committed.
- **`hygiene-no-node-modules`**: `node_modules/` must not be committed. Add it to .gitignore.
- **`hygiene-no-python-cache`**: Python caches and virtualenvs must not be committed.
- **`hygiene-no-windows-junk`**: Windows shell metadata must not be committed.

### Warnings (review before merge)

- **`agent-context-non-stub`**: Agent-context file is suspiciously short. Either fill it in with real guidance or remove it. Empty context files mislead agents that load them.
- **`agent-no-console-log`**: `console.log` / `.debug` / `.trace` left in non-test source. Route through the project logger or remove before merge.

The section goes on the same way for 12 more rules: 21 of the config's26, since the 5 at level: info are left out (--include-info adds them). Run it again when .alint.yml changes, or in CI, so the file never lists rules CI no longer checks.

The two agent rulesets

agent-context (4 rules) checks the files coding agents read at the start of a session: AGENTS.md, and the equivalents for Claude Code, Cursor, Gemini and GitHub Copilot. agent-hygiene(6 rules) reports what a session can leave behind, by file name and text, whoever committed it.

RuleWhat it checksLevel
agent-context-recommendedAn AGENTS.md, CLAUDE.md or .cursorrules exists at the rootinfo
agent-context-non-stubEach context file has at least 10 lineswarning
agent-context-not-bloatedEach context file has at most 300 linesinfo
agent-context-no-stale-pathsPoints out backticked paths in AGENTS.md and CLAUDE.md, so you can check they still exist (off in the config above, which checks each path instead)info
agent-no-versioned-duplicatesFiles named like copies: _old, _new, _final, _copy, _backup or .copy. before the extensionwarning
agent-no-scratch-docs-at-rootScratch documents at the root: PLAN.md, NOTES.md, TODO.md and 8 other nameswarning
agent-no-affirmation-prosePhrases such as "you're absolutely right" or "happy to help" in code and Markdowninfo
agent-no-console-logconsole.log, .debug and .trace in JavaScript and TypeScript source, not tests or scriptswarning
agent-no-debugger-statementsdebugger; in JavaScript and TypeScript, breakpoint() in Python, outside testserror
agent-no-model-todosTODO, FIXME, XXX or HACK comments attributed to a model, such as TODO(claude)warning

Apart from agent-context-recommended, the context rules run only in a repository that has one of those files. Editor backups, a committed node_modules/ and .env files are the job of hygiene/no-tracked-artifacts, the third ruleset in the config. In the docs, alint for coding agents explains how the pieces fit together, the agent output format lists every field, and export-agents-md its options.