Ιστολόγιο

Hooks στο Claude Code 2026: ρύθμιση βήμα προς βήμα και 7 παραδείγματα έτοιμα για χρήση

Markdown

7 hooks έτοιμα για χρήση στο .claude/settings.json, έτοιμα για αντιγραφή και επικόλληση: προστασία .env, prettier, force-push στο main, μεγάλες παύλες και διακομιστής ανάπτυξης. 4 τύποι χειριστών και 31 συμβάντα.

Διαβάστε ολόκληρο το άρθρο

Τα hooks στο Claude Code είναι εντολές κελύφους, κλήσεις HTTP ή σύντομοι έλεγχοι LLM που εκτελούνται αυτόματα πριν ή μετά από μια ενέργεια του Claude. Προσθέτουν ελέγχους σε συγκεκριμένα συμβάντα εργαλείων, μορφοποιούν κώδικα μετά από επεξεργασία και εισάγουν νέο context στην εκκίνηση συνεδρίας. Αντίστοιχο PreToolUse hook μπορεί να απορρίψει εκείνη την κλήση· αυτά τα regex παραδείγματα είναι βοηθητικές δικλείδες, όχι όριο ασφάλειας σε κάθε διαδρομή πρόσβασης αρχείων ή Git. Ακολουθεί ανάλυση των 4 τύπων χειριστών, των 31 συμβάντων κύκλου ζωής, ενός ελέγχου για το «πότε ένας κανόνας ανήκει σε hook», 7 hooks έτοιμων για αντιγραφή στο .claude/settings.json και 3 παγίδων που έχω αντιμετωπίσει ο ίδιος.

Τεκμηρίωση Ailoot: API, κλειδιά και ρύθμιση.

Τι είναι τα hooks στο Claude Code;

Κύριο συμπέρασμα

Ένα hook είναι μια εντολή κελύφους, κλήση HTTP, σύντομη προτροπή LLM ή subagent που εκτελεί το Claude Code ως απόκριση σε ένα συγκεκριμένο συμβάν κύκλου ζωής. Σε αντίθεση με τις οδηγίες στο CLAUDE.md, τις οποίες το μοντέλο μπορεί να αγνοήσει ή να ξεχάσει, ένα hook εκτελείται κάθε φορά με τον ίδιο τρόπο: είναι κώδικας, όχι πρόταση.

Για μισό χρόνο, είχα τον κανόνα «μην επεξεργάζεσαι ποτέ απευθείας το .env» στο CLAUDE.md. Το Claude τον παραβίαζε μία φορά τον μήνα. Όχι από κακή πρόθεση· απλώς τον ξεχνούσε προς το τέλος μιας μεγάλης συνεδρίας. Μία φορά, κατέληξε ένα επιπλέον token στο .env· άλλη φορά, μια μεταβλητή με διπλό όνομα αντικατέστησε εκείνη που χρησιμοποιούνταν.

Μετέφερα αυτόν τον κανόνα σε ένα hook, ώστε να είναι αδύνατο να ξεχαστεί. Όταν αντίστοιχο εργαλείο άμεσης επεξεργασίας παρέχει διαδρομή .env, το διαμορφωμένο hook απορρίπτει εκείνη την κλήση. Ανακατεύθυνση Bash, scripts, εργαλεία MCP και άλλες διαδρομές πρόσβασης απαιτούν χωριστούς ελέγχους· το παράδειγμα δεν κάνει αμετάβλητο το αρχείο.

Τα hooks είναι εντολές κελύφους, τελικά σημεία HTTP ή προτροπές LLM που ορίζετε και εκτελούνται αυτόματα σε συγκεκριμένα σημεία του κύκλου ζωής του Claude Code.

— Anthropic, https://code.claude.com/docs/en/hooks

Με άλλα λόγια, ένα hook είναι μια εντολή σας που εκτελεί το Claude Code σε ένα συγκεκριμένο συμβάν. Κάθε επεξεργασία αρχείου, εκκίνηση Bash, έναρξη συνεδρίας ή ολοκλήρωση subagent είναι ένα συμβάν στο οποίο μπορείτε να προσαρτήσετε ένα hook.

Γιατί έχει σημασία αυτό για έναν vibe coder:

  • Προστατέψτε αρχεία που περιέχουν μυστικά από τυχαίες επεξεργασίες.
  • Εκτελείτε αυτόματα prettier/eslint μετά από κάθε παραγωγή κώδικα.
  • Αποκλείστε το git push --force στο main χωρίς ρητή άδεια.
  • Εισάγετε νέο πλαίσιο στην αρχή κάθε συνεδρίας.
  • Καταγράφετε τις ενέργειες του Claude για έλεγχο.

Το CLAUDE.md διαχειρίζεται το πλαίσιο. Τα hooks διαχειρίζονται τις ενέργειες. Πρόκειται για δύο διαφορετικά πράγματα και η σύγχυσή τους είναι το βασικό λάθος των αρχαρίων.

Σε τι διαφέρουν τα hooks από το CLAUDE.md και τις δεξιότητες;

Κύριο συμπέρασμα

Το CLAUDE.md είναι κείμενο που το μοντέλο διαβάζει στην αρχή μιας συνεδρίας και προσπαθεί να ακολουθήσει. Ένα hook είναι μια εντολή κελύφους που εκτελεί η διεργασία του Claude Code ως απόκριση σε ένα συμβάν, ανεξάρτητα από το μοντέλο. Μια δεξιότητα είναι ένα ονομασμένο πακέτο οδηγιών που μπορεί να καλέσει το Claude με το εργαλείο Skill, σαν συνάρτηση. Και τα τρία εξυπηρετούν διαφορετικά είδη εργασιών.

Η τεκμηρίωση της Anthropic εξηγεί ρητά τη διαφορά ανάμεσα στο CLAUDE.md και στα hooks:

Το περιεχόμενο του CLAUDE.md παραδίδεται ως μήνυμα χρήστη μετά το system prompt και όχι ως μέρος του system prompt. Το Claude το διαβάζει και προσπαθεί να το ακολουθήσει, αλλά δεν υπάρχει εγγύηση αυστηρής συμμόρφωσης.

— Anthropic, τεκμηρίωση μνήμης, https://code.claude.com/docs/en/memory

Με άλλα λόγια: το περιεχόμενο του CLAUDE.md φτάνει στο Claude ως το πρώτο μήνυμα του χρήστη και όχι ως οδηγία συστήματος. Το μοντέλο θα το διαβάσει και θα προσπαθήσει να το ακολουθήσει. Αλλά δεν υπάρχουν εγγυήσεις, ειδικά προς το τέλος μιας μεγάλης συνεδρίας, όταν το πλαίσιο μεγαλώνει και οι παλαιότερες οδηγίες εκτοπίζονται.

Ένα hook λειτουργεί διαφορετικά. Βρίσκεται στο settings.json, δεν εξαρτάται από το μοντέλο και εκτελείται από τη διεργασία του Claude Code σε συγκεκριμένο συμβάν: PreToolUse, PostToolUse, SessionStart και άλλα. Η εντολή εκτελείται πριν το Claude λάβει το αποτέλεσμα και μπορεί να αποκλείσει φυσικά μια ενέργεια (exit 2) ή να τροποποιήσει ένα αρχείο μετά την επεξεργασία (exit 0).

Σύγκριση:

ΧαρακτηριστικόCLAUDE.mdHookΔεξιότητα
Πού βρίσκεταιCLAUDE.md στη ρίζα του έργου.claude/settings.jsonΦάκελος .claude/skills/
Ποιος το εκτελείΤο μοντέλο το διαβάζει ως μέρος μηνύματος χρήστηΗ διεργασία του Claude Code σε ένα συμβάνΤο μοντέλο μέσω του εργαλείου Skill
Εγγύηση εκτέλεσηςΌχι (βέλτιστη προσπάθεια)Διαμορφωμένο αντίστοιχο command hook εκτελεί κώδικα· αποτυχίες και έξοδος εξαρτώνται από συμβάνΜέσω κλήσης μοντέλου (με δικαίωμα, αλλά όχι σε επίπεδο κελύφους)
Σε τι χρησιμεύειΠλαίσιο έργου, τόνος, ύφος, δρομολόγησηΠεριορισμοί, μορφοποίηση, έλεγχοι σε συγκεκριμένα αρχείαΣύνθετες διαδικασίες πολλών βημάτων με παραμέτρους
Πότε εκτελείταιΣε κάθε μήνυμα μοντέλου μιας συνεδρίαςΣε συμβάν κύκλου ζωήςΌταν το καλεί το μοντέλο
Μπορεί να αποκλείσει μια ενέργεια;ΌχιΝαι (exit 2)Όχι

Το πλήρες πρότυπο CLAUDE.md και οι 6 κανόνες για ένα ζωντανό αρχείο βρίσκονται στον οδηγό Πώς να ρυθμίσετε το CLAUDE.md το 2026: έτοιμο πρότυπο και 6 κανόνες. Μάθετε για τις δεξιότητες ως ονομασμένες δυνατότητες στο Claude Code Skills: Πώς να δημιουργήσετε τη δική σας βιβλιοθήκη.

Ένα hook είναι το χαμηλότερο επίπεδο: χωρίς μοντέλο, χωρίς ερμηνεία, μόνο κέλυφος.

Τα hooks είναι ένα από τα εργαλεία μηχανικής πλαισίου, μαζί με το Plan Mode και το /compact.

4 τύποι hooks: Command, HTTP, Prompt, Agent — ποιον να επιλέξετε;

Κύριο συμπέρασμα

Το Claude Code διαθέτει 4 τύπους χειριστών. Το Command είναι ένα script κελύφους, ο πιο συνηθισμένος τύπος. Το HTTP στέλνει αίτημα POST στη διεύθυνσή σας, για ομάδες και διασυνδέσεις. Το Prompt κάνει μια σύντομη κλήση Haiku για σημασιολογικό έλεγχο. Το Agent δημιουργεί ένα subagent με πρόσβαση σε εργαλεία για εις βάθος επικύρωση. Οι αρχάριοι χρειάζονται Command και Prompt· καλύπτουν το 90% των εργασιών.

ΤύποςΤι κάνειΠότε να τον επιλέξετεΠολυπλοκότητα
CommandΕκτελεί μια εντολή κελύφους, λαμβάνει JSON στο stdin και αποκρίνεται με κωδικό εξόδου και stdout90% των περιπτώσεων: έλεγχος διαδρομών, μορφοποίηση, grep σε περιεχόμενο, lsof, λειτουργίες gitχαμηλή
HTTPΣτέλνει αίτημα POST στη διεύθυνσή σας με σώμα JSON και λαμβάνει JSON στην απόκρισηΌταν ένας κανόνας αφορά ομάδα/CI: κεντρική επικύρωση, κοινός πίνακας κατάστασης, απομακρυσμένος έλεγχοςμέτρια (απαιτεί διακομιστή)
PromptΣτέλνει μια σύντομη προτροπή στο Haiku (από προεπιλογή) και λαμβάνει ναι/όχι για μια σημασιολογική αξιολόγησηΌταν το grep δεν αρκεί: «αξιολόγησε αν αυτό το κείμενο ακούγεται εταιρικό»χαμηλή
AgentΔημιουργεί ένα subagent με πρόσβαση σε Read/Grep/Glob για ελέγχους πολλών βημάτωνΒαριά επικύρωση: «βρες όλα τα αρχεία που άλλαξαν και έλεγξε αν υπάρχουν αντίστοιχα tests»υψηλή

Το συνηθέστερο λάθος είναι να προσπαθεί κανείς να κάνει με Command κάτι που απαιτεί Prompt. Για παράδειγμα, το «μη χρησιμοποιείς μεγάλες παύλες σε αρχεία .md» είναι εργασία grep, επομένως το Command είναι ιδανικό. Αλλά το «μη γράφεις με εταιρικό ύφος» είναι σημασιολογικό και χρειάζεται Prompt.

