Claude Code hookit: mikä on hook ja näin teet omat

Claude Code hookit ajavat komennon aina tietyssä kohdassa: muokkauksen jälkeen, ennen komentoa tai kun Claude odottaa sinua. Tapahtumat, matcherit ja valmiit esimerkit.

VVibekoodaus11 min

Kirjoitat CLAUDE.md-tiedostoon, että koodi ajetaan Prettierin läpi jokaisen muutoksen jälkeen. Claude muistaa sen useimmiten. Sitten tulee pitkä istunto, konteksti täyttyy ja yksi tiedosto jää muotoilematta. Kukaan ei huomaa ennen kuin CI valittaa.

Hook korjaa juuri tämän. Se on komento, jonka Claude Code ajaa itse tietyssä kohdassa, eikä Claude voi unohtaa sitä. Anthropicin dokumentaatio kutsuu tätä deterministiseksi hallinnaksi: tietyt asiat tapahtuvat aina, eivätkä ne jää kielimallin valinnan varaan.

Tässä oppaassa käydään läpi, mistä hook koostuu, mihin tiedostoon se kirjoitetaan ja mitkä tapahtumat kannattaa tuntea. Lopussa on neljä valmista esimerkkiä, jotka voit kopioida omaan projektiisi.


Mikä on Claude Code hook?

Hook on käyttäjän määrittelemä komento, joka käynnistyy, kun Claude Codessa tapahtuu jotain tiettyä. Tapahtuma voi olla vaikkapa se, että Claude on juuri muokkaamassa tiedostoa, se on saanut komennon ajettua tai se jää odottamaan lupaasi.

Yleensä hook on shell-komento tai skripti. Claude Code antaa sille tapahtuman tiedot JSON-muodossa, ja skripti päättää exit-koodilla tai omalla JSON-vastauksellaan, mitä seuraavaksi tapahtuu.

Hookilla voit siis:

  • muotoilla tiedoston heti, kun Claude on muokannut sitä
  • estää vaarallisen komennon ennen kuin se ajetaan
  • saada työpöytäilmoituksen, kun Claude tarvitsee sinua
  • lisätä Clauden kontekstiin tietoa istunnon alussa tai tiivistyksen jälkeen

Hookit eivät korvaa ohjeita. Harkintaa vaativat työtavat sopivat paremmin skilleihin, jotka ovat Clauden luettavia ohjeita. Hook on sääntö, joka pitää joka kerta.


Missä hookit määritellään

Hookit kirjoitetaan asetustiedoston hooks-osioon. Tiedoston paikka ratkaisee, mihin hook vaikuttaa:

TiedostoKoskeeJaettavissa
~/.claude/settings.jsonkaikkia omia projektejasiei, pysyy koneellasi
.claude/settings.jsonyhtä projektiakyllä, voi viedä versionhallintaan
.claude/settings.local.jsonyhtä projektiaei, Claude Code lisää sen gitignoreen tallentaessaan siihen asetuksen

Lisäksi hookeja voi tulla organisaation hallinnoiduista asetuksista, pluginin hooks/hooks.json-tiedostosta sekä skillin tai subagentin frontmatterista. Eri tasojen hookit eivät korvaa toisiaan, vaan ne lasketaan yhteen.

Kun olet lisännyt hookin, kirjoita Claude Codessa /hooks. Komento avaa näkymän, josta näet kaikki käytössä olevat hookit tapahtumittain. Jos muokkaat asetustiedostoa käsin kesken istunnon, Claude Code yleensä huomaa muutoksen itse. Jos ei huomaa, käynnistä istunto uudelleen.

Asetustiedostojen tasoista ja oikeuksista on oma oppaansa: Claude Code oikeudet ja asetukset.


Hookin rakenne: tapahtuma, matcher ja käsittelijä

Hook-asetuksessa on kolme sisäkkäistä tasoa. Ensin valitaan tapahtuma, jonka jälkeen tulee matcher-ryhmä, joka rajaa milloin hook laukeaa. Sisimpänä on yksi tai useampi käsittelijä, eli varsinainen ajettava komento.

