lefthook: οι έλεγχοι που ξεχνάς γίνονται αυτόματοι, και τρέχουν παράλληλα
Το lefthook είναι ένα δυαδικό αρχείο γραμμένο σε Go που τρέχει τα git hooks — pre-commit, commit-msg, pre-push — παράλληλα, με δικό του αρχείο ρυθμίσεων lefthook.yml, χωρίς Node ή Python κατά την εκτέλεση. Η υπόσχεση: οι έλεγχοι που ξεχνάς γίνονται αυτόματοι, οπότε δεν σπρώχνεις σπασμένο κώδικα. Το ζυγίσαμε στο μηχάνημά μας: 14 MB στον δίσκο, ένα αρχείο, μηδέν εξαρτήσεις, μηδέν tokens στο μοντέλο, μηδέν ευρώ. Και βρήκαμε μία παγίδα που αξίζει να την ξέρεις: ένα σπασμένο hook μπορεί να φαίνεται ότι πέρασε, αν το δοκιμάσεις χωρίς να έχεις κάνει git add.

Τι κάνει
Έχεις πιάσει τον εαυτό σου να ανεβάζει κώδικα που δεν έχεις ελέγξει. Δεν το έκανες από αμέλεια. Ήσουν κουρασμένος, ή βιαζόσουν, ή απλώς ξέχασες. Το lefthook υπάρχει για να μη συμβεί αυτό.
Δύο λέξεις πρώτα, γιατί χωρίς αυτές το υπόλοιπο δεν βγάζει νόημα. Τα «git hooks» είναι σημεία στα οποία το git σταματά και σου δίνει τον λόγο να τρέξεις κάτι δικό σου πριν προχωρήσει. Το πιο γνωστό είναι το pre-commit: τρέχει ακριβώς πριν κλειδώσει το commit. Το commit-msg τρέχει όταν γράφεις το μήνυμα του commit. Το pre-push τρέχει λίγο πριν στείλεις στον απομακρυσμένο server. Αν ένας από αυτούς τους ελέγχους βγει με σφάλμα, η πράξη μπλοκάρει.
Το lefthook αναλαμβάνει να τρέχει όλα αυτά για σένα. Είναι ένα δυαδικό αρχείο γραμμένο σε Go — δηλαδή ένα εκτελέσιμο που δεν χρειάζεται κάποια γλώσσα ή βιβλιοθήκη εγκατεστημένη από πίσω για να δουλέψει. Τις ρυθμίσεις τις διαβάζει από ένα δικό του αρχείο, το lefthook.yml, όπου γράφεις ποιοι έλεγχοι τρέχουν σε ποιο σημείο. Και το βασικό: τους τρέχει παράλληλα, όχι τον έναν μετά τον άλλον.
Αυτό το τελευταίο είναι όλη η αξία. Σκέψου πέντε ελέγχους που ο καθένας παίρνει δύο δευτερόλεπτα. Σειριακά, δέκα δευτερόλεπτα. Παράλληλα, κοντά στα δύο. Στην πράξη οι έλεγχοι είναι οι ίδιοι που θα έτρεχες και με το χέρι — μόνο που δεν τους θυμάσαι ποτέ, και δεν τους περιμένεις.
Το project το συντηρεί η Evil Martians, το στούντιο πίσω από άλλα γνωστά εργαλεία του οικοσυστήματος. Το αποθετήριο ζει από τον Φεβρουάριο του 2019 και έχει σήμερα 8.953 αστέρια, 329 forks και 105 ανοιχτά issues, με άδεια MIT· η τελευταία δραστηριότητα είναι στις 26 Οκτωβρίου 2026 (αποθετήριο).
Μία διευκρίνιση που τη χρειάζεσαι από την αρχή: το lefthook δεν είναι διακομιστής MCP. Δεν μιλάει με το μοντέλο, δεν φορτώνει σχήμα εργαλείων, δεν καταλαμβάνει χώρο στη συνεδρία σου. Είναι εργαλείο του κελύφους, που τρέχει όταν τρέχει το git. Θα το ξαναπούμε στην ώρα του, γιατί πολλοί το μπερδεύουν με ό,τι άλλο κυκλοφορεί τελευταία.
Για ποιον είναι
Για όποιον δουλεύει σε ομάδα, ή μόνος σε πολλά project, και θέλει να σταματήσει να στέλνει κώδικα που χαλάει τον κώδικα των άλλων. Ο ερασιτέχνης που μόλις άκουσε τη λέξη «πράκτορας» θα πιάσει το όφελος από την πρώτη φορά που θα ξεχάσει να τρέξει το τεστ: το εργαλείο το τρέχει μόνο του, και το commit δεν κλείνει αν κάτι δεν περνά. Ο επαγγελματίας κερδίζει κάτι πιο ακριβές: σταματά να μεταφέρει τους κανόνες του project στο κεφάλι του, γιατί τους γράφει μία φορά στο YAML και δεν τους ξανασκέφτεται.
Λάμπει όταν το project έχει πολλούς ελέγχους — μορφοποίηση, στατική ανάλυση, τεστ — και ο χρόνος αναμονής σε κάθε commit άρχισε να σε ενοχλεί. Λάμπει σε project που θα ζήσει καιρό, γιατί το μόνο που κληροδοτείς στον επόμενο είναι ένα αρχείο κειμένου.
Δεν είναι για σένα αν δουλεύεις μόνος σε ένα πρόχειρο script που δεν θα το ξαναδείς. Εκεί το κόστος εγκατάστασης δεν το βγάζει. Και δεν είναι για σένα αν θέλεις κάτι που να ελέγχει τον κώδικα μέσα στην κουβέντα με τον βοηθό· αυτό είναι άλλη κατηγορία εργαλείου, και το lefthook δεν την αγγίζει.
Εγκατάσταση
Θέλεις Node, μόνο και μόνο για να κατεβάσει το δυαδικό· από εκεί και πέρα η εκτέλεση δεν χρειάζεται Node ούτε Python. Το πεδίο engines του πακέτου είναι κενό (null) — δεν απαιτεί καμία έκδοση. Το npm εδώ είναι ο μεταφορέας, όχι η μηχανή.
Τρέχεις από τη ρίζα του project σου:
npm i -D lefthook@2.2.2Μετά γράφεις το lefthook.yml στη ρίζα, με ένα hook που θέλεις. Και μετά λες στο lefthook να εγκαταστήσει το ίδιο το hook στο git:
npx lefthook installΑυτό γράφει το hook στο .git/hooks/pre-commit — το σημείο που το git διαβάζει μόνο του. Από εδώ και πέρα δεν καλείς τίποτα χειροκίνητα: το git φωνάζει το lefthook κάθε φορά που κάνεις commit.
Μία παγίδα του Windows που τη συναντήσαμε. Το npm δίνει δύο αρχεία: ένα shim με κατάληξη .cmd, και το πραγματικό .exe κάτω από τον φάκελο lefthook-windows-x64. Αν καλέσεις το shim από το κέλυφος bash, παίρνεις «No such file or directory» — δεν είναι σφάλμα του lefthook, είναι το shim που δεν τρέχει έτσι. Μέσα από npx το πρόβλημα δεν εμφανίζεται.
Ο κατασκευαστής τεκμηριώνει κι άλλους δρόμους εγκατάστασης — Homebrew, go install, απευθείας δυαδικό από τις εκδόσεις. Αυτό είναι ισχυρισμός κατασκευαστή: εμείς τρέξαμε μόνο τον δρόμο του npm, και δεν θα σου περιγράψω βήματα που δεν εκτέλεσα.
Χρήση σε κάθε LLM
Εδώ χρειάζεται προσοχή, γιατί το lefthook δεν μοιάζει με τα εργαλεία που συνήθως παρουσιάζουμε. Δεν είναι διακομιστής MCP. Δεν του γράφεις ρύθμιση τύπου mcpServers, δεν δηλώνεις εκτελέσιμο και ορίσματα, δεν κάνεις επανεκκίνηση για να το δει ο βοηθός. Δεν χρειάζεται καν να το δηλώσεις.
Ο λόγος είναι απλός και αξίζει να τον καταλάβεις. Το lefthook κάθεται πάνω στα git hooks. Τα hooks τρέχουν όταν τρέχει το git — άρα και όταν ο βοηθός κάνει commit. Ο πράκτορας δεν χρειάζεται να ξέρει ότι το lefthook υπάρχει· το git το καλεί μόνο του. Το μόνο που προσθέτεις ανά βοηθό είναι μία οδηγία, ώστε να μη σπάσει το hook με παράκαμψη τύπου --no-verify. Δεν έστησα συνεδρία μέσα σε Claude Code, Codex ή Cursor· οι εντολές είναι του κελύφους, και λέω πού το ξέρω.
Claude Code
Γράφεις τη σύμβαση του project στο CLAUDE.md: πριν από κάθε commit τρέχει το hook, χωρίς παράκαμψη. Και αν θέλεις να το δοκιμάσεις ο ίδιος, τρέχεις από τη ρίζα του project:
npx lefthook run pre-commitCodex CLI
Το ίδιο, σε αρχείο οδηγιών AGENTS.md στη ρίζα. Δεν υπάρχει ενότητα ρυθμίσεων να προσθέσεις — μόνο η σύμβαση και η ίδια εντολή:
npx lefthook run pre-commitCursor
Και εδώ το ίδιο σχήμα: μία οδηγία στους κανόνες του project, καμία δήλωση διακομιστή. Για έλεγχο με το χέρι:
npx lefthook run pre-commitΣε CI
Εδώ φαίνεται η μεγάλη αρετή του YAML: το ίδιο αρχείο δουλεύει και στο CI, χωρίς δεύτερη ρύθμιση. Βάζεις ένα βήμα που τρέχει την ίδια εντολή πριν από το build:
npx lefthook run pre-commitΈτσι οι κανόνες δεν ζουν στο μηχάνημα του καθενός, αλλά σε ένα αρχείο που περνά από review όπως όλος ο υπόλοιπος κώδικας. Η ίδια ρύθμιση για τοπικά hooks και για CI είναι, κατά τη γνώμη μας, το πιο υποτιμημένο πλεονέκτημα του εργαλείου.
Πού κερδίζει, πού χάνει
Κερδίζει στο κεντρικό: οι έλεγχοι που ξεχνάς γίνονται αυτόματοι. Στη δοκιμή μας, ένα hook που απαγορεύει τη λέξη TODO μπλόκαρε το commit με exit 1 όταν τη βρήκε, και πέρασε με exit 0 όταν το αρχείο ήταν καθαρό.
Κερδίζει στην ταχύτητα. Η εκτέλεση ήταν 0,09 δευτερόλεπτα για ένα hook — και επειδή τρέχουν παράλληλα, η διαφορά μεγαλώνει όσο προσθέτεις ελέγχους. Κερδίζει στην καθαρότητα: ένα στατικό δυαδικό, μηδέν εξαρτήσεις κατά την εκτέλεση, καμία διεργασία που μένει ανοιχτή. Και κερδίζει στο ότι η ρύθμιση είναι ένα αρχείο κειμένου, που το διαβάζει ο άνθρωπος και το εκτελεί το CI το ίδιο.
Τώρα πού χάνει.
Πρώτο, η καινοτομία είναι μέτρια, και θέλουμε να το πούμε καθαρά. Το lefthook δεν ανοίγει καινούργιο δρόμο. Αντικαθιστά το husky — το εργαλείο των JavaScript project που κάνει την ίδια δουλειά. Δεν φέρνει νέα ιδέα· φέρνει καλύτερη εκτέλεση. Παράλληλα αντί σειριακά, ένα στατικό δυαδικό αντί για Node, μηδέν εξαρτήσεις αντί για ένα δέντρο πακέτων. Αυτό δεν είναι μειονέκτημα — είναι ακριβώς ο λόγος που είναι καλή επιλογή για ένα project που θα ζει σε έξι μήνες. Αλλά δεν πρέπει να περιμένεις επανάσταση· περιμένεις κάτι που δουλεύει και δεν σε απασχολεί.
Δεύτερο, η παγίδα της σιωπής. Όταν τρέχεις το hook χωρίς σταθμευμένα αρχεία, παραλείπεται με ένα μήνυμα και βγαίνει με exit 0. Δηλαδή ένα σπασμένο hook μπορεί να φαίνεται «πέρασε», αν το δοκιμάσεις στα τυφλά. Το αναλύουμε στην επόμενη ενότητα, γιατί το βρήκαμε μόνοι μας και είναι το πιο χρήσιμο πράγμα σε αυτό το άρθρο.
Τρίτο, θέλει YAML. Όποιος δεν έχει γράψει ποτέ YAML θα κάνει ένα λάθος στη στοίχιση. Είναι μικρό εμπόδιο, αλλά υπάρχει.
Δοκιμή
Ό,τι ακολουθεί τρέξαμε σε Windows 11, σε Dell Inspiron 3576, με Node 26.7.0, χωρίς κάρτα γραφικών.
Έστησα φρέσκο αποθετήριο git και έγραψα το lefthook.yml με ένα hook που απαγορεύει τη λέξη TODO μέσα στο app.js. Το πρώτο πράγμα που έτρεξα ήταν η εγκατάσταση του hook:
npx lefthook installΈγραψε το hook στο .git/hooks/pre-commit, όπως περίμενα.
Μετά έβαλα ένα καθαρό app.js, το πρόσθεσα στο staging και έτρεξα τον έλεγχο. Βγήκε exit 0 και τύπωσε «done in 0.09 seconds». Μετά έβαλα μέσα ένα TODO, το πρόσθεσα, και ξανάτρεξα. Βγήκε exit 1 — το commit μπλοκάρει. Δηλαδή η υπόσχεση ισχύει: ο έλεγχος τρέχει, κρίνει, και σταματά το λάθος.
Και μετά η παγίδα, που την ανακάλυψα μόνη μου και αξίζει μία παράγραφο.
Την πρώτη φορά έτρεξα npx lefthook run pre-commit πριν κάνω git add, με άδειο staging. Το hook παραλείφθηκε. Τύπωσε no-todo (skip) no matching staged files και βγήκε με exit 0. Αν δεν το πρόσεχα, θα είχα καταγράψει «πέρασε» — ενώ στην πραγματικότητα δεν είχε τρέξει τίποτα. Αυτή είναι η σιωπηλή αποτυχία που μπορεί να σε κάψει: ένα σπασμένο hook μοιάζει υγιές αν το δοκιμάσεις χωρίς να έχεις σταθμεύσει αρχεία. Το έμαθα όταν η πρώτη μου εκτέλεση βγήκε «καθαρή» χωρίς να έχει ελέγξει τίποτα.
Άρα η συνταγή δοκιμής, με τη σειρά που δουλεύει: εγκαθιστάς με npm i -D lefthook@2.2.2, γράφεις το lefthook.yml, τρέχεις npx lefthook install, κάνεις git add το αρχείο σου, και μετά τρέχεις npx lefthook run pre-commit. Αν παραλείψεις το git add, παίρνεις πράσινο φως για δουλειά που δεν έγινε.
Τι δεν έτρεξα, και το λέω. Δεν έστησα συνεδρία μέσα σε Claude Code, Codex ή Cursor — δεν έχουμε όλα αυτά στο μηχάνημά μας, και δεν θα σου δώσω βήματα που δεν είδα. Δεν μέτρησα κορύφωση μνήμης: η διεργασία ζει περίπου 100 χιλιοστά του δευτερολέπτου, και ένα νούμερο μνήμης από τόσο σύντομη ζωή θα ήταν επινόηση. Τα νούμερα του αποθετηρίου — 8.953 αστέρια, 329 forks, 105 ανοιχτά issues, άδεια MIT, τελευταίο push 26 Οκτωβρίου 2026 — και τα νούμερα του npm — 21.072.106 λήψεις από 26 Σεπτεμβρίου έως 25 Οκτωβρίου 2026, τελευταία έκδοση 2.2.2 δημοσιευμένη 13 Οκτωβρίου 2026 — είναι από την έρευνά μας, όπως τα δίνουν το GitHub και το npm.
Τι κοστίζει
Το μοντέλο. Δικό μας νούμερο: μηδέν tokens. Το lefthook δεν είναι διακομιστής MCP, δεν φορτώνει σχήμα εργαλείων, δεν πιάνει χώρο σε καμία συνεδρία. Δεν πληρώνεις τίποτα στο πλαίσιο του βοηθού, ούτε όταν το χρησιμοποιείς ούτε όταν δεν το χρησιμοποιείς.
Το μηχάνημα. Δικό μας νούμερο: 14 MB στον δίσκο, σε ένα αρχείο — node_modules/lefthook-windows-x64/bin/lefthook.exe, 14.252.032 bytes. Καμία διεργασία που μένει ανοιχτή μετά την εκτέλεση. Μνήμη δεν μέτρησα, για τον λόγο που εξήγησα.
Σε χρήμα, μηδέν. Άδεια MIT, χωρίς κλειδί, χωρίς υπηρεσία, χωρίς λογαριασμό. Δεν υπάρχει πληρωμένο επίπεδο, δεν υπάρχει τηλεμετρία που να ξέρουμε.
Ισχυρισμός κατασκευαστή, όχι δικό μας νούμερο: η υποστήριξη πλατφορμών (macOS, Linux, Windows) και το σύνολο των δυνατοτήτων του YAML. Αυτά τα διαβάζουμε στην τεκμηρίωση, δεν τα δοκιμάσαμε ένα προς ένα.
Ετυμηγορία
Score: 8.3/10.
Το lefthook λύνει ένα πρόβλημα που το ξέρεις αλλά δεν το λες: ανεβάζεις κώδικα που δεν έχεις ελέγξει. Το λύνει αυτόματα, παράλληλα, με ένα στατικό δυαδικό που δεν κουβαλά εξαρτήσεις. Στη δοκιμή μας: exit 0 σε καθαρό αρχείο, exit 1 με ένα TODO, 0,09 δευτερόλεπτα, 14 MB στον δίσκο, μηδέν tokens στο μοντέλο, μηδέν ευρώ.
Τους υπόλοιπους βαθμούς τους κρατά ή τους χάνει για τρεις λόγους. Η καινοτομία είναι μέτρια — αντικαθιστά το husky, δεν ανοίγει δρόμο, και η αξία του είναι η εκτέλεση και η συντήρηση, όχι η ιδέα. Η παγίδα της σιωπής υπάρχει: χωρίς git add, το hook παραλείπεται και βγαίνει με exit 0. Και θέλει YAML, που για κάποιους είναι εμπόδιο.
Πού το προτείνουμε χωρίς δισταγμό: όταν το project θα ζήσει καιρό και θέλεις οι κανόνες να ζουν σε ένα αρχείο κειμένου, ίδιο για το μηχάνημά σου και για το CI. Εκεί το lefthook είναι η σωστή επιλογή, ακριβώς επειδή δεν σε απασχολεί.
Πηγές: αποθετήριο https://github.com/evilmartians/lefthook · πακέτο npm https://www.npmjs.com/package/lefthook · τεκμηρίωση https://lefthook.dev/ · εκδόσεις https://github.com/evilmartians/lefthook/releases
lefthook: the checks you forget become automatic, and they run in parallel
What it does
You have caught yourself pushing code you never checked. You did not do it out of carelessness. You were tired, or in a hurry, or you simply forgot. lefthook exists so that does not happen.
Two words first, because without them the rest makes no sense. “Git hooks” are points where git pauses and gives you the chance to run something of your own before it moves on. The best known is pre-commit: it runs right before the commit is sealed. commit-msg runs when you write the commit message. pre-push runs just before you send to the remote. If one of those checks fails, the action is blocked.
lefthook takes over running all of them for you. It is a Go binary — an executable that needs no language or library installed behind it to work. It reads its configuration from a file of its own, lefthook.yml, where you write which checks run at which point. And the key part: it runs them in parallel, not one after the other.
That last point is the whole value. Picture five checks that each take two seconds. Serially, ten seconds. In parallel, near two. In practice the checks are the same ones you would run by hand — it is just that you never remember them, and you never wait for them.
The project is maintained by Evil Martians, the studio behind other well-known tools in the ecosystem. The repository has been alive since February 2019 and today holds 8,953 stars, 329 forks and 105 open issues, under the MIT licence, with the last activity on 26 October 2026 (repository).
One clarification you need from the start: lefthook is not an MCP server. It does not speak to the model, it loads no tool schema, it takes up no room in your session. It is a shell tool, and it runs when git runs.
Who it is for
For anyone working in a team, or alone across many projects, who wants to stop shipping code that breaks other people’s code. The beginner who just heard the word “agent” will grasp the benefit the first time they forget to run the tests: the tool runs them anyway, and the commit does not close if something fails. The professional gains something sharper: no more carrying the project’s rules in their head, because they write them once in the YAML and never think about them again.
It shines when a project has many checks — formatting, static analysis, tests — and the wait on every commit has started to annoy you. It shines in a project that will live a while, because the only thing you pass on to the next person is a text file.
It is not for you if you are working alone on a throwaway script you will never open again. There the setup cost does not pay back. And it is not for you if you want something that inspects code inside the conversation with the assistant; that is a different class of tool, and lefthook does not touch it.
Install
You want Node, only so it can fetch the binary; from then on the execution needs neither Node nor Python. The package’s engines field is empty (null) — it requires no version at all. npm here is the carrier, not the engine.
Run this from the root of your project:
npm i -D lefthook@2.2.2Then write lefthook.yml at the root, with one hook you want. And then tell lefthook to install the hook itself into git:
npx lefthook installThat writes the hook into .git/hooks/pre-commit — the point git reads on its own. From here you call nothing by hand: git calls lefthook every time you commit.
One Windows trap we hit. npm gives you two files: a .cmd shim, and the real .exe under the lefthook-windows-x64 folder. If you call the shim from a bash shell, you get “No such file or directory” — it is not a lefthook fault, it is the shim that does not run that way. Through npx the problem does not appear.
The vendor documents other install routes — Homebrew, go install, a direct binary from the releases. That is a vendor claim: we only ran the npm route, and I will not describe steps I did not execute.
Using it per LLM
Care is needed here, because lefthook does not look like the tools we usually cover. It is not an MCP server. You do not write it an mcpServers entry, you do not declare an executable and arguments, you do not restart so the assistant can see it. You do not need to declare it at all.
The reason is simple and worth understanding. lefthook sits on top of the git hooks. The hooks run when git runs — which means also when the assistant commits. The agent does not need to know lefthook exists; git calls it on its own. The only thing you add per assistant is an instruction, so it does not break the hook with a bypass such as --no-verify. I stood up no session inside Claude Code, Codex or Cursor; the commands are shell commands, and I say where I know them from.
Claude Code
You write the project convention into CLAUDE.md: before every commit the hook runs, with no bypass. And if you want to test it yourself, you run this from the project root:
npx lefthook run pre-commitCodex CLI
The same, in an instructions file AGENTS.md at the root. There is no settings section to add — just the convention and the same command:
npx lefthook run pre-commitCursor
Here too the same shape: one instruction in the project rules, no server declaration. To check by hand:
npx lefthook run pre-commitIn CI
This is where the great virtue of the YAML shows: the same file works in CI too, with no second configuration. You add a step that runs the same command before the build:
npx lefthook run pre-commitThat way the rules do not live on each person’s machine; they live in one file that goes through review like the rest of the code. The same configuration for local hooks and for CI is, in our view, the most underrated advantage of the tool.
Where it wins, where it loses
It wins on the core point: the checks you forget become automatic. In our test, a hook banning the word TODO blocked the commit with exit 1 when it found it, and passed with exit 0 when the file was clean.
It wins on speed. The run took 0.09 seconds for one hook — and because they run in parallel, the gap grows as you add checks. It wins on cleanliness: one static binary, zero runtime dependencies, no process left hanging. And it wins because the configuration is a text file that a human reads and CI executes the same way.
Now where it loses.
First, the innovation is modest, and we want to say so plainly. lefthook opens no new road. It replaces husky — the JavaScript-world tool doing the same job. It brings no new idea; it brings better execution. Parallel instead of serial, one static binary instead of Node, zero dependencies instead of a package tree. That is not a flaw — it is exactly why it is a good choice for a project that will live in six months’ time. But do not expect a revolution; expect something that works and stops bothering you.
Second, the trap of silence. When you run the hook with nothing staged, it is skipped with a message and exits with exit 0. So a broken hook can look like it passed, if you test it blind. We unpack that in the next section, because we found it ourselves and it is the most useful thing in this article.
Third, it wants YAML. Anyone who has never written YAML will make one indentation mistake. It is a small hurdle, but it is there.
Testing
Everything below we ran on Windows 11, on a Dell Inspiron 3576, with Node 26.7.0, no graphics card.
I set up a fresh git repository and wrote lefthook.yml with one hook banning the word TODO inside app.js. The first thing I ran was installing the hook:
npx lefthook installIt wrote the hook into .git/hooks/pre-commit, as expected.
Then I put a clean app.js in place, staged it and ran the check. It returned exit 0 and printed “done in 0.09 seconds”. Then I put a TODO inside, staged it, and ran again. It returned exit 1 — the commit is blocked. The promise holds: the check runs, judges, and stops the mistake.
And then the trap, which I discovered myself and which deserves a paragraph.
The first time I ran npx lefthook run pre-commit before doing git add, with an empty staging area. The hook was skipped. It printed no-todo (skip) no matching staged files and exited with exit 0. Had I not noticed, I would have recorded “it passed” — while in reality nothing had run at all. This is the silent failure that can burn you: a broken hook looks healthy if you test it without staging files. I learned it when my first run came back “clean” without having checked anything.
So the test recipe, in the order that works: install with npm i -D lefthook@2.2.2, write lefthook.yml, run npx lefthook install, git add your file, and then run npx lefthook run pre-commit. Skip the git add and you get a green light for work that never happened.
What I did not run, and I say so. I stood up no session inside Claude Code, Codex or Cursor — we do not have all of those on our machine, and I will not hand you steps I did not see. I did not measure peak memory: the process lives about 100 milliseconds, and a memory figure from such a short life would be invention. The repository figures — 8,953 stars, 329 forks, 105 open issues, MIT licence, last push 26 October 2026 — and the npm figures — 21,072,106 downloads from 26 September to 25 October 2026, latest version 2.2.2 published on 13 October 2026 — come from our research, as GitHub and npm report them.
What it costs
The model. Our own figure: zero tokens. lefthook is not an MCP server, it loads no tool schema, it takes no room in any session. You pay nothing in the assistant’s context, whether you use it or not.
The machine. Our own figure: 14 MB on disk, in one file — node_modules/lefthook-windows-x64/bin/lefthook.exe, 14,252,032 bytes. No process left running after execution. I did not measure memory, for the reason I gave.
In money, nothing. MIT licence, no key, no service, no account. There is no paid tier, and there is no telemetry we know of.
Vendor claim, not our own figure: platform support (macOS, Linux, Windows) and the full set of YAML features. We read those in the documentation; we did not test them one by one.
Verdict
Score: 8.3/10.
lefthook solves a problem you know but do not name: you push code you have not checked. It solves it automatically, in parallel, with one static binary that carries no dependencies. On our test: exit 0 on a clean file, exit 1 with one TODO, 0.09 seconds, 14 MB on disk, zero tokens in the model, zero money.
It keeps or loses the remaining points for three reasons. The innovation is modest — it replaces husky, opens no road, and its value is execution and maintenance, not the idea. The trap of silence is real: with no git add, the hook is skipped and exits with exit 0. And it wants YAML, which for some is a hurdle.
Where we recommend it without hesitation: when a project will live a while and you want the rules to live in one text file, the same for your machine and for CI. There lefthook is the right choice, precisely because it stops bothering you.
Sources: repository https://github.com/evilmartians/lefthook · npm package https://www.npmjs.com/package/lefthook · documentation https://lefthook.dev/ · releases https://github.com/evilmartians/lefthook/releases