Αν μόλις ξεκινάτε, χρησιμοποιήστε Command. Και τα 7 hooks έτοιμα για χρήση παρακάτω είναι Command. Τα HTTP/Prompt/Agent έρχονται αργότερα, όταν θα είστε έτοιμοι.

Πού βρίσκεται το settings.json και ποια είναι τα 4 επίπεδα ρύθμισης;

Κύριο συμπέρασμα

Το Claude Code αναζητά ρυθμίσεις σε 4 σημεία: εταιρικό (αναπτύσσεται μέσω MDM), χρήστη ( ~/.claude/settings.json), έργου (.claude/settings.json στη ρίζα του αποθετηρίου) και τοπικό (.claude/settings.local.json, δεν βρίσκεται στο git). Και τα 4 αρχεία συγχωνεύονται στην αρχή της συνεδρίας, με το χαμηλότερο επίπεδο να υπερισχύει.

ΕπίπεδοΔιαδρομήΠότε ισχύειΣτο git;
Εταιρικό/Library/Application Support/ClaudeCode/settings.json (Mac), /etc/claude-code/settings.json (Linux)Σε όλη την ομάδα μέσω MDMόχι
Χρήστη~/.claude/settings.jsonΣε όλα τα έργα ενός χρήστηόχι
Έργου.claude/settings.json στη ρίζα του αποθετηρίουΑυτό το έργο, για όλη την ομάδαναι
Τοπικό.claude/settings.local.jsonΜόνο αυτό το έργο, μόνο αυτός ο χρήστηςόχι (στο .gitignore)

Διατηρώ τα 7 hooks που περιγράφονται παρακάτω στο .claude/settings.json του έργου, ώστε να περιλαμβάνονται αυτόματα όταν κλωνοποιείται το αποθετήριο και το Claude να ακολουθεί τους ίδιους κανόνες σε ένα νέο παράθυρο. Τα προσωπικά πειραματικά hooks μπαίνουν στο .claude/settings.local.json, ώστε να μην επηρεάζουν την ομάδα.

Και τα 4 αρχεία συγχωνεύονται στην αρχή της συνεδρίας. Αν οι κανόνες συγκρούονται, υπερισχύει το χαμηλότερο επίπεδο (τοπικό έναντι έργου, έργο έναντι χρήστη).

Ο πιο γρήγορος τρόπος να δημιουργήσετε το πρώτο σας hook είναι το διαδραστικό μενού /hooks μέσα στο Claude Code. Επιλέξτε ένα συμβάν από τη λίστα, επιλέξτε έναν matcher (για παράδειγμα, Bash ή Edit) και επικολλήστε μια εντολή. Το Claude Code γράφει έγκυρο JSON στο settings.json για εσάς.

31 συμβάντα κύκλου ζωής: ποια χρειάζονται οι αρχάριοι;

Κύριο συμπέρασμα

Το Claude Code διαθέτει σήμερα 31 συμβάντα κύκλου ζωής, χωρισμένα σε 3 συχνότητες: μία φορά ανά συνεδρία (SessionStart/SessionEnd), μία φορά ανά σειρά (UserPromptSubmit/Stop) και σε κάθε κλήση εργαλείου (PreToolUse/PostToolUse). Οι αρχάριοι χρειάζονται 4 από τα 31 συμβάντα: PreToolUse για περιορισμούς, PostToolUse για αυτόματες επεξεργασίες, SessionStart για πλαίσιο και Stop για τελικούς ελέγχους.

Τα συμβάντα εμφανίζονται με τρεις συχνότητες: μία φορά ανά συνεδρία (SessionStart, SessionEnd), μία φορά ανά σειρά (UserPromptSubmit, Stop, StopFailure) και σε κάθε κλήση εργαλείου μέσα στον agentic βρόχο (PreToolUse, PostToolUse).

— Anthropic, αναφορά hooks, https://code.claude.com/docs/en/hooks

Είναι σημαντικό να κατανοήσετε τις τρεις συχνότητες για να μην μπερδευτείτε:

  1. Μία φορά ανά συνεδρία - SessionStart, SessionEnd, Setup. Αυτά εκτελούνται μία φορά όταν ανοίγει και κλείνει το Claude Code. Χρησιμοποιήστε τα για να αρχικοποιείτε το πλαίσιο και να καθαρίζετε προσωρινά αρχεία.
  2. Μία φορά ανά σειρά - UserPromptSubmit, UserPromptExpansion, Stop, StopFailure. Αυτά ενεργοποιούνται σε κάθε μήνυμά σας και κάθε φορά που σταματά το μοντέλο. Χρησιμοποιήστε τα για να καταγράφετε τη συνομιλία και να εκτελείτε τελικούς ελέγχους αποτελεσμάτων.
  3. Σε κάθε κλήση εργαλείου - PreToolUse, PostToolUse, PostToolUseFailure, PermissionRequest, PermissionDenied, PostToolBatch, SubagentStart, SubagentStop. Αυτά ενεργοποιούνται σε κάθε επεξεργασία αρχείου, εκκίνηση Bash, ανάγνωση ή αναζήτηση. Αυτό είναι το πιο θερμό επίπεδο, όπου βρίσκονται οι περιορισμοί, η μορφοποίηση και οι επικυρώσεις.

Η πλήρης λίστα των 31 συμβάντων περιλαμβάνει ασύγχρονα/αντιδραστικά συμβάντα: TeammateIdle, PreCompact, PostCompact, Elicitation, ElicitationResult, InstructionsLoaded, ConfigChange, CwdChanged, FileChanged, WorktreeCreate, WorktreeRemove, Notification. Αυτά αφορούν προχωρημένα σενάρια· παραλείψτε τα προς το παρόν.

Έλεγχος πέντε ερωτήσεων: πότε ανήκει ένας κανόνας σε hook και πότε παραμένει στο CLAUDE.md;