{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Edit|Write",
        "hooks": [
          {
            "type": "command",
            "command": "jq -r '.tool_input.file_path' | xargs npx prettier --write"
          }
        ]
      }
    ]
  }
}

Tässä PostToolUse on tapahtuma, Edit|Write on matcher ja sisin olio on käsittelijä. Kaikki tapahtumat ovat saman hooks-olion avaimia. Jos tiedostossa on jo hooks-osio, lisää uusi tapahtuma sen rinnalle äläkä korvaa koko oliota.

Käsittelijän type on useimmiten command, joka ajaa shell-komennon. Muita tyyppejä ovat:

  • http, joka lähettää tapahtuman tiedot POST-pyyntönä osoitteeseen
  • mcp_tool, joka kutsuu MCP-palvelimen työkalua
  • prompt, joka pyytää Claude-mallia tekemään päätöksen yhdellä kutsulla
  • agent, joka käynnistää subagentin tarkistamaan asian työkaluilla (dokumentaation mukaan vielä kokeellinen)

Aloita command-tyypillä. Muut tyypit ovat hyödyllisiä, kun tarvitset harkintaa tai keskitettyä palvelinta.


Tärkeimmät tapahtumat

Tapahtumia on kymmeniä. Alkuun riittää kourallinen:

TapahtumaMilloin se laukeaa
SessionStartistunto alkaa tai jatkuu
UserPromptSubmitlähetät viestin, ennen kuin Claude käsittelee sen
PreToolUseennen työkalun käyttöä, voi estää sen
PermissionRequesttyökalun käyttö tarvitsee lupapäätöksen
PostToolUsetyökalun käyttö onnistui
NotificationClaude Code lähettää ilmoituksen
StopClaude on vastannut
PreCompactennen kontekstin tiivistystä
SessionEndistunto päättyy

Koko lista on hook-referenssissä. Huomaa, että Stop laukeaa aina kun Claude lopettaa vastauksen, ei vain silloin kun koko tehtävä on valmis.


Matcher: rajaa milloin hook laukeaa

Ilman matcheria hook laukeaa tapahtuman jokaisella kerralla. Matcherilla rajaat sen. Eri tapahtumat vertaavat matcheria eri asiaan:

  • PreToolUse ja PostToolUse vertaavat työkalun nimeen, esimerkiksi Bash, Edit|Write tai mcp__.*
  • SessionStart vertaa siihen, miten istunto alkoi: startup, resume, clear, compact tai fork
  • Notification vertaa ilmoituksen tyyppiin, esimerkiksi permission_prompt tai idle_prompt

Pystyviiva erottaa vaihtoehdot, joten Edit|Write osuu sekä muokkaukseen että uuden tiedoston kirjoittamiseen. Tyhjä merkkijono "" osuu kaikkeen. Matcherit erottavat isot ja pienet kirjaimet, joten bash ei osu Bash-työkaluun.

Jotkin tapahtumat, kuten UserPromptSubmit ja Stop, eivät tue matcheria lainkaan. Ne laukeavat aina.

Työkalutapahtumissa voi rajata vielä tarkemmin if-kentällä. Se käyttää samaa kirjoitustapaa kuin lupasäännöt, joten "if": "Bash(git *)" ajaa hookin vain git-komennoille eikä jokaiselle Bash-komennolle. Dokumentaation mukaan if on kuitenkin paras arvaus. Jos jokin on pakko estää aina, käytä lupasääntöjä.


Mitä hook saa ja miten se vastaa

Kun tapahtuma laukeaa, Claude Code syöttää hookille JSONin stdinin kautta. Bash-komennon kohdalla PreToolUse-hook saa esimerkiksi tällaisen:

{
  "session_id": "abc123",
  "cwd": "/Users/maija/verkkokauppa",
  "hook_event_name": "PreToolUse",
  "tool_name": "Bash",
  "tool_input": {
    "command": "npm test"
  }
}

Tiedostojen muokkauksessa polku on kentässä tool_input.file_path. Siksi esimerkeissä käytetään jq-työkalua, joka poimii kentän JSONista. Asenna se macOS:ssä komennolla brew install jq tai Debianissa ja Ubuntussa komennolla apt-get install jq.

