lintent uses lintent.yaml to define semantic meaning for lint rules.

Basic Structure

rules:
  <linter>:
    <code>:
      illegal: "What the rule catches"
      legal: "What correct code looks like"
      why: "The reasoning"

Minimal Example

rules:
  ruff:
    F401:
      illegal: "Importing modules that are not used"
      legal: "Only import what you use"
      why: "Clean dependency graph, faster startup"

Full Example

# lintent.yaml

rules:
  ruff:
    E501:
      illegal: "Lines over 88 characters"
      legal: "Break into multiple lines or extract to named variables"
      why: "Readability - code should fit in viewport"

    F401:
      illegal: "Importing modules that are not used"
      legal: "Only import what you use, or mark with # noqa: F401 if for side-effects"
      why: "Clean dependency graph, faster startup, clearer code"

    F841:
      illegal: "Assigning to a variable that is never read"
      legal: "Use the variable, remove it, or prefix with _ if intentional"
      why: "Dead code indicates logic errors or incomplete refactoring"

    B006:
      illegal: "Mutable default argument in function definition"
      legal: "Use None as default and create mutable inside function"
      why: "Mutable defaults are shared across calls, causing subtle bugs"

  pyright:
    reportMissingParameterType:
      illegal: "Function parameter without type annotation"
      legal: "def func(param: Type) -> ReturnType"
      why: "Type annotations enable tooling and catch errors early"

Linter Overrides

For monorepos or custom setups, override linter paths:

linters:
  ruff:
    enabled: true
    paths: ["./backend/src"]

  eslint:
    enabled: true
    config: "./frontend/.eslintrc.js"
    paths: ["./frontend/src"]

  pyright:
    enabled: false  # Explicitly disable

rules:
  ruff:
    F401:
      illegal: "Unused imports"
      legal: "Only import what you use"
      why: "Clean dependencies"

Linter Override Fields

Field Type Default Description
enabled boolean auto-detected Force enable or disable
config string auto-detected Path to linter config file
paths string[] ["."] Directories to lint

Writing Good Semantic Rules

Be Specific

# Good
illegal: "Using == for None comparison"
legal: "Use 'is None' or 'is not None'"
why: "None is a singleton; identity check is faster and clearer"

# Bad
illegal: "Bad comparison"
legal: "Use better comparison"
why: "It's better"

Include Examples When Helpful

illegal: "Mutable default argument"
legal: |
  Use None as default:
  def func(items=None):
      items = items or []
why: "Mutable defaults are shared across calls"

Think About Intent

Ask yourself: - What is the rule trying to prevent? - What should the developer do instead? - Why does this matter?

Using Presets

Start with a preset and customize:

lintent init --preset python

Then edit lintent.yaml to add or modify rules.

Validation

Check your config for errors:

lintent validate --pretty
{
  "valid": true,
  "linters": ["ruff", "pyright"],
  "rules_count": 10
}

Next Steps