Конфигурации на приклучоци за копирање од производството за валидација на претходна задача, скенирање на PII, безбедносни мерки за имплементација и лого на сесија Пред шест месеци, на мојот монитор држев налеплива белешка, во која се вели: „Дали сте ја врзале лентата, дали сте ја провериле гранката, дали сте го погледнале она што го избришала?“ Секоја сесија на Клод Код, истата рачна проверка. Секој пат кога Клод го уредуваше датотеката, јас се префрлував на друг терминал и го извршував форматирачот. Секој пат кога таа извршуваше команда на Баш, јас се запрашав на излезот за да се запрашам дали нешто се допирало до производството. Секој пат кога се обидувал да се ангажира, јас би проверил дека сум на вистинската гранка прво. Проблемот беше во тоа што ја правев работата на компјутерот. Повторувачки модел се совпаѓа на секоја акција, стотици пати на ден. Потоа дознав дека Клод Код ги зафаќа настаните. Секоја една акција. Алатки за повици, уредувања на датотеки, команда на Баш, сесија започнува, сесија завршува. Сите од нив. И можете да прекинете било кој од нив со скрипта за обвивка. Но, сепак, тоа не е во ред. Еве што го заменило. Системот на настани за кој никој не зборува Клод Код не е само интерфејс за разговор кој пишува код. Под површината, работи жицикли. Корисникот испраќа повик. Клод одлучува која алатка да се користи. алатката извршува. Клод го чита резултатот. Повторете се додека не се заврши. На секоја транзиција во тој круг, Клод Код пука на настанот и можете да прикачите раководител на било кој од нив. Двете настани кои се најважни: Вашиот оператор може да го прегледа повикот и да врати пресуда за JSON: дозволете го, одбијте го или молчи и дозволете нормалниот тек на дозволи да го обработи. PostToolUse избувнува по успешен повик на алатка. Вашиот манипулатор добива целосен излез. Правете што сакате со него. Завртете го датотеката. Логирајте ја командата. Испратете веб-кук. алатката веќе работи, така што ова е реактивно, а не превентивно. Трговците се регистрирани во Тие можат да бидат команда на школки, HTTP крајни точки или LLM повици.Јас користам команда на школки, бидејќи тие се брзи, дебугабилни и не бараат инфраструктура. .claude/settings.json Целиот интерфејс е: Клод Код води JSON до stdin на вашиот скрипт. Вашиот скрипт опционално пишува JSON до stdout. Тоа е тоа. Ако вашиот скрипт излегува без излез, Клод Код продолжува нормално. Сценарио 1: Сценарио за спречување на катастрофи Ова го напишав откако Клод се обиде да градење директориум кој се случи да има симлинк во мојата домашна папка. Ништо лошо се случи затоа што го фатив во поканата за дозвола. Но јас не треба да го фати. 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 Осум модели. Може да биде осумдесет. Поентата не е да се наведе секоја опасна команда. Поентата е да ги фати оние што сте ги имале лично речиси случајно. Мојата листа ги одразува моите лузни. Твоите ќе ги одразуваат твоите. Регистрацијата во : .claude/settings.json "PreToolUse": [ { "matcher": "Bash", "hooks": [{ "type": "command", "command": ".claude/hooks/guard.sh" }] } ] на е regex на името на алатката. Ова значи дека овој приклучок само ги зафаќа командата Bash, а не датотеките кои се уредуваат или читаат. matcher "Bash" Сценарио 2: Форматерот кој никогаш не заборава Пред овој приклучок, мојот работен тек беше: Клод го уредува датотеката, забележувам дека форматирањето е погрешно, го замолувам Клод да го поправи, Клод го извршува форматирачот, ја разгледувам форматираната верзија. #!/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 Оваа верзија е подетална од минималниот пример што го наоѓате во документацијата. Проверете дали форматирачот навистина постои пред да го повикате. и за Python затоа што форматирањето и лентирањето се различни работи. ruff format ruff check --fix Регистрирајте го како PostToolUse со По секоја модификација на датотеката, фајлот е форматиран пред Клод да го прочита назад или да се префрли на следното уредување. "Edit|Write" Ефектот на соединението е значаен. Повеќе од една недела го измерив. Без кука, потрошив просечно 4 минути по сесија барајќи од Клод да ги поправи проблемите со форматирањето. Со кука, нула. Повеќе од 30 сесии неделно, што е два часа вратени. Сценарио 3: Тајниот детектор Овој постои поради речиси пропуштена. Клод дебугираше API интеграција, прочита конфигурациска датотека која содржи тест API клуч и го вклучи клучот во својот одговор. клучот беше за средина за поставување и беше ротиран следниот ден. Но принципот ме вознемири. Излезот на алатката тече низ разговорот, се кешира, потенцијално се најавува. #!/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 Ова не е замена за правилно управување со тајни. Тоа е tripwire. Тоа ги фаќа очигледни шеми: AWS пристапни клучеви, работи кои изгледаат како API верификации, приватни клучни блокови, JWTs, низи за поврзување со база на податоци со вградени лозинки. Кога ќе изгори, ќе се и печати предупредување на stderr. Тоа не блокира ништо. Блокирање на лажен позитивен ќе го прекине вашиот проток. Логирање на вистински позитивен ви дава нешто да се истражуваат на крајот на сесијата. .claude/secret-alerts.log Преглед на Повеќето записи се лажни позитивни (тестови, примери за документација). Околу еднаш неделно, еден е доволно реален за да се оправда ротирање на верификација или ажурирање на .gitignore. secret-alerts.log Сценарио 4: Полицаецот на клонот Кратка, остра и родена од вистинска грешка. , побара од Клод да притисне брза поправка, и тоа помина пред да го регистрирам она што се случуваше. Движењето помина. ЦИ беше зелено. Нема оштетување направено. Но компромисот не требаше да слета на главното без ПР. 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 Две стражари во еден скрипт. Нема притискање на заштитени гранки. Нема сила притискање на која било гранка. Второто правило е опционално, но јас го чувам затоа што притискањето на силата е вид на нешто што треба да ве натера да ја напишете командата самите, со целосна свест за она што го правите. Клод грациозно се справува со одбивањето. Тој ја гледа причината, сугерира создавање на гранка на функцијата и продолжува на вистинскиот пат. Кукот не ја прекинува сесијата. Сценарио 5: Црната кутија рекордер Секој повик за алатка. Секој влез. Секој излез. Временски запечатен и прикачен на датотека за дневник. Ова е кукот што најчесто му го препорачувам на тимовите, бидејќи одговара на прашањето што секогаш го поставувате откако нешто не е во ред: "Што точно направил Клод?" #!/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 Таб-сепаратирани, а не JSON. Намерно избор. TSV датотеки се зафатени, сортирани и исечени со стандардни Unix алатки. Треба да се види секоја команда Bash од денес? grep "$(date +%Y-%m-%d)" .claude/session-log.tsv | grep "Bash" | cut -f4 Треба да се брои колку уреди на датотеки Клод направи оваа недела? grep -c "Edit\|Write" .claude/session-log.tsv Полето за излез е скратено на 500 знаци за да се спречи датотеки со повеќе мегабајти кога Клод чита големи датотеки.Ако ви е потребен целосен излез, префрлете се на датотеки со дневен ред за сесија: заменете го името на датотеката со . .claude/logs/session-${SESSION}.tsv За тимови кои имаат потреба од централизирано логирање, заменете го прилог на датотеката со HTTP приклучок кој укажува на вашата инфраструктура за логирање. JSON корисничкото оптоварување Claude Code испраќа содржи сè што го фаќа овој скрипт, плус дополнителен контекст како што се работниот директориум и конфигурацијата на алатките. Комбинираните поставки на датотеката Сите пет сценарија, поврзани заедно: { "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" } ] } ] } } Копирајте го JSON во Креирајте ги петте скрипти во Трчање Дона .claude/settings.json .claude/hooks/ chmod +x .claude/hooks/*.sh Претходна Вест PreToolUse hooks run in order. и Оценувајте ја секоја команда на Баш. Ако и двете враќаат одбивање, командата е блокирана. PostToolUse хаковите исто така работат во ред, но не можат да блокираат ништо; алатката веќе е извршена. guard.sh no-push-main.sh Празниот натпревар на вториот влез PostToolUse значи и оган на секој повик за алатки, не само за уредување на датотеки. Тоа е намерно. Сакам да го скенирам излезот на Баш за верификации и сакам да ги лограм сè, без оглед на типот на алатката. secrets.sh record.sh Што научив да трчам овие шест месеци Сè друго е осигурување. Форматорот е непосредна, мерлива заштеда на време. Инсталирајте го првиот, дури и ако ги игнорирате останатите. The formatter hook pays for itself on day one. Подобро би прегледал десет лажни аларми неделно отколку да пропуштам една вистинска верификација. Прегледот на датотеката за дневник трае 30 секунди. False positives in the secret scanner are fine. На секои неколку недели додавам модел по речиси пропуштен. Сега има осум обрасци. За шест месеци ќе има дваесет. Тоа е поентата. Тоа го акумулира институционалното знаење на вашиот тим за она што никогаш не треба да работи непроменето. The guard script needs to evolve. rm -rf Но, кога нешто оди погрешно, имајќи целосна евиденција за секоја акција што Клод ја презеде, претвора двечасовна истрага во петминутно држење. The audit log is most valuable after incidents. Секој приклучок PreToolUse додава латентност на секој повик на алатка. Моите скрипти за стража и гранка-коп работат во помалку од 5 ms. Форматорот е најбавен на 50-200ms во зависност од големината на датотеката, но работи PostToolUse за да не го блокира цевката. Ако вашиот приклучок повикува надворешен API, користете PostToolUse или прифатете ја латенцијата. Keep hooks fast. The Sticky Note е надвор Набљудувањето што некогаш живееше во мојата глава сега живее во пет скрипти на школки вкупно 150 линии. Тие работат на секој повик на алатка без моето вклучување. Тие ги фаќаат работите што би ги пропуштиле кога сум уморен на крајот на долга сесија. Асистентите за кодирање на АИ се моќни.Но моќта без стражар е само ризик што сè уште не сте го измериле.Пет скрипти, десет минути на инсталација, а ризикот паѓа на речиси нула. Леплива белешка е заменета со нешто подобро.Нешто што не се потпира на мене се сеќавам да го погледне.