Habit Hooks

Turn best-practice coding advice into AI habits.

uv tool install habit-hooks
cd your-project
habit-hooks init

Why

The effect: better code, better agent performance on the next task, and fewer tokens — good code needs less context to work in.

Does it actually work?

Does coaching actually beat a bare metric, or do both just get gamed? Liina Suoniemi measured it — independently, and pre-registered before any model ran.

Genuine-fix rate by how the instruction is phrased. A coaching prompt reaches 83.3% on both models. The bare linter message reaches 28.9% on Haiku 4.5 and 5.6% on Sonnet 4.6.

18 real Python functions, one known smell each, 5 trials per function per condition, 90 trials per bar. Scored by a deterministic judge — no LLM — checked against blind human labelling at 90% agreement, Cohen's κ 0.85. Method, raw trials and the author's own list of what the judge can miss are all in the repository.

How it works

habit-sensors <scope flags> | habit-mapper

Each sensor translates a tool's raw rule IDs into a tool-independent smell key — max-params, PLR0913 and friends all become too-many-parameters — so the guide is chosen by smell, never by which tool reported it.

Languages

Python ruff, deptry
TypeScript eslint, knip, ts-morph
PHP phpmd
Java pmd
Any line count, jscpd

Each is a separately installable plugin. A project's own config for a wrapped tool always wins — installing Habit Hooks never overrides preferences you already set.

What it catches

oversized-functiontoo-many-parameters high-complexitydeep-nesting oversized-fileunused-variable unused-importloose-equality var-declarationnon-const-binding duplicate-importredundant-type-annotation unused-class-memberunused-file unused-exportunused-dependency test-only-dead-codeparse-error warning-commentexplicit-any non-null-assertionnon-essential-comment duplicated-codeswallowed-exception

Pink fails the run. Grey coaches and exits 0. Either can be overridden per smell.

Starting on an existing codebase

Snooze today's findings, so from then on only new smells surface:

habit-sensors --all | habit-snooze --snooze

Commit the index it writes. Nothing is buried permanently — the ratchet variant brings a file's issues back the moment you touch it.