Κύριο συμπέρασμα

Αν ένας κανόνας αφορά ενέργεια (όχι πλαίσιο), σχετίζεται με ασφάλεια/χρήματα/δεδομένα, μπορεί να ελεγχθεί με grep/regex, είναι δύσκολο να αναιρεθεί αν παραβιαστεί και το Claude τον έχει ήδη παραβιάσει τουλάχιστον μία φορά, τότε ανήκει σε hook. Αν λιγότερες από τρεις από αυτές τις πέντε απαντήσεις είναι «ναι», παραμένει στο CLAUDE.md. Εφάρμοσα τον έλεγχο στις 80 γραμμές μου και 5 κανόνες μεταφέρθηκαν σε hooks.

Για μένα, αυτό λειτουργεί σαν νόμος και όχι σαν πρόταση. Συνόψισα την επιλογή ανάμεσα στο CLAUDE.md και σε ένα hook σε έναν απλό έλεγχο πέντε ερωτήσεων. Αν τουλάχιστον τρεις απαντήσεις είναι «ναι», ο κανόνας περνά σε hook. Αν είναι λιγότερες από τρεις, παραμένει στο κείμενο.

Ο έλεγχος «πότε ανήκει ένας κανόνας σε hook;»:

  1. Αφορά αυτός ο κανόνας μια ενέργεια και όχι το πλαίσιο; («μην εκτελείς rm -rf» είναι ενέργεια· «έχω έργο TypeScript» είναι πλαίσιο.)
  2. Αφορά αυτός ο κανόνας την ασφάλεια, τα χρήματα ή τα δεδομένα; («μην αγγίζεις το .env», «μη δημοσιεύεις κλειδιά».)
  3. Μπορείτε να τον ελέγξετε με grep, regex ή τον κωδικό εξόδου μιας εντολής κελύφους; («μετά την επεξεργασία του .md, έλεγξε ότι δεν υπάρχει μεγάλη παύλα».)
  4. Αν παραβιαστεί ο κανόνας, θα ήταν οδυνηρό να αναιρεθούν οι συνέπειες; («force push στο main» αναιρείται δύσκολα· «ξεχάστηκε μια τελεία στο τέλος» εύκολα.)
  5. Έχετε δει ήδη το Claude να ξεχνά αυτόν τον κανόνα τουλάχιστον μία φορά;

Παράδειγμα: «Μη χρησιμοποιείς μεγάλες παύλες· χρησιμοποίησε μόνο ενωτικά.» Ενέργεια; Ναι. Ασφάλεια; Όχι. Ελέγχεται με grep; Ναι. Δύσκολο να αναιρεθεί; Όχι. Το έχετε δει να παραβιάζεται; Ναι. 3 στα 5: βάλτε το σε hook.

Αντιπαράδειγμα: «Έχω vibe coders, όχι developers· γράφε χωρίς αργκό.» Ενέργεια; Περισσότερο πλαίσιο. Ασφάλεια; Όχι. Ελέγχεται με regex; Πολύ δύσκολα. Δύσκολο να αναιρεθεί; Όχι. Το έχετε δει να παραβιάζεται; Ναι. 1 στα 5: κρατήστε το στο CLAUDE.md.

Πέντε από τους κανόνες μου πέρασαν τον έλεγχο. Μεταφέρθηκαν σε hooks. Το υπόλοιπο 75% παρέμεινε στο αρχείο κειμένου.

7 hooks έτοιμα για αντιγραφή

Κύριο συμπέρασμα

Παρακάτω βρίσκονται 7 hooks έτοιμα για χρήση στο .claude/settings.json: αποκλεισμός επεξεργασιών του .env, αυτόματη εκτέλεση prettier, αποτροπή force-push στο main, έλεγχος για μεγάλες παύλες, απελευθέρωση θύρας πριν από το npm run dev, αυτόματο commit μετά από επιτυχημένα tests και εισαγωγή νέου πλαισίου στην αρχή μιας συνεδρίας. Αντιγράψτε το καθένα στο αρχείο, επανεκκινήστε το Claude Code και λειτουργεί.

Και τα 7 hooks είναι αποθηκευμένα σε ένα αρχείο .claude/settings.json στη ρίζα του έργου. Κάθε καταχώριση έχει έναν τύπο συμβάντος, ένα φίλτρο εργαλείου (matcher) και μια εντολή κελύφους. Ο κωδικός εξόδου 2 απορρίπτει αντίστοιχη κλήση PreToolUse πριν την εκτέλεση. Στο PostToolUse η ενέργεια έχει ήδη συμβεί: το hook αναφέρει ανατροφοδότηση και δεν την αναιρεί.

Για τα περισσότερα συμβάντα hook, μόνο ο κωδικός εξόδου 2 αποκλείει μια ενέργεια. Το Claude Code αντιμετωπίζει τον κωδικό εξόδου 1 ως σφάλμα που δεν αποκλείει και συνεχίζει την ενέργεια, παρόλο που συμβατικά το 1 σημαίνει αποτυχία στο Unix.

— Anthropic, αναφορά hooks, https://code.claude.com/docs/en/hooks

Το exit 0 σημαίνει επιτυχία. Το exit 1 σημαίνει σφάλμα, αλλά το Claude συνεχίζει (αυτό είναι το πρώτο αντιπαράδειγμα παρακάτω). Το exit 2 έχει συμπεριφορά ανά συμβάν: μπορεί να μπλοκάρει PreToolUse, ενώ στο PostToolUse αναφέρει μόνο ανατροφοδότηση για ενέργεια που έγινε ήδη.

Hook 1. Έλεγχος άμεσης επεξεργασίας .env (PreToolUse, exit 2)

Αποκλείει απόπειρες απευθείας επεξεργασίας οποιουδήποτε αρχείου που ταιριάζει με .env, .env.local, .env.production κ.ο.κ.

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Edit|Write|MultiEdit",
        "hooks": [
          {
            "type": "command",
            "command": "FILE=$(jq -r '.tool_input.file_path // empty'); [ -z \"$FILE\" ] && exit 0; echo \"$FILE\" | grep -qE '(^|/)\\.env(\\.|$)' && { echo 'Do not edit `.env` directly. Tell me which variable to add, and I’ll open the file myself.' >&2; exit 2; } || exit 0"
          }
        ]
      }
    ]
  }
}

Τι κάνει: Πριν από κάθε Edit/Write/MultiEdit, λαμβάνει τη διαδρομή αρχείου, ελέγχει με grep αν ταιριάζει με το μοτίβο .env και, αν ναι, επιστρέφει exit 2 με ένα μήνυμα. Το Claude βλέπει το stderr και μου λέει: «Προσπάθησα να επεξεργαστώ το .env, αλλά το hook με απέκλεισε· πες μου ποια μεταβλητή να προσθέσω».

Hook 2. Αυτόματη εκτέλεση prettier μετά από κάθε επεξεργασία κώδικα (PostToolUse, exit 0)

{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Edit|Write|MultiEdit",
        "hooks": [
          {
            "type": "command",
            "command": "FILE=$(jq -r '.tool_input.file_path // empty'); [ -z \"$FILE\" ] && exit 0; echo \"$FILE\" | grep -qE '\\.(ts|tsx|js|jsx|json)$' && npx prettier --write \"$FILE\" 2>/dev/null & exit 0"
          }
        ]
      }
    ]
  }
}

Τι κάνει: Μετά από κάθε Edit/Write, λαμβάνει τη διαδρομή και, αν η επέκταση είναι .ts/.tsx/.js/.jsx/.json, εκτελεί prettier στο παρασκήνιο με &. Πάντα επιστρέφει 0, επειδή πρόκειται για μορφοποίηση και όχι περιορισμό. Αν αποτύχει το prettier, δεν πειράζει· το αρχείο παραμένει όπως ήταν.

Η διαφορά με το hook 1 είναι θεμελιώδης: PreToolUse + exit 2 είναι σκληρός αποκλεισμός πριν από την ενέργεια. PostToolUse + exit 0 είναι ήπια επεξεργασία μετά την ενέργεια. Πρόκειται για δύο διαφορετικές λειτουργίες για διαφορετικές εργασίες.

Hook 3. Αποκλεισμός του git push --force στον κλάδο main (PreToolUse, exit 2)

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash",
        "hooks": [
          {
            "type": "command",
            "command": "CMD=$(jq -r '.tool_input.command // empty'); [ -z \"$CMD\" ] && exit 0; echo \"$CMD\" | grep -qE 'git[[:space:]]+push' && echo \"$CMD\" | grep -qE '(\\-\\-force|\\-\\-force-with-lease|[[:space:]]-f([[:space:]]|$))' && echo \"$CMD\" | grep -qE '([[:space:]/:])main([[:space:]/:]|$)' && { echo 'Force push to main is forbidden. Create a new branch or ask me to do it manually.' >&2; exit 2; } || exit 0"
          }
        ]
      }
    ]
  }
}

Τι κάνει: Σε κάθε εκκίνηση Bash, ελέγχει αν η εντολή περιλαμβάνει push, περιλαμβάνει --force/--force-with-lease/-f και αναφέρει main. Αν ταιριάζουν και οι τρεις συνθήκες, αποκλείει την ενέργεια με σαφές μήνυμα.

Παλαιότερα είχα αυτόν τον κανόνα στο CLAUDE.md με κεφαλαία. Το Claude εξακολουθούσε να τον παραβιάζει περίπου μία φορά κάθε δύο εβδομάδες όταν του ζητούσα να κάνει «force push για να αναιρέσει το κακό commit μου». Το hook εντοπίζει τις κυριολεκτικές μορφές εντολών που εμφανίζονται, αλλά aliases, scripts, έμμεσος κλάδος προορισμού ή άλλος client Git μπορούν να παρακάμψουν τον έλεγχο συμβολοσειράς. Επιβάλετε προστασία main στο remote και περιορίστε διαθέσιμα διαπιστευτήρια agent.

Hook 4. Αποκλεισμός των μεγάλων παυλών σε αρχεία κειμένου (PostToolUse, exit 2)

{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Edit|Write|MultiEdit",
        "hooks": [
          {
            "type": "command",
            "command": "FILE=$(jq -r '.tool_input.file_path // empty'); [ -z \"$FILE\" ] && exit 0; echo \"$FILE\" | grep -qE '\\.(md|mdx|tsx?)$' && grep -q $'\\xe2\\x80\\x94' \"$FILE\" && { echo \"File $FILE contains an em dash (U+2014). Replace it with a regular hyphen (U+002D).\" >&2; exit 2; } || exit 0"
          }
        ]
      }
    ]
  }
}

Τι κάνει: Το PostToolUse με exit 2 αναφέρει στο Claude αποτυχία ελέγχου μετά την αλλαγή. Δεν αναιρεί ούτε εμποδίζει την εγγραφή. Αν το Claude επεξεργαστεί ένα αρχείο και αφήσει μεγάλη παύλα, το hook αποτυγχάνει, το Claude λαμβάνει ενημέρωση και προσπαθεί ξανά. Μετά από 2–3 συνεδρίες, το Claude σταματά να εισάγει εντελώς αυτόν τον χαρακτήρα.

Σημειώστε ότι το grep αναζητά συγκεκριμένα τον χαρακτήρα της μεγάλης παύλας (U+2014) χρησιμοποιώντας $'\xe2\x80\x94', τη σημειογραφία του Bash για την απόδοσή του ως byte UTF-8. Αν γράψετε απλώς grep -q '-', θα εντοπίζει και τα κανονικά ενωτικά και θα εκτελείται σε κάθε αρχείο. Ένας αόρατος χαρακτήρας χαλάει όλη τη λογική.

