Kopieer-pas hookkonfigurasies van produksie vir pre-commit validering, PII-skanning, ontplooi sekuriteite en sessie logging Zes maande gelede het ek 'n kleefteken op my monitor gehou. Dit het gesê: "Het jy lint? het jy die tak gekyk? het jy gekyk wat dit verwyder het?" Elke Claude-kode-sessie, dieselfde handmatige kontrole. Elke keer as Claude 'n lêer bewerk het, sou ek na 'n ander terminal skakel en die formater hardloop. Elke keer as dit 'n Bash-bevel uitgevoer het, sou ek by die uitvoer skyn om te wonder of iets produksie aangeraak het. Die kleef nota was nie die probleem nie. Die probleem was dat ek 'n rekenaar se werk gedoen het. herhalende patroon wat op elke aksie ooreenstem, honderde keer per dag. Toe het ek uitgevind Claude Code vuur gebeurtenisse. Elke enkele aksie. gereedskap oproepe, lêer bewerkings, Bash kommando's, sesie begin, sesie eindig. Al hulle. En jy kan enige van hulle met 'n shell script afsluit. Die kleefnote is weg; hier is wat dit vervang het. Die gebeurtenis stelsel niemand praat oor Claude Code is nie net 'n chat-interface wat kode skryf nie. Onder die oppervlak, dit loop 'n lewenscyklus loop. Gebruiker stuur 'n oproep. Claude besluit watter gereedskap om te gebruik. Die gereedskap uitgevoer. Claude lees die resultaat. Herhaal totdat gedoen. By elke oorgang in daardie loop, Claude Code vuur 'n gebeurtenis. Die twee gebeurtenisse wat die meeste belangrik is: Jou bestuurder kan die oproep inspekteer en 'n JSON-oordeel teruggee: toelaat dit, ontken dit, of bly stil en laat die normale toestemmingsstroom dit hanteer. PostToolUse vuur nadat 'n gereedskap oproep suksesvol is. Jou handelaar kry die volledige uitvoer. Doen wat jy wil met dit. Lint die lêer. Log die bevel. Stuur 'n webhook. Die gereedskap is reeds hardloop, so dit is reaktiwiteit, nie voorkomend nie. Handelaars word in die Hulle kan shell opdragte, HTTP eindpunte, of LLM prompts. ek gebruik shell opdragte omdat hulle is vinnig, debuggable, en vereis nie infrastruktuur. .claude/settings.json Die hele koppelvlak is: Claude Code draai JSON na die stdin van jou script. Jou script skryf optioneel JSON na stdout. Dit is dit. As jou script sonder uitvoer verlaat, gaan Claude Code normaal. Skrif 1: Die Disaster Prevention Skrif Ek het hierdie een geskryf nadat Claude probeer 'n bou directory wat gebeur het om 'n simlink in my tuisfolder te hê. Niets slegte gebeur nie, want ek het dit in die toestemmingskop gevang. rm -rf #!/bin/bash # .claude/hooks/guard.sh # Blocks destructive commands before they execute CMD=$(jq -r '.tool_input.command // empty') [ -z "$CMD" ] && exit 0 # Patterns I never want to run unreviewed BLOCKED_PATTERNS=( 'rm -rf' 'rm -r /' 'DROP TABLE' 'DROP DATABASE' 'truncate ' '> /dev/sd' 'mkfs\.' 'dd if=' ) for pattern in "${BLOCKED_PATTERNS[@]}"; do if echo "$CMD" | grep -qi "$pattern"; then jq -n --arg reason "Blocked: command matches dangerous pattern '$pattern'" '{ hookSpecificOutput: { hookEventName: "PreToolUse", permissionDecision: "deny", permissionDecisionReason: $reason } }' exit 0 fi done Die punt is om nie elke gevaarlike bevel op te stel nie. Die punt is om diegene wat jy persoonlik byna per ongeluk gevoer het, te vang. My lys weerspieël my littekens. Jou sal jou weerspieël. Die registrasie in : .claude/settings.json "PreToolUse": [ { "matcher": "Bash", "hooks": [{ "type": "command", "command": ".claude/hooks/guard.sh" }] } ] die is 'n regex op die instrument naam. Dit beteken dat hierdie hook slegs vuurwerk vir Bash-opdragte maak, nie lêers of lêers nie. matcher "Bash" Skrif 2: Die Formatter wat nooit vergeet nie Voordat hierdie hook, my werkstroom was: Claude bewerk lêer, ek sien dat die formatting verkeerd is, ek vra Claude om dit te herstel, Claude hardloop die formater, ek hersien die gevormde weergawe. Vier stappe vir iets wat moet nul stappe wees. #!/bin/bash # .claude/hooks/fmt.sh # Formats files immediately after Claude edits them TOOL=$(jq -r '.tool_name // empty') [ "$TOOL" != "Edit" ] && [ "$TOOL" != "Write" ] && exit 0 FP=$(jq -r '.tool_input.file_path // .tool_input.path // empty') [ -z "$FP" ] || [ ! -f "$FP" ] && exit 0 case "${FP##*.}" in js|ts|jsx|tsx|mjs) if [ -f node_modules/.bin/prettier ]; then node_modules/.bin/prettier --write "$FP" 2>/dev/null elif command -v npx &>/dev/null; then npx prettier --write "$FP" 2>/dev/null fi ;; rs) rustfmt "$FP" 2>/dev/null ;; py) command -v ruff &>/dev/null && ruff format "$FP" 2>/dev/null command -v ruff &>/dev/null && ruff check --fix "$FP" 2>/dev/null ;; go) gofmt -w "$FP" 2>/dev/null ;; css|scss) command -v stylelint &>/dev/null && stylelint --fix "$FP" 2>/dev/null ;; esac exit 0 Hierdie weergawe is meer grondig as die minimale voorbeeld wat jy in dokumentasie vind. Dit kyk of die formater eintlik bestaan voordat jy dit noem. Dit hanteer Prettier via plaaslike install of npx. Dit loop beide en vir Python omdat formattering en linting verskillende dinge is. ruff format ruff check --fix Registreer dit as PostToolUse met 'n Die lêer word geformatteer voordat Claude dit weer lees of na die volgende redigering beweeg. "Edit|Write" Die samestelde effek is beduidend. Oor 'n week het ek dit gemeten. sonder die hoek, het ek 'n gemiddelde van 4 minute per sessie spandeer om Claude te vra om formatering probleme op te los. Met die hoek, nul. Oor 30 sessies per week, dit is twee uur herstel. Skrif 3: Die geheime detektor Hierdie een bestaan as gevolg van 'n byna-mis. Claude het 'n API-integrasie gedebuggeer, 'n konfig lêer gelees wat 'n toets API-sleutel bevat en die sleutel in sy reaksie ingesluit het. Die sleutel was vir 'n opstelomgewing en is die volgende dag gedraai. Maar die beginsel het my beïnvloed. Toolsuitkomste vloei deur die gesprek, word cached, moontlik aangemeld. #!/bin/bash # .claude/hooks/secrets.sh # Scans tool output for credential-shaped strings OUTPUT=$(jq -r '.tool_output // empty') [ -z "$OUTPUT" ] && exit 0 ALERTS="" # AWS keys (AKIA...) echo "$OUTPUT" | grep -qE 'AKIA[0-9A-Z]{16}' && ALERTS="$ALERTS aws_key" # Generic API key patterns (long hex/base64 after common key names) echo "$OUTPUT" | grep -qiE '(api_key|apikey|secret_key|access_token|auth_token)["\x27: =]+[A-Za-z0-9+/]{20,}' && ALERTS="$ALERTS api_credential" # Private key headers echo "$OUTPUT" | grep -q 'BEGIN.*PRIVATE KEY' && ALERTS="$ALERTS private_key" # JWT tokens echo "$OUTPUT" | grep -qE 'eyJ[A-Za-z0-9_-]{10,}\.eyJ[A-Za-z0-9_-]{10,}\.' && ALERTS="$ALERTS jwt_token" # Connection strings with passwords echo "$OUTPUT" | grep -qiE '(postgresql|mysql|mongodb|redis)://[^:]+:[^@]+@' && ALERTS="$ALERTS connection_string" if [ -n "$ALERTS" ]; then TS=$(date '+%H:%M:%S') TOOL=$(jq -r '.tool_name // unknown') echo "[$TS] SECRET_ALERT in $TOOL:$ALERTS" >> .claude/secret-alerts.log echo "WARNING: potential credential in $TOOL output ($ALERTS)" >&2 fi exit 0 Dit is nie 'n vervanging vir behoorlike geheime bestuur nie. Dit is 'n tripwire. Dit vang die voor die hand liggende patrone: AWS toegang sleutels, dinge wat lyk soos API-aankondigings, private sleutelblokke, JWT's, databasisverbindingsreekse met ingebed wagwoorde. Wanneer dit brand, word dit en druk 'n waarskuwing af aan stderr. Dit blokkeer niks nie. die blokkeer van 'n vals positiewe sal jou vloei onderbreek. die logging op 'n ware positiewe gee jou iets om aan die einde van die sessie te ondersoek. .claude/secret-alerts.log Ek beoordeel Een keer per dag. Die meeste inskrywings is vals positiewe (toetsfixtures, dokumentasie voorbeelde). Ongeveer een keer per week, een is werklik genoeg om die draai van 'n credential of die opdatering van 'n .gitignore te regverdig. secret-alerts.log Geskryf deur: The Branch Cop Kort, skerp, en gebore uit 'n ware fout. , het Claude gevra om 'n vinnige regstelling te druk, en dit het gegaan voordat ek geregistreer het wat gebeur het. Die dryf het gegaan. CI was groen. Geen skade gedoen nie. Maar die kompromie was nie bedoel om op die hoof te land sonder 'n PR. main git push origin main #!/bin/bash # .claude/hooks/no-push-main.sh # Prevents git push to main/master/production branches CMD=$(jq -r '.tool_input.command // empty') echo "$CMD" | grep -q 'git push' || exit 0 BRANCH=$(git branch --show-current 2>/dev/null) PROTECTED="main master production release" for b in $PROTECTED; do if [ "$BRANCH" = "$b" ]; then jq -n --arg branch "$BRANCH" '{ hookSpecificOutput: { hookEventName: "PreToolUse", permissionDecision: "deny", permissionDecisionReason: ("Push to " + $branch + " blocked. Create a feature branch first.") } }' exit 0 fi done # Also block force push to any branch if echo "$CMD" | grep -qE 'push.*(-f|--force)'; then jq -n '{ hookSpecificOutput: { hookEventName: "PreToolUse", permissionDecision: "deny", permissionDecisionReason: "Force push blocked. Use --force-with-lease if you must." } }' fi Twee wagte in een script. Geen druk na beskermde takke nie. Geen krag druk na enige takke nie. Die tweede reël is optioneel, maar ek hou dit omdat krag drukke die soort ding is wat jou moet vereis om die bevel self te typ, met volle bewustheid van wat jy doen. Claude hanteer die ontkenning gracieus. Dit sien die rede, stel voor om 'n kenmerktak te skep en gaan op die regte spoor. Die hoek onderbreek nie die sessie nie. Script 5: Die swart boks rekenaar Elke gereedskap oproep. Elke invoer. Elke uitvoer. Timestamp en bygevoeg aan 'n log lêer. Dit is die hoek wat ek die meeste dikwels aan te beveel aan teams, want dit beantwoord die vraag wat jy altyd vra nadat iets verkeerd gegaan het: "Wat het Claude presies gedoen?" #!/bin/bash # .claude/hooks/record.sh # Logs every tool call to a structured audit file TS=$(date '+%Y-%m-%d %H:%M:%S') TOOL=$(jq -r '.tool_name // "unknown"') SESSION=$(jq -r '.session_id // "unknown"') # Compact input (one line, no whitespace bloat) INPUT=$(jq -c '.tool_input // {}') # Truncate output to prevent log bloat (first 500 chars) OUTPUT=$(jq -r '.tool_output // empty' | head -c 500) # Tab-separated for easy parsing with awk/cut printf '%s\t%s\t%s\t%s\t%s\n' \ "$TS" "$SESSION" "$TOOL" "$INPUT" "$OUTPUT" \ >> .claude/session-log.tsv exit 0 Tabel-geskei, nie JSON nie. Bewuste keuse. TSV-lêers is grypbaar, sorterbaar en snybaar met standaard Unix-tools. Moet jy elke Bash-bevel vanaf vandag sien? grep "$(date +%Y-%m-%d)" .claude/session-log.tsv | grep "Bash" | cut -f4 Moet jy tel hoeveel lêerredaksies Claude hierdie week gemaak het? grep -c "Edit\|Write" .claude/session-log.tsv Die uitvoerveld word gekort tot 500 karakters om te voorkom dat verskeie megabytes log lêers wanneer Claude groot lêers lees. As jy volle uitvoer nodig het, skakel na per-sessie log lêers: vervang die lêername met . .claude/logs/session-${SESSION}.tsv Vir teams wat sentralised logging benodig, vervang die lêer byvoeging met 'n HTTP hook wat na jou logging-infrastruktuur dui. Die JSON-gewerkloosheid wat Claude Code stuur, bevat alles wat hierdie script vang, plus bykomende konteks soos die werkende directory en gereedskapkonfigurasie. Die gekombineerde instellings lêer Al die vyf skrywers, gekoppel aan: { "hooks": { "PreToolUse": [ { "matcher": "Bash", "hooks": [ { "type": "command", "command": ".claude/hooks/guard.sh" }, { "type": "command", "command": ".claude/hooks/no-push-main.sh" } ] } ], "PostToolUse": [ { "matcher": "Edit|Write", "hooks": [ { "type": "command", "command": ".claude/hooks/fmt.sh" } ] }, { "matcher": "", "hooks": [ { "type": "command", "command": ".claude/hooks/secrets.sh" }, { "type": "command", "command": ".claude/hooks/record.sh" } ] } ] } } Kopieer die JSON in Maak die vyf skrywers in Die hardloop Die Done. .claude/settings.json .claude/hooks/ chmod +x .claude/hooks/*.sh Vervolgens word die hoek in orde gevoer. beide en evalueer elke Bash-bevel. As een van hulle 'n ontkenning terugkeer, word die bevel geblokkeer. PostToolUse hooks loop ook in volgorde, maar hulle kan niks blokkeer nie; die instrument is reeds uitgevoer. guard.sh no-push-main.sh Die leë matcher op die tweede PostToolUse-invoer beteken en vuur op elke gereedskapoproep, nie net lêerredaksies nie. Dit is opsetlik. Ek wil die Bash-uitvoer skandeer vir credentials en ek wil alles log, ongeag die gereedskapstype. secrets.sh record.sh Wat ek geleer het om hierdie vir ses maande te hardloop Alles anders is versekering. Die formater is 'n onmiddellike, meetbare tyd bespaar. Installeer daardie een eers, selfs as jy die res ignoreer. The formatter hook pays for itself on day one. Ek sal liewer tien valse alarms 'n week hersien as om een werklike credential te mis. Die oorsig van die log lêer neem 30 sekondes. False positives in the secret scanner are fine. Elke paar weke voeg ek 'n patroon by na 'n by-mis. Nou het dit agt patrone. In ses maande sal dit twintig hê. Dit is die punt. Dit akkumuleer jou span se institusionele kennis oor wat nooit onbeoordeel moet loop nie. The guard script needs to evolve. rm -rf Jy lees dit selde proaktief.Maar wanneer iets verkeerd gaan, het 'n volledige rekord van elke aksie Claude geneem verander 'n twee uur se ondersoek in 'n vyf-minuut greep. The audit log is most valuable after incidents. Elke PreToolUse hook voeg latensie by elke gereedskapoproep. My garde- en takkop-skripte loop in minder as 5ms elkeen. Die formater is die traagste by 50-200ms afhangende van die lêergrootte, maar dit loop PostToolUse sodat dit nie die pijplyn blokkeer nie. As jou hook 'n eksterne API oproep, gebruik PostToolUse of aanvaar die latensie. Keep hooks fast. Die Sticky Note is weg Die monitoring wat voorheen in my kop geleef het, leef nou in vyf skaalskripte met 'n totaal van 150 lyn. Hulle loop op elke gereedskapoproep sonder my betrokkeheid. Hulle vang dinge wat ek sou mis as ek moeg is aan die einde van 'n lang sessie. AI-kodingsondersteuners is kragtig.Maar krag sonder garde is net 'n risiko wat jy nog nie gemeten het nie.Vyf skripte, tien minute van instelling, en die risiko val na byna nul. Die kleef nota is vervang deur iets beter. iets wat nie vertrou op my onthou om dit te kyk nie.