Hook vastaa exit-koodilla:

  • Exit 0: ei huomautettavaa. PreToolUse-hookissa tämä ei hyväksy komentoa, vaan normaali lupakysely jatkuu tavalliseen tapaan.
  • Exit 2: estä. Kirjoita syy stderriin, niin Claude saa sen palautteena ja voi muuttaa toimintaansa.
  • Muu koodi: useimmissa tapahtumissa toiminto jatkuu, ja keskusteluun tulee ilmoitus hook-virheestä.

Jos tarvitset enemmän kuin kyllä tai ei, päätä skripti koodiin 0 ja tulosta JSON. PreToolUse-hook voi esimerkiksi kieltäytyä ja kertoa syyn:

{
  "hookSpecificOutput": {
    "hookEventName": "PreToolUse",
    "permissionDecision": "deny",
    "permissionDecisionReason": "Käytä pnpm:ää, ei npm:ää"
  }
}

Arvoja ovat deny, ask ja allow. Kun hook palauttaa allow, se ohittaa lupakyselyn, mutta asetusten kieltosäännöt pätevät silti. Valitse yhdelle hookille joko exit-koodi 2 tai JSON, älä molempia.


Useampi hook samassa tapahtumassa

Samaan tapahtumaan voi kytkeä monta hookia. Voit esimerkiksi kirjata jokaisen Bash-komennon lokiin ja samalla estää vaaralliset komennot:

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash",
        "hooks": [
          {
            "type": "command",
            "command": "jq -r .tool_input.command >> ~/.claude/bash.log"
          },
          {
            "type": "command",
            "command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/esta-vaaralliset.sh"
          }
        ]
      }
    ]
  }
}

Claude Code ajaa osuvat hookit rinnakkain ja odottaa, että jokainen on valmis, ennen kuin se yhdistää tulokset. PreToolUse-päätöksissä tiukin vastaus voittaa järjestyksessä deny, ask, allow.

Tästä seuraa yksi ansa. Kun yksi hook estää komennon, muut ajetaan silti loppuun. Yllä olevassa esimerkissä lokiin kirjautuu myös estetty komento, koska lokihook ehti jo tehdä työnsä. Älä siis rakenna mitään sen varaan, että yhden hookin kielto pysäyttäisi toisen hookin sivuvaikutukset.

Asetustiedostojen hookit toimivat myös subagenteissa. Kun subagentti käyttää työkalua, samat PreToolUse- ja PostToolUse-hookit laukeavat kuin pääkeskustelussa. Suojaus pätee siis, vaikka Claude jakaisi työn osiin.


Esimerkki 1: ilmoitus, kun Claude odottaa sinua

Pitkän tehtävän aikana terminaalin tuijottaminen on ajanhukkaa. Tämä hook näyttää macOS:ssä työpöytäilmoituksen aina, kun Claude tarvitsee sinua. Lisää se tiedostoon ~/.claude/settings.json, niin se toimii kaikissa projekteissa:

{
  "hooks": {
    "Notification": [
      {
        "matcher": "",
        "hooks": [
          {
            "type": "command",
            "command": "osascript -e 'display notification \"Claude Code odottaa sinua\" with title \"Claude Code\"'"
          }
        ]
      }
    ]
  }
}

Linuxissa komento on notify-send 'Claude Code' 'Claude Code odottaa sinua'. Jos notify-send puuttuu, Debianissa ja Ubuntussa se tulee paketissa libnotify-bin. Palvelimilla ja SSH-yhteyksien yli ilmoituksia ei yleensä näy, koska niistä puuttuu työpöydän ilmoituspalvelu.

macOS:ssä on yksi kompastuskivi. osascript lähettää ilmoitukset Script Editorin kautta, ja jos Script Editorilla ei ole ilmoituslupaa, mitään ei näy eikä macOS kysy lupaa. Aja terminaalissa kerran osascript -e 'display notification "testi"', avaa sitten Järjestelmäasetusten Ilmoitukset, etsi Script Editor ja salli ilmoitukset.

