Lintrule Documentation


    How to use Lintrule in production

    The point of Lintrule is to reduce bottlenecks on senior IC engineers and catch defects before they hit production.

    If there's a required reviewer, there should be a rule

    Even though LLMs are expensive, it's far, far cheaper to have the LLM check your code than it is to set a senior engineer as a codeowner and have them be the bottleneck for every PR.

    To get the most bang for your buck, target Lintrule towards the most dangerous parts of your codebase. You might want to look at where you have senior ICs as required reviewers Typically, these are places like:

    • Your database migrations -> .rules/
    • Your terraform config -> .rules/
    • Your authorization code -> .rules/
    • Your distributed systems logic -> .rules/

    Sit down with your required reviewers and have them write down what they're checking for, in plain text, as a ruleset.

    If there's a post-mortem, there should be a rule

    When you have a production incident, add a rule to prevent it from happening again. Occasionally, you can literally stick your post-mortem, directly into a ruleset, with a prompt like this:

    Prevent outages like the one described in the post-mortem below:
    # post-mortem here...

    Writing good rules

    Lintrule sometimes requires "prompt engineering", but not typically. Here's some tips for how to write rules effectively.

    Use multiple checks in one ruleset

    You can add lots of rules in one file. Typically folks do this with either markdown headers, or with bullet points.

    Fail if we're doing any of these in typescript:
    - Using `console.log` or `console.error` instead of `stat.increment` or `log()` from `next-axiom` (our logging library)
    - Don't pass around `supabase` as an argument. Instead use the imported `serverSupabase`.
    - Prefer imports like `@/app/lib` instead of relative imports like `../../lib`

    Use the comments already have in your code

    You probably leave comments in your code like "warning: this shouldn't be used unless you do X". Lintrule can use these comments or check if they're not there when they should be.

    For example, say you want to prevent breaking changes in your migrations. You might have a rule like:

    Prevent breaking changes in SQL migrations, like dropping tables or columns.

    But then you discover that this fails when you want to have a breaking change. That's okay, you can fix this by just telling Lintrule it's okay, so long as someone has given a good explanation in a comment.

    Prevent breaking changes in SQL migrations, like dropping tables or columns. (unless there's a comment explaining why)

    Use terms like fail and pass

    Lintrule's job is to give a yes / no on your code. Other terms that mean the same thing tend to work too, like:

    • "don't let this pass if"
    • "avoid doing x"
    • "prevent y"

    Use your own language

    Language models speak lots of languages, you don't need to write your rules in english.

    échouer si nous faisons l'un de ces points en TypeScript :
    - Utiliser `console.log` ou `console.error` au lieu de `stat.increment` ou `log()` de `next-axiom` (notre bibliothèque de log)
    - Ne pas passer `supabase` comme argument. Utilisez plutôt le `serverSupabase` importé.
    - Préférer des imports comme `@/app/lib` au lieu des imports relatifs comme `../../lib`