Hook 5. Απελευθέρωση της θύρας 3000 πριν από το npm run dev (PreToolUse, exit 0)

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash",
        "hooks": [
          {
            "type": "command",
            "command": "CMD=$(jq -r '.tool_input.command // empty'); [ -z \"$CMD\" ] && exit 0; echo \"$CMD\" | grep -qE '(npm|pnpm|yarn)[[:space:]]+run[[:space:]]+dev' && { lsof -ti:3000 | xargs -r kill -9 2>/dev/null; echo 'Port 3000 freed before launch' >&2; }; exit 0"
          }
        ]
      }
    ]
  }
}

Τι κάνει: Πριν από κάθε npm run dev (ή pnpm/yarn), τερματίζει τη διεργασία στη θύρα 3000. Πάντα επιστρέφει 0, επειδή πρόκειται για προετοιμασία και όχι για περιορισμό. Έτσι προστατεύεστε από ένα είδος παγίδας: το Claude βλέπει «η θύρα χρησιμοποιείται», νομίζει ότι υπάρχει πρόβλημα στον κώδικα και αρχίζει να διορθώνει πράγματα, ενώ στην πραγματικότητα ο παλιός διακομιστής απλώς είχε μείνει ενεργός.

Hook 6. Αυτόματο commit μετά από επιτυχημένα tests (PostToolUse, exit 0)

{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Bash",
        "hooks": [
          {
            "type": "command",
            "command": "INPUT=$(cat); CMD=$(printf '%s' \"$INPUT\" | jq -r '.tool_input.command // empty') || exit 1; EXIT=$(printf '%s' \"$INPUT\" | jq -r '.tool_response.exit_code // empty') || exit 1; case \"$CMD\" in 'npm test'|'pnpm test'|'yarn test') ;; *) exit 0 ;; esac; [ \"$EXIT\" = \"0\" ] || exit 0; git diff --cached --quiet || { echo 'Existing staged changes: review manually' >&2; exit 0; }; git add -- src/orders.ts tests/orders.test.ts || exit 1; git diff --cached --quiet && exit 0; git commit -m 'tests: checkpoint after successful run'"
          }
        ]
      }
    ]
  }
}

Τι κάνει: Διαβάζει JSON stdin μία φορά και δέχεται μόνο τις ακριβείς απλές εντολές δοκιμών που εμφανίζονται. Συνεχίζει μόνο όταν το παρεχόμενο tool_response.exit_code είναι ρητά μηδέν· αν η εγκατεστημένη έκδοση δεν εκθέτει το πεδίο, παραλείπει commit αντί να μαντεύει επιτυχία. Αντικαταστήστε src/orders.ts και tests/orders.test.ts με τα ακριβή αρχεία της εργασίας. Υπάρχουσες staged αλλαγές σταματούν τη συνταγή ώστε να μη συμπεριληφθεί άσχετη δουλειά. Αποτυχημένο add τη σταματά, κενό diff δεν δημιουργεί commit και κανονικά commit hooks μένουν ενεργά. Δοκιμάστε επιτυχείς, αποτυχημένες και ελλιπείς εισόδους αποτελέσματος offline πριν ενεργοποιήσετε.

Αντιπαράδειγμα: προσθήκη git commit --no-verify σε κάθε Edit. Κρατήστε ενεργούς ελέγχους commit. Αν ένας έλεγχος ενεργοποιεί αναδρομικά αυτή την αυτοματοποίηση, περιορίστε το έναυσμα ή ανασχεδιάστε τον έλεγχο· μην παρακάμπτετε επαλήθευση από προεπιλογή. Εξετάστε staged diff και ιδιοκτησία αρχείων εργασίας πριν ενεργοποιήσετε αυτόματα commits.

Hook 7. Εισαγωγή νέου πλαισίου στην αρχή της συνεδρίας (SessionStart με additionalContext)

{
  "hooks": {
    "SessionStart": [
      {
        "matcher": "*",
        "hooks": [
          {
            "type": "command",
            "command": "BRANCH=$(git symbolic-ref --short HEAD 2>/dev/null || echo 'no-branch'); STATUS=$(git status --short 2>/dev/null | head -10); echo \"{\\\"additionalContext\\\":\\\"Current branch: $BRANCH. Uncommitted changes:\\n$STATUS\\\"}\""
          }
        ]
      }
    ]
  }
}

Τι κάνει: Στην αρχή της συνεδρίας, συλλέγει τον τρέχοντα κλάδο Git και τη λίστα των μη δεσμευμένων αλλαγών και επιστρέφει JSON με πεδίο additionalContext. Το Claude Code εισάγει αυτό το κείμενο στο πρώτο μήνυμα συστήματος, ώστε το Claude να γνωρίζει από την αρχή πού βρίσκεται και τι απομένει από την προηγούμενη συνεδρία.

Χρησιμοποιήστε το additionalContext για πληροφορίες που πρέπει να γνωρίζει το Claude σχετικά με την τρέχουσα κατάσταση του περιβάλλοντος ή μια μόλις ολοκληρωμένη ενέργεια: κατάσταση περιβάλλοντος (τρέχων κλάδος, στόχος ανάπτυξης, ενεργές σημαίες δυνατοτήτων), υπό όρους κανόνες έργου (ποια εντολή test ισχύει για το αρχείο που μόλις επεξεργάστηκε), εξωτερικά δεδομένα (ανοιχτά ζητήματα που σας έχουν ανατεθεί, πρόσφατα αποτελέσματα CI).

— Anthropic, αναφορά hooks, https://code.claude.com/docs/en/hooks

Επεκτάσεις αυτού του hook: λήψη του πιο πρόσφατου commit και της περιγραφής του, κατάσταση GitHub Actions, το ενεργό sprint από Linear/Jira και ανοιχτά ζητήματα για το τρέχον αποθετήριο.

3 παγίδες hooks που πιάνουν έναν στους δύο

Κύριο συμπέρασμα