Jos haluat ilmoituksen vain lupakyselyistä, vaihda matcheriksi permission_prompt. Terminaalissa ilmoitus tulee silloin, kun lupakysely on odottanut noin kuusi sekuntia.


Esimerkki 2: formatteri jokaisen muokkauksen jälkeen

Tämä on se hook, jonka useimmat ottavat käyttöön ensimmäisenä. Se ajaa Prettierin jokaiselle tiedostolle, jota Claude muokkaa tai kirjoittaa. Lisää se projektin tiedostoon .claude/settings.json, jolloin koko tiimi saa saman muotoilun:

{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Edit|Write",
        "hooks": [
          {
            "type": "command",
            "command": "jq -r '.tool_input.file_path' | xargs npx prettier --write"
          }
        ]
      }
    ]
  }
}

jq poimii JSONista muokatun tiedoston polun, ja xargs antaa sen Prettierille. Onnistunut hook ei näy keskustelussa mitenkään, joten testaa se pyytämällä Claudea lisäämään JavaScript-tiedostoon rivi, jossa on yksinkertaiset lainausmerkit. Prettierin oletusasetuksilla ne muuttuvat kaksinkertaisiksi.

Yksi rajoitus kannattaa tietää. Edit|Write ei osu tiedostoihin, joita Claude muuttaa Bash-komennoilla, esimerkiksi sedillä. Jos sinun on pakko nähdä jokainen muutos, dokumentaatio neuvoo lisäämään Stop-hookin, joka käy työpuun läpi kerran vuoron lopussa.

Pythonissa sama toimii esimerkiksi Ruffilla. Vaihda vain komento siihen, millä projektisi muotoilee koodin.


Esimerkki 3: estä vaaralliset komennot

Joitain komentoja et halua Clauden ajavan koskaan, vaikka hyväksyisit ne kiireessä. Tämä skripti estää rm -rf-komennot ja suorat pushit main-haaraan. Tallenna se tiedostoon .claude/hooks/esta-vaaralliset.sh:

#!/bin/bash
INPUT=$(cat)
COMMAND=$(echo "$INPUT" | jq -r '.tool_input.command // empty')

if echo "$COMMAND" | grep -qE 'rm -rf'; then
  echo "Estetty: rm -rf ei ole sallittu tässä projektissa" >&2
  exit 2
fi

if echo "$COMMAND" | grep -qE 'git push .*main'; then
  echo "Estetty: älä pushaa suoraan mainiin, tee haara ja PR" >&2
  exit 2
fi

exit 0

Anna skriptille suoritusoikeus:

chmod +x .claude/hooks/esta-vaaralliset.sh

Kytke se sitten PreToolUse-tapahtumaan Bash-työkalulle:

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash",
        "hooks": [
          {
            "type": "command",
            "command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/esta-vaaralliset.sh"
          }
        ]
      }
    ]
  }
}

$CLAUDE_PROJECT_DIR osoittaa projektin juureen, josta istunto alkoi, joten skripti löytyy, vaikka Claude olisi siirtynyt alikansioon. Lainausmerkit sen ympärillä pitävät polun ehjänä, jos siinä on välilyöntejä.

Kun Claude yrittää ajaa estetyn komennon, se saa stderrin viestin palautteena ja etsii toisen tavan. Dokumentaation mukaan deny-päätöksen tehnyt PreToolUse-hook pitää kaikissa lupatiloissa, myös bypassPermissions-tilassa.

Muista silti, että tällainen tekstihaku on suodatin eikä muuri. Komennon voi kirjoittaa monella tavalla, joten varsinainen raja kannattaa vetää lupasäännöillä. Hook on hyvä lisäkerros.

Samalla mallilla voit suojata tiedostoja. Vaihda matcheriksi Edit|Write, lue polku kentästä .tool_input.file_path ja vertaa sitä listaan, jossa on vaikkapa .env, package-lock.json ja .git/.


Esimerkki 4: muistuta säännöistä tiivistyksen jälkeen

Kun konteksti täyttyy, Claude Code tiivistää keskustelun. Silloin yksityiskohtia katoaa. SessionStart-hook compact-matcherilla ajetaan jokaisen tiivistyksen jälkeen, ja komennon tulostama teksti lisätään Clauden kontekstiin:

{
  "hooks": {
    "SessionStart": [
      {
        "matcher": "compact",
        "hooks": [
          {
            "type": "command",
            "command": "echo 'Muistutus: käytä pnpm:ää. Aja pnpm test ennen committia.' && git log --oneline -5"
          }
        ]
      }
    ]
  }
}

Tässä hook kertoo pari sääntöä ja näyttää viisi viimeisintä committia. Jos haluat saman tiedon jokaisen istunnon alkuun, CLAUDE.md on siihen parempi paikka. Kontekstin hallinnasta kerrotaan lisää oppaassa Claude Code konteksti ja muisti.


Kun tarvitset harkintaa: prompt-hookit

Kaikkea ei voi tarkistaa grepillä. prompt-tyyppinen hook lähettää ohjeesi ja tapahtuman tiedot Claude-mallille, joka vastaa JSONilla "ok": true tai "ok": false ja syyllä.

Tämä Stop-hook kysyy mallilta, onko kaikki pyydetty tehty. Jos ei ole, Claude jatkaa töitä ja käyttää syytä seuraavana ohjeenaan:

{
  "hooks": {
    "Stop": [
      {
        "hooks": [
          {
            "type": "prompt",
            "prompt": "Tarkista, onko kaikki pyydetyt tehtävät tehty. Jos ei, vastaa {\"ok\": false, \"reason\": \"mitä on vielä tekemättä\"}."
          }
        ]
      }
    ]
  }
}

Jokainen tarkistus on mallikutsu, joten käytä tätä harkiten. Dokumentaation mukaan Claude Code ohittaa Stop-hookin, jos se on estänyt lopettamisen kahdeksan kertaa peräkkäin ilman Clauden työkalukutsua välissä.


Kun hook ei toimi

Tavallisimmat syyt löytyvät nopeasti:

  1. Hook ei näy /hooks-näkymässä. Tarkista tiedoston paikka ja JSON. Pilkku viimeisen alkion perässä tai kommentti rikkoo tiedoston.
  2. Hook näkyy mutta ei laukea. Tarkista matcherin kirjoitusasu. Bash ja bash ovat eri asioita.
  3. Keskusteluun tulee hook-virhe. Aja skripti käsin ja syötä sille esimerkki-JSON:
echo '{"tool_name":"Bash","tool_input":{"command":"ls"}}' | ./.claude/hooks/esta-vaaralliset.sh
echo $?
  1. "command not found". Käytä absoluuttista polkua tai $CLAUDE_PROJECT_DIR-muuttujaa ja tarkista, että skriptillä on suoritusoikeus.
  2. JSON-vastaus ei tee mitään. Tarkista, ettei shellin profiili tulosta mitään ennen JSONia, ja että kentät ovat oikealla tasolla. Esimerkiksi additionalContext kuuluu hookSpecificOutput-olion sisään.

Tarkemmat tiedot saat lokista. Käynnistä Claude Code komennolla claude --debug-file /tmp/claude.log ja seuraa lokia toisessa terminaalissa komennolla tail -f /tmp/claude.log. Kesken istunnon saat lokin päälle komennolla /debug.

Jos haluat kytkeä kaikki hookit pois, aseta asetustiedostoon "disableAllHooks": true.


Turvallisuus: lue ennen kuin lisäät

Komentohook ajetaan täysillä käyttäjäoikeuksillasi. Se voi lukea, muuttaa ja poistaa mitä tahansa tiedostoa, johon sinulla on pääsy. Lue siis jokainen komento ennen kuin lisäät sen, varsinkin jos kopioit sen netistä.

Vieraan repon kanssa kannattaa olla tarkkana. Interaktiivisessa istunnossa Claude Code ei aja asetustiedostojen hookeja ennen kuin olet hyväksynyt kansion luotettavaksi. claude -p -ajossa tätä kyselyä ei tule, joten repoon tallennetut hookit ajetaan suoraan. Lue silloin ensin repon .claude-kansio tai aja ilman hookeja asetuksella --settings '{"disableAllHooks": true}'. Skriptattua käyttöä käsitellään tarkemmin oppaassa Claude Code headless-automaatio.