Η πρώτη παγίδα: ένα hook με exit 1 περνά σιωπηλά και το Claude αγνοεί το σφάλμα. Η δεύτερη: η βαριά εργασία σε ένα hook τερματίζεται μετά από timeout 60 δευτερολέπτων. Η τρίτη: ένα hook βλέπει μόνο τις μεταβλητές περιβάλλοντος από το ~/.zshrc, όχι το .env του έργου. Κάθε μία διορθώνεται με μία γραμμή, αλλά χωρίς να γνωρίζετε αυτές τις παγίδες, μπορεί να νομίσετε ότι «τα hooks δεν λειτουργούν».

Παγίδα 1. Ένα hook με exit 1 περνά σιωπηλά

Η πιο επικίνδυνη. Για μία εβδομάδα νόμιζα ότι το hook προστασίας του .env λειτουργούσε, αλλά αποδείχθηκε ότι είχα jq -r '.tool_input.file_path' στο hook χωρίς έλεγχο για null. Όταν το tool_input ήταν κενό, το jq επέστρεφε κωδικό 1. Το Claude αντιμετώπισε το exit 1 ως «σφάλμα hook, συνέχεια», οπότε η ενέργεια εκτελέστηκε. Δεν καταλάβαινα γιατί εξακολουθούσε να πειράζεται το .env. Είδα την αιτία μόνο όταν εκτέλεσα χειροκίνητα το hook σε τερματικό με κενή είσοδο.

Η λύση είναι ένας κανόνας: ξεκινήστε κάθε hook ελέγχοντας για null και τελειώστε το με || exit 0. Κάθε μη αναμενόμενη έξοδος οδηγεί έτσι σε «ασφαλή» έξοδο αντί να περνά σιωπηλά.

# Safe start and end template:
FILE=$(jq -r '.tool_input.file_path // empty')
[ -z "$FILE" ] && exit 0
# ... your logic ...
exit 0   # or || exit 0 on one line

Παγίδα 2. Τα αργά hooks τερματίζονται λόγω timeout

Είχα ένα hook που εκτελούσε eslint --fix σε ολόκληρο το αρχείο μετά το Edit. Τα μεγάλα αρχεία (1000+ γραμμές) χρειάζονταν 8–10 δευτερόλεπτα για επεξεργασία. Το προεπιλεγμένο timeout hook του Claude Code είναι 60 δευτερόλεπτα, οπότε νόμιζα ότι ήμουν εντός ορίου. Όταν όμως γίνονται αρκετά Edit μέσα σε ένα λεπτό, τα hooks συσσωρεύονται και μπαίνουν σε ουρά, και μερικά απλώς παραλείπονται. Το κατάλαβα μόνο όταν το αρχείο καταγραφής έδειξε «hook timed out».

Λύση: αν ένα hook απαιτεί βαριά εργασία, εκτελέστε την στο παρασκήνιο. eslint --fix "$FILE" & χωρίς να περιμένετε το αποτέλεσμα. Τότε το hook επιστρέφει exit 0 σε χιλιοστά του δευτερολέπτου, ενώ η πραγματική εργασία εκτελείται στο παρασκήνιο.

# Heavy operation in background:
npx eslint --fix "$FILE" &
exit 0

Παγίδα 3. Ένα hook δεν μπορεί να δει τις μεταβλητές περιβάλλοντος του έργου

Νόμιζα ότι το process.env σε ένα hook θα ήταν διαθέσιμο όπως σε μια εφαρμογή Node.js. Δεν είναι. Το hook εκτελείται σε κέλυφος που ξεκινά η γονική διεργασία του Claude Code και βλέπει μόνο ό,τι υπάρχει στο ~/.zshrc ή στο ~/.bashrc, καθώς και ό,τι περνά ρητά το Claude Code. Αν το hook σας εξαρτάται από το OPENAI_API_KEY του .env, θα πρέπει να διαβάσετε χειροκίνητα το .env.

Λύση: διαβάστε ρητά το .env στην εντολή του hook.

# Passing project env into hook:
cd "$PWD" && source .env && curl -H "Authorization: Bearer $OPENAI_API_KEY" ...
# Or with dotenv:
dotenv -e .env -- node my-validator.js

Αυτό είναι ιδιαίτερα επώδυνο σε monorepo, όπου διαφορετικά πακέτα έχουν τα δικά τους αρχεία .env. Λύστε το περνώντας το PWD και εκτελώντας ρητά cd "$PWD" στην αρχή της εντολής.

Πώς δοκιμάζετε τα hooks πριν κάνετε commit;

Κύριο συμπέρασμα

Ένα hook είναι μια εντολή κελύφους. Μπορείτε να την εκτελέσετε χειροκίνητα σε τερματικό με ψεύτικο stdin, να ελέγξετε τον κωδικό εξόδου και το stderr, και να τα κάνετε όλα αυτά πριν την εκτελέσει το Claude Code. Έτσι εξοικονομείτε ώρες αποσφαλμάτωσης και προστατεύεστε από hooks που αποκλείουν τη δική τους λειτουργία.

Βασικό σενάριο δοκιμής. Πάρτε την εντολή hook από το JSON, ανοίξτε ένα τερματικό και τροφοδοτήστε την με το JSON που θα έστελνε το Claude Code:

# Test hook 1 (protect .env):
echo '{"tool_input":{"file_path":".env"}}' | bash -c '
FILE=$(jq -r ".tool_input.file_path // empty")
[ -z "$FILE" ] && exit 0
echo "$FILE" | grep -qE "(^|/)\.env(\.|$)" && {
  echo "BLOCKED" >&2
  exit 2
} || exit 0
'
echo "Exit code: $?"

Θα πρέπει να δείτε BLOCKED στο stderr και Exit code: 2. Αν λάβετε exit 0, το regex σας δεν λειτουργεί· διορθώστε το grep.