Dokumentaation omat neuvot hook-skripteille ovat lyhyet: älä luota syötteeseen sokeasti, laita shell-muuttujat lainausmerkkeihin ("$VAR" eikä $VAR), tarkista polut ..-merkkien varalta, käytä absoluuttisia polkuja ja jätä arkaluonteiset tiedostot kuten .env rauhaan.


Hook, skill vai CLAUDE.md?

Kolme työkalua, kolme eri tarkoitusta:

CLAUDE.mdSkillHook
Mikä se onpysyvä ohjeladattava ohje tai työtapaajettava komento
Milloin vaikuttaajoka istunnossakun Claude tai sinä otatte sen käyttöönaina kun tapahtuma osuu
Kuka päättääClaude tulkitseeClaude tulkitseeClaude Code ajaa
Esimerkki"käytä pnpm:ää"julkaisun tarkistuslistaPrettier muokkauksen jälkeen

Hyvä nyrkkisääntö: kun huomaat, että Claude jättää jonkin säännön välillä noudattamatta ja sen on pakko pitää, siirrä sääntö hookiksi. Kun kyse on työtavasta, jota Claude soveltaa harkiten, tee siitä skill. Projektin perustiedot kuuluvat edelleen CLAUDE.md-tiedostoon.

Jos haluat jakaa hookit, skillit ja muut laajennukset useaan projektiin kerralla, ne voi paketoida pluginiksi.


Mistä aloittaa

Aloita yhdellä hookilla. Ilmoitushook on helpoin, koska se ei muuta mitään projektissasi ja huomaat heti, toimiiko se. Sen jälkeen lisää formatteri projektin .claude/settings.json-tiedostoon ja vie se versionhallintaan, niin koko tiimi saa saman muotoilun.

Kun nämä toimivat, mieti, mitä olet joutunut korjaamaan Clauden jäljiltä useammin kuin kerran. Usein siitä saa seuraavan hookin. Lisää Claude Code -vinkkejä löytyy oppaasta Claude Code käytännön vinkit ja Claude Code -oppaista.

Usein kysytyt kysymykset

Mikä on Claude Code hook?

Hook on komento, jonka Claude Code ajaa itse tietyssä kohdassa istuntoa, esimerkiksi ennen työkalun käyttöä, tiedoston muokkauksen jälkeen tai kun Claude odottaa vastaustasi. Hookit kirjoitetaan settings.json-tiedoston hooks-osioon.

Mihin tiedostoon Claude Code hookit kirjoitetaan?

Omat, kaikkia projekteja koskevat hookit menevät tiedostoon ~/.claude/settings.json. Projektin yhteiset hookit menevät tiedostoon .claude/settings.json, jonka voi viedä versionhallintaan. Vain omalla koneella pysyvät projektin hookit menevät tiedostoon .claude/settings.local.json.

Miten hook estää komennon?

PreToolUse-hook estää työkalun käytön, kun skripti päättyy exit-koodiin 2. Virhetulosteeseen kirjoitettu syy välitetään Claudelle, jotta se osaa valita toisen tavan. Toinen tapa on tulostaa JSON, jossa permissionDecision on deny.

Miksi hook ei toimi?

Yleisimmät syyt ovat väärä tiedoston paikka, virheellinen JSON, skripti ilman suoritusoikeutta ja matcher, joka ei osu työkalun nimeen. Matcherit erottavat isot ja pienet kirjaimet. Komento /hooks näyttää, näkeekö Claude Code hookin lainkaan.

Mitä eroa on hookilla ja CLAUDE.md-ohjeella?

CLAUDE.md on ohje, jota Claude yleensä noudattaa. Hook on komento, joka ajetaan joka kerta, kun tapahtuma osuu, riippumatta siitä mitä Claude päättää. Jos jonkin asian on tapahduttava aina, se kannattaa tehdä hookilla.

Claude Code hookit: mikä on hook ja näin teet omat