Σενάρια προς έλεγχο:

  1. Θετική διαδρομή - το αρχείο πρέπει να αποκλειστεί. .env για το hook 1, git push --force main για το hook 3.
  2. Αρνητική διαδρομή - το αρχείο δεν πρέπει να αποκλειστεί. README.md για το hook 1, git push origin feature-branch για το hook 3.
  3. Οριακές περιπτώσεις - κενή είσοδος, null τιμές, μη αναμενόμενοι χαρακτήρες. Το hook πρέπει είτε να επιστρέψει exit 0 είτε να αποτύχει με σαφές σφάλμα, όχι να περάσει σιωπηλά.

Πού να τοποθετείτε τα πειραματικά hooks. Όχι στο .claude/settings.json, αλλά στο .claude/settings.local.json (όχι στο git). Τοποθετήστε εκεί νέα hooks κάτω από το PostToolUse με echo αντί για την πραγματική ενέργεια, ελέγξτε αν ενεργοποιούνται και μετά μεταφέρετέ τα στο παραγωγικό settings.json.

// Experiment in settings.local.json - writes to /tmp/hook-debug.log:
{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Edit",
        "hooks": [
          {
            "type": "command",
            "command": "echo \"[hook fired] $(date) $(jq -r '.tool_input.file_path // \"?\"')\" >> /tmp/hook-debug.log"
          }
        ]
      }
    ]
  }
}

Μετά από 5–10 επεξεργασίες στο Claude Code, ανοίξτε το /tmp/hook-debug.log για να δείτε ποια αρχεία ενεργοποίησαν το hook. Αν είναι κενό, ο matcher δεν ταιριάζει· διορθώστε το regex.

Τι ακολουθεί;

Κύριο συμπέρασμα

Ξεκινήστε με hooks PostToolUse που επιστρέφουν exit 0· είναι τα ασφαλέστερα και δεν αποκλείουν τίποτα. Μετά από μία εβδομάδα, προσθέστε το πρώτο σας hook PreToolUse με exit 2 για να προστατεύσετε το .env ή να αποτρέψετε force-push. Μετά από δύο εβδομάδες, το CLAUDE.md θα μικρύνει από συμβόλαιο 200 γραμμών σε σύντομη περιγραφή πλαισίου 50–80 γραμμών, με επιλεγμένους ελέγχους συμβάντων σε hooks και αυστηρά όρια πρόσβασης επιβαλλόμενα χωριστά από δικαιώματα, sandbox και προστασίες remote.

5 βήματα για την επόμενη εβδομάδα:

  1. Κάντε grep στο CLAUDE.md σας για λέξεις όπως «ποτέ», «απαγορεύεται», «πάντα» και «πρέπει». Κάθε τέτοιος κανόνας είναι υποψήφιος για hook. Αν ένας κανόνας είναι προστακτικός, το αρχείο κειμένου δεν θα τον επιβάλει.
  2. Ξεκινήστε με PostToolUse + exit 0. Είναι τα ασφαλέστερα: κάνουν μια αλλαγή αλλά δεν αποκλείουν τίποτα. Prettier (hook 2), τερματισμός του διακομιστή ανάπτυξης (hook 5), αυτόματο commit μετά από tests (hook 6).
  3. Μόνο όταν βεβαιωθείτε, προσθέστε το πρώτο σας PreToolUse + exit 2. Για παράδειγμα, προστασία του .env (hook 1) ή αποτροπή force-push (hook 3). Πρόκειται για σκληρό αποκλεισμό και ένα λάθος στην εντολή grep μπορεί να αποκλείσει κι εσάς τους ίδιους.
  4. Δοκιμάστε τα hooks χειροκίνητα πριν κάνετε commit (δείτε την παραπάνω ενότητα). Εξοικονομεί ώρες αποσφαλμάτωσης.
  5. Κρατήστε το settings.local.json για πειράματα. Τοποθετήστε εκεί νέα hooks με echo αντί για την πραγματική ενέργεια.

Αφού ρυθμίσετε τα hooks, το επόμενο βήμα στο σύνολο οδηγών είναι πώς να αναιρείτε αλλαγές στο Claude Code, σε περίπτωση που ένα hook αφήσει να περάσει κάτι επικίνδυνο. Αν θέλετε το Claude να θυμάται τη δομή του έργου σας μεταξύ συνεδριών, δημιουργήστε έναν Δεύτερο Εγκέφαλο στο Claude Code (φάκελος business/ + συνδεδεμένη βάση γνώσεων). Και για να δώσετε ονόματα στις δεξιότητες του έργου σας ώστε να μπορείτε να τις επαναχρησιμοποιείτε, δείτε το Claude Code Skills.

Αν χρειάζεστε πρόσβαση σε νευρωνικά δίκτυα μέσω του Ailoot, ρίξτε μια ματιά στο Ailoot.

Περισσότερες λεπτομέρειες

Ερωτήσεις και απαντήσεις: Hooks στο Claude Code 2026: ρύθμιση βήμα προς βήμα και 7 παραδείγματα έτοιμα για χρήση

Γιατί ένα hook πρέπει να διαβάζει JSON εισόδου μόνο μία φορά;

Το stdin είναι ροή: η πρώτη διεργασία jq το καταναλώνει και οι επόμενες αναγνώσεις φτάνουν EOF. Αποθηκεύστε είσοδο μία φορά και εξαγάγετε εντολή και αποτέλεσμα από εκείνη την τιμή. Θεωρήστε απόν ή άγνωστο αποτέλεσμα ανεπαλήθευτο και παραλείψτε auto-commit.

Τα regex hooks των παραδειγμάτων δημιουργούν όριο ασφάλειας;

Όχι. Ελέγχουν συγκεκριμένα συμβάντα και αναγνωρίσιμες συμβολοσειρές εντολών. Ανακατεύθυνση shell, aliases, scripts, εργαλεία MCP ή άλλη διαδρομή εγγραφής μπορεί να τα παρακάμπτουν· χρησιμοποιήστε περιορισμένα διαπιστευτήρια, δικαιώματα συστήματος αρχείων, sandbox και προστατευμένους κλάδους για αυστηρά όρια.

Όλα τα άρθρα