SSD Nodes Learn 🎉 VPS $5.50/महिन्यापासून
मार्गदर्शक Matt Connorद्वारे Matt Connor · अपडेटेड 2026-08-15

Claude Code Hooks: events, exit code 2 आणि security

Claude Code hooks model ची संमती नसतानाही चालतात. ते कुठे असतात, कोणते events trigger होतात, exit code 2 tool call कसा रद्द करतो आणि security cost जाणून घ्या.

Claude Code hook म्हणजे काय

Claude Code hooks हे shell commands आहेत, जे Claude Code स्वतःच्या lifecycle मधील ठरावीक टप्प्यांवर आपोआप चालवते. Hook आणि rules file यांच्यातील हाच मुख्य फरक आहे. CLAUDE.md मधील instruction हा सल्ला असतो आणि model त्याचा संदर्भातील इतर सर्व घटकांशी तुलनात्मक विचार करते. Hook हा code असतो आणि model सहमत असो वा नसो, तो चालतो. तुम्ही formatter बद्दल दोनदा सांगूनही तुमचा agent तो सतत वगळत असेल, तर अधिक कडक instruction देण्याची गरज नाही. तुम्हाला hook आवश्यक आहे.

ही यंत्रणा लहान आहे. तुम्ही settings file मध्ये एखाद्या event name अंतर्गत command नोंदवता. तो event trigger झाल्यावर Claude Code तुमची command चालवते आणि event data तिच्या standard input (stdin) मध्ये JSON (JavaScript object notation) स्वरूपात लिहिते. तुमची command ते data वाचते, आवश्यक काम करते आणि exit status द्वारे उत्तर देते. PreToolUse hook कडून exit 2 मिळाल्यास tool call चालण्यापूर्वीच रद्द होते. तुमच्या script ने standard error (stderr) वर लिहिलेला मजकूर कारण म्हणून model कडे परत पाठवला जातो.

येथील event names आणि field names Claude Code hooks reference मधून घेतले आहेत. August 2026 मध्ये release 2.1.232 विरुद्ध त्यांची पडताळणी केली आहे. हा भाग वेगाने बदलतो. त्यामुळे कोणत्याही blog post मधून, यासह, JSON copy करण्यापूर्वी तुमच्या version साठी reference तपासा. तुमची version claude --version ने दाखवा.

हुक कॉन्फिगरेशन कुठे असते

हुक हा settings file मधील JSON block असतो. सहा ठिकाणी हुक ठेवता येतो आणि त्या file चा scope हुकचा scope ठरतो.

  • ~/.claude/settings.json: तुमच्या मशीनवरील प्रत्येक project साठी; इतर कोणाच्याही मशीनसाठी नाही.
  • .claude/settings.json: एका project साठी. हा repository मध्ये commit केला जातो, त्यामुळे तो clone करणाऱ्या प्रत्येकाला हुक मिळतो.
  • .claude/settings.local.json: एका project साठी; फक्त तुमच्या मशीनवर.
  • Managed policy settings: संपूर्ण organisation साठी; administrator हे सेट करतो.
  • Plugin मधील hooks/hooks.json: तो plugin enabled असेपर्यंत सक्रिय राहतो.
  • Skill किंवा subagent frontmatter: तो component active असेपर्यंत सक्रिय राहतो.

या files मधील हुक entries एकमेकींना override न करता merge होतात. Project settings file मधील हुक user settings मधील हुकच्या जागी येत नाहीत; ते त्यात जोडले जातात. त्यामुळे एका event मध्ये अनेक files मधील अनेक हुक असू शकतात. "disableAllHooks": true सेट केल्यास हे हुक बंद होतात. मात्र एक अपवाद आहे: managed policy settings मधील हुक सुरूच राहतात, जोपर्यंत ती setting managed settings मध्येही लागू केली जात नाही.

सध्या registered असलेले सर्व हुक event नुसार यादीत पाहण्यासाठी session मध्ये /hooks चालवा. प्रत्येक हुकसाठी source file आणि matcher देखील दाखवला जातो. हा menu read-only आहे. त्यामुळे हुक बदलण्यासाठी settings file संपादित करा. File watcher साधारणपणे हा बदल restart न करता ओळखतो.

Claude Code hook events कोणते उपलब्ध आहेत

Release 2.1.232 मध्ये SessionStart ते SessionEnd पर्यंत एकतीस events सूचीबद्ध आहेत. यामध्ये compaction, subagents, worktrees आणि configuration files यांचा समावेश होतो. Server कामासाठी त्यांपैकी काही events पुरेसे असतात.

  • PreToolUse: tool call execute होण्यापूर्वी. हा event execution रोखू शकतो.
  • PostToolUse: tool call यशस्वी झाल्यानंतर. तो अयशस्वी झाल्यास PostToolUseFailure trigger होतो. त्यामुळे प्रत्येक outcome पाहणाऱ्या hook साठी दोन्ही आवश्यक आहेत.
  • PermissionRequest: tool call साठी permission decision आवश्यक असताना. याच वेळी approval prompt दिसतो.
  • UserPromptSubmit: prompt submit केल्यानंतर, Claude त्यावर प्रक्रिया करण्यापूर्वी. हा hook stdout वर जे print करतो ते model च्या context मध्ये जोडले जाते.
  • SessionStart आणि SessionEnd: session च्या प्रत्येक समाप्तीच्या वेळी. Compaction नंतरही SessionStart trigger होतो, आणि त्यावेळी matcher value compact असते.
  • Stop: Claude चे उत्तर पूर्ण झाल्यावर. हे पूर्ण झालेल्या task साठी एकदा नव्हे, तर प्रत्येक turn साठी एकदा trigger होते.

प्रत्येक group मध्ये matcher असतो. तो कोणत्या occurrences वर hook चालवायचा हे ठरवतो. Tool events मध्ये तो tool name नुसार filtering करतो. त्यामुळे "Edit|Write" file edits वर trigger होतो आणि इतर कोणत्याही गोष्टीवर होत नाही. Matchers case sensitive असतात. रिकामा matcher प्रत्येक occurrence वर trigger होतो. MCP (model context protocol) server वरील tools ची नावे mcp__<server>__<tool> या स्वरूपात असतात. त्यामुळे "mcp__github__.*" matcher वापरल्यास एका server ची tools निवडली जातात आणि इतर tools वगळल्या जातात.

Stop hooks मध्ये एक महत्त्वाची मर्यादा आहे. Stop hook ने execution रोखल्यास model पुन्हा काम करण्यासाठी पाठवले जाते. सलग आठ वेळा block झाल्यानंतर Claude Code तो hook override करते. Hook input मधील stop_hook_active field वाचा आणि त्याची value true असल्यास exit 0 करा. अन्यथा hook त्या मर्यादेपर्यंत loop होत राहील.

stdin वर hook ला काय मिळते

Claude npm test चालवण्याच्या तयारीत असताना, Bash वरील PreToolUse hook stdin वरून हे वाचतो:

{
  "session_id": "abc123",
  "cwd": "/home/deploy/myproject",
  "hook_event_name": "PreToolUse",
  "tool_name": "Bash",
  "tool_input": {
    "command": "npm test"
  }
}

प्रत्येक event मध्ये session_id, cwd, permission_mode, transcript_path आणि hook_event_name असतात. Tool events मध्ये tool_name, tool_input आणि tool_use_id देखील असतात. इतर events मध्ये त्यांची स्वतंत्र fields असतात: UserPromptSubmit मध्ये prompt मजकूर असतो, तर SessionStart मध्ये startup च्या source पैकी resume, clear, compact किंवा fork असतो.

Shell script मध्ये हे वाचण्याची नेहमीची पद्धत jq आहे. Minimal server image मध्ये ते उपलब्ध नसते. Ubuntu आणि Debian वर sudo apt install -y jq वापरून ते आधी install करा.

टूल कॉल सुरू असताना exit status चा परिणाम

याचे तीन परिणाम असतात.

  • Exit 0 म्हणजे तुमच्या hook ने कोणताही आक्षेप नोंदवलेला नाही. PreToolUse वर याचा अर्थ अनुमती असा होत नाही आणि सामान्य permission flow तरीही चालतो. UserPromptSubmit आणि SessionStart वर stdout model च्या context मध्ये जोडला जातो.
  • Exit 2 मुळे block करता येणाऱ्या events वरील कृती थांबते. त्यामध्ये PreToolUse देखील समाविष्ट आहे. stderr मधील मजकूर model ला दाखवले जाणारे कारण बनतो. PostToolUse सारख्या block करता न येणाऱ्या events वर block दुर्लक्षित केला जातो. मात्र stderr feedback म्हणून model पर्यंत पोहोचतो.
  • इतर कोणताही exit code हा non-blocking error असतो. कृती पुढे सुरू राहते. Transcript मध्ये Failed with non-blocking status code: या मजकुरानंतर stderr मधील पहिली ओळ असलेली hook error सूचना दिसते.

Block करणे किंवा शांत राहणे यापेक्षा अधिक काही करायचे असल्यास exit 0 वापरा आणि stdout वर JSON object print करा. PreToolUse hook permissionDecision द्वारे निर्णय घेते:

{
  "hookSpecificOutput": {
    "hookEventName": "PreToolUse",
    "permissionDecision": "deny",
    "permissionDecisionReason": "Database drops go through a migration, not through the agent."
  }
}

"allow" interactive prompt वगळते, "deny" call रद्द करून कारण model कडे पाठवते आणि "ask" prompt नेहमीप्रमाणे दाखवते. प्रत्येक hook साठी एकच style निवडा. stdout वर JSON decision देताना exit 2 मिसळल्यास त्याचा परिणाम स्वतंत्रपणे शोधावा लागतो.

एकाच event शी अनेक hooks जुळल्यास ते parallel मध्ये चालतात आणि प्रत्येक hook पूर्ण होईपर्यंत चालू राहतो. एका hook कडून आलेला deny त्याच्या sibling hooks ला थांबवत नाही. त्यामुळे guardrail hook त्याच call ला नाकारत असतानाही logging hook आपली ओळ लिहितो. त्यानंतर Claude Code सर्व उत्तरे एकत्र करते आणि सर्वाधिक restrictive उत्तर ठेवते: deny, defer, ask, allow या क्रमाने.

उदाहरण 1: destructive command चालण्यापूर्वी तो अवरोधित करा

हे तुमच्या project मध्ये .claude/hooks/block-destructive.sh म्हणून जतन करा:

#!/bin/bash
# Deny a Bash tool call whose command matches a banned pattern.
INPUT=$(cat)
COMMAND=$(echo "$INPUT" | jq -r '.tool_input.command // empty')

for pattern in 'rm -rf /' 'mkfs' 'dd if=' 'DROP TABLE'; do
  if printf '%s' "$COMMAND" | grep -qiF -- "$pattern"; then
    echo "Blocked by policy: the command matches '$pattern'. A human runs this one." >&2
    exit 2
  fi
done

exit 0

ते executable करा. त्यानंतर .claude/settings.json मधील PreToolUse वर त्याची नोंदणी करा:

chmod +x .claude/hooks/block-destructive.sh
{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash",
        "hooks": [
          {
            "type": "command",
            "command": "${CLAUDE_PROJECT_DIR}/.claude/hooks/block-destructive.sh",
            "timeout": 10,
            "statusMessage": "Checking the command against policy"
          }
        ]
      }
    ]
  }
}

Script वर विश्वास ठेवण्यापूर्वी तो manually तपासा. कारण hook स्वतःच्या input मुळे crash झाल्यास तो fail open होतो:

echo '{"tool_name":"Bash","tool_input":{"command":"rm -rf /var/lib/postgresql"}}' \
  | .claude/hooks/block-destructive.sh
echo $?

stderr वर Blocked by policy: ओळ आणि 2 exit code दिसला पाहिजे. ls -la सारखी harmless command द्या. त्यावर कोणतेही output दिसू नये आणि 0 exit code दिसला पाहिजे. Session मध्ये denied call तुमच्या message ला कारण म्हणून transcript मध्ये दिसतो. Model तो message वाचून त्यानुसार बदल करतो.

ही एक बाब हा उपाय उपयुक्त ठरवते: PreToolUse hooks प्रत्येक permission mode मध्ये permission-mode check होण्यापूर्वी चालतात. त्यामुळे bypassPermissions अंतर्गतही deny लागू राहतो. म्हणूनच Claude Code auto mode आणि त्याच्या permission settings सोबत hook उपयुक्त ठरतो. या mode मध्ये prompts कमी केलेले असतात, तरी hook चालतो.

हा उपाय नेमका काय आहे, याबाबत स्पष्ट रहा. Command string वर pattern matching केल्याने agent निष्काळजीपणे वागण्यापासून guardrail मिळतो. मात्र agent हुशारीने वागल्यास ही boundary ठरत नाही. कारण तीच command तुमच्या grep ला न दिसणाऱ्या स्वरूपात लिहिता येते. कठोर नियम permission system मध्ये आणि process ज्या account अंतर्गत चालतो त्या account मध्ये लागू केले पाहिजेत.

उदाहरण 2: प्रत्येक संपादनानंतर format आणि lint

PostToolUse सोबत Edit|Write matcher वापरल्यास तो कोणत्याही file-editing tool नंतर चालतो. हे .claude/hooks/after-edit.sh म्हणून जतन करा:

#!/bin/bash
# Format the edited file, then report lint failures back to the model.
INPUT=$(cat)
FILE=$(echo "$INPUT" | jq -r '.tool_input.file_path // empty')
[ -z "$FILE" ] && exit 0

case "$FILE" in
  *.py)
    ruff format "$FILE" >/dev/null 2>&1
    if ! ruff check "$FILE" >&2; then
      exit 2
    fi
    ;;
  *.sh)
    if ! shellcheck "$FILE" >&2; then
      exit 2
    fi
    ;;
esac

exit 0
{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Edit|Write",
        "hooks": [
          {
            "type": "command",
            "command": "${CLAUDE_PROJECT_DIR}/.claude/hooks/after-edit.sh",
            "timeout": 60
          }
        ]
      }
    ]
  }
}

Claude ला Python file मध्ये चुकीच्या indentation चे function जोडण्यास सांगा आणि नंतर ती file उघडा. ती file format केलेली दिसते. Hook चालल्याची हीच पडताळणी आहे, कारण hook यशस्वी झाल्यास संभाषणात काहीही दिसत नाही.

येथील exit 2 कोणतेही बदल पूर्ववत करत नाही. PostToolUse tool आधीच execute झाल्यानंतर चालतो, त्यामुळे edit कोणत्याही परिस्थितीत disk वर राहतो. exit 2 मुळे ruff check चे output model पर्यंत feedback म्हणून पोहोचते. त्यामुळे agent पुढे जाण्याऐवजी त्याने नुकतीच निर्माण केलेली error दुरुस्त करतो. Commit वेळी सापडणाऱ्या lint failure आणि त्याच turn मध्ये agent दुरुस्त करत असलेल्या lint failure मधील हा फरक आहे.

येथे दोन matcher मर्यादा महत्त्वाच्या आहेत. Edit|Write ला shell command मुळे बदललेल्या files दिसत नाहीत आणि Claude Bash द्वारे files पुरेशा वेळा लिहितो, त्यामुळे ही उणीव प्रत्यक्षात महत्त्वाची ठरते. प्रत्येक call साठी coverage हवी असल्यास Bash शी देखील match करा आणि script कडून बदललेल्या files ची यादी git status --porcelain वापरून तयार करून घ्या. प्रत्येक turn मध्ये एकदाच coverage हवी असल्यास scan Stop hook मध्ये ठेवा.

उदाहरण 3: audit साठी प्रत्येक tool call नोंदवा

PostToolUse वरील रिकामा matcher प्रत्येक tool वर लागू होतो. नोंद home directory मधील फाइलऐवजी system journal मध्ये पाठवल्याने ती agent च्या स्वतःच्या shell च्या आवाक्याबाहेर राहते:

{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "",
        "hooks": [
          {
            "type": "command",
            "command": "jq -c '{time: now|todate, session: .session_id, cwd: .cwd, tool: .tool_name, input: .tool_input}' | logger -t claude-code -p local0.info"
          }
        ]
      }
    ]
  }
}

journalctl -t claude-code -o cat | tail -n 5 वापरून ती नोंद पुन्हा वाचा. प्रत्येक tool call साठी एक JSON ओळ दिसली पाहिजे; सर्वांत नवीन नोंद शेवटी असते. काहीही दिसत नसल्यास hook चालला नाही. खालील troubleshooting विभागात याची कारणे आणि उपाय दिले आहेत.

अयशस्वी calls नोंदवण्यासाठी PostToolUseFailure अंतर्गत हाच block जोडा, कारण PostToolUse फक्त यशस्वी call वर चालतो आणि अयशस्वी command हीच सहसा महत्त्वाची नोंद असते. तुमच्या home directory मधील फाइलमध्ये append करण्याऐवजी logger वापरण्याचे कारण ownership आहे: hook agent च्या shell प्रमाणेच त्याच user म्हणून चालतो. त्यामुळे एखादा user ज्या फाइलमध्ये append करू शकतो, ती फाइल तो truncate देखील करू शकतो. Journal systemd-journald स्वतःच्या account अंतर्गत लिहितो.

हुक किती वेळ चालू शकतो

ChartDefault hook timeout in seconds, by hook type and event
The data behind this chart
[
  {
    "label": "command, http or mcp_tool hook",
    "default_timeout_seconds": 600
  },
  {
    "label": "agent hook",
    "default_timeout_seconds": 60
  },
  {
    "label": "prompt hook",
    "default_timeout_seconds": 30
  },
  {
    "label": "command hook on UserPromptSubmit",
    "default_timeout_seconds": 30
  },
  {
    "label": "command hook on MessageDisplay",
    "default_timeout_seconds": 10
  },
  {
    "label": "any hook on SessionEnd",
    "default_timeout_seconds": 1.5
  }
]

Command hook ला डीफॉल्टनुसार 600 सेकंद मिळतात. हा कालावधी दहा मिनिटांचा आहे. काही events हा कालावधी मोठ्या प्रमाणात कमी करतात. SessionEnd hooks साठी सर्व hooks मध्ये एकत्रित 1.5 सेकंदांची मर्यादा असते. त्यामुळे session समाप्तीनंतरची cleanup प्रक्रिया जलद असणे आवश्यक आहे. मात्र hook वरील timeout अधिक मोठ्या मूल्यावर सेट केल्यास ही एकत्रित मर्यादा त्यानुसार वाढते, परंतु कमाल 60 सेकंदांपर्यंत.

Timeout गाठणारा hook रद्द केला जातो आणि कोणताही निर्णय देत नाही. PreToolUse guardrail साठी याचा अर्थ तो अडथळा आणत नाही. Tool call सामान्य permission flow मध्ये पुढे सुरू राहतो. त्यामुळे guardrail scripts लहान ठेवा. कोणीही प्रतीक्षा करत नसलेल्या धीम्या कामासाठी, उदाहरणार्थ log दुसऱ्या ठिकाणी पाठवण्यासाठी, "async": true सेट करा. अशा वेळी hook background मध्ये चालतो आणि tool call ला थांबवत नाही.

Hooks, rules files, skills आणि MCP servers

हे चारही घटक agent चे काम करण्याचे पद्धत बदलत असल्यामुळे त्यांचा एकमेकांशी गोंधळ होतो. यांपैकी केवळ एक घटक सूचना म्हणून न राहता अंमलात येणे थांबवतो.

Rules file (CLAUDE.md किंवा .claude/rules/ अंतर्गत असलेली file) हा model च्या context मध्ये लोड होणारा मजकूर असतो. तो वर्तनाला दिशा देतो; मात्र तो काहीही सक्तीने लागू करत नाही. दीर्घ conversation, मोठा diff आणि नव्याने आलेली user request यांच्यासमोर त्यातील एखादी ओळ दुर्लक्षित होऊ शकते. तुम्ही लिहून ठेवलेल्या सूचनांकडे agents दुर्लक्ष का करतात यामागील हीच सामान्य प्रक्रिया आहे.

Skill हा instructions आणि scripts असलेला folder असतो. model ला तो skill संबंधित आहे असे वाटल्यावर तो तो लोड करतो. हा निर्णयच skill चा मुख्य भाग आहे आणि त्याची मर्यादाही आहे: निर्णय अजूनही model घेतो. Ponytail, जो agent ला काम करणारा सर्वात छोटा बदल निवडण्यास प्रवृत्त करतो यासारख्या skill मध्ये हे दोन्ही पैलू दिसतात. तो hook पेक्षा वेगळ्या प्रकारे संपूर्ण task कडे पाहण्याची पद्धत ठरवतो; मात्र model तो लोड करण्याचा निर्णय घेतो तेव्हाच तो लागू होतो.

MCP (model context protocol) server model ला call करण्यासाठी नवीन tools देतो. त्यामुळे agent ज्या resources पर्यंत पोहोचू शकतो त्यांची व्याप्ती वाढते. मात्र त्यामुळे agent कोणत्याही resource पर्यंत पोहोचेलच असे होत नाही. तसेच तो स्वतंत्र process असतो आणि त्याचे operation तुम्हाला स्वतंत्रपणे करावे लागते. हे स्वतःचे एक काम आहे: VPS वर MCP servers चालवणे पहा.

या चार घटकांपैकी hook हा एकमेव घटक आहे जो model च्या निर्णयाशिवाय चालतो. एखादी preference असल्यास rules file वापरा. model ने लागू असताना पाळावी अशी procedure असल्यास skill वापरा. प्रत्येक वेळी होणे आवश्यक असलेल्या step साठी किंवा कधीही होऊ नये अशा गोष्टीसाठी hook वापरा. सविस्तर तुलना, त्यात skill rules file पेक्षा कधी अधिक योग्य ठरतो यासह, skills, MCP आणि rules files ची तुलना येथे आहे.

Plugin हे पाचवे mechanism नसून packaging आहे. ते hooks आणि skills एकाच installable unit मध्ये एकत्र करते. त्यामुळे team प्रत्येक machine वर समान guardrail लागू करू शकते: Claude Code plugins कसे काम करतात पहा.

सामायिक VPS वरील सुरक्षा निर्णय

Hook म्हणजे agent द्वारे trigger केला जाणारा code. तो Claude Code सुरू करणाऱ्या user म्हणून चालतो. त्याला त्या user चे environment आणि file permissions वारशाने मिळतात. Laptop वर हा workflow शी संबंधित प्रश्न असतो. Agent unattended पद्धतीने चालणाऱ्या VPS वर हा चार व्यावहारिक भाग असलेला सुरक्षा प्रश्न असतो.

Repository मधील hook हा तुम्ही लिहिलेला code नसतो. .claude/settings.json commit केलेले असल्यामुळे repository clone करून त्यामध्ये session सुरू केल्यास repository सोबत आलेले hooks register होऊ शकतात. Claude Code त्या folder साठीच्या workspace trust dialog मागे project hooks ठेवतो. त्यामुळे trust स्वीकारणे म्हणजे ते hooks चालवण्याचा निर्णय घेण्याचा क्षण असतो. प्रथम hooks block वाचा.

Hook ला संपूर्ण tool input दिसतो. tool_input log करणारा audit hook प्रत्येक command चे प्रत्येक argument file मध्ये लिहितो. त्यात command line वर असलेला कोणताही token समाविष्ट होऊ शकतो. त्या log ला secret प्रमाणेच सुरक्षा द्यावी लागते. हा AI agent च्या आवाक्याबाहेर secrets ठेवण्याच्या व्यापक समस्येचा भाग आहे.

Hook model च्या context मध्ये लिहू शकतो. SessionStart किंवा UserPromptSubmit hook stdout वर जे काही print करतो ते conversation मध्ये जोडले जाते. बाहेरील स्रोत, issue tracker किंवा log file मधील text pipe करणारा hook untrusted text model कडे पाठवतो, जणू तो text तुम्ही स्वतः type केला आहे. त्या stdout कडे output म्हणून नव्हे, तर input म्हणून पाहा.

प्रत्यक्ष नियंत्रण privilege चे असते. Agent dedicated unprivileged user म्हणून चालवा आणि त्याला आवश्यक तेवढेच sudo नियम द्या. PreToolUse deny ठेवणे उपयुक्त आहे. हे design नुसार best effort असते. Reference मध्ये if filter बद्दलही तेच सांगितले आहे आणि hard deny आवश्यक असल्यास permission system वापरण्यास सांगितले आहे. Permission rules आणि process ज्या account अंतर्गत चालतो ते account हे दबावाच्या परिस्थितीतही लागू राहणारे भाग आहेत.

प्रत्येक configuration मध्ये एक गुणधर्म कायम लागू राहतो. PreToolUse hooks प्रत्येक permission mode मध्ये permission-mode check च्या आधी चालतात. त्यामुळे deny परत करणारा hook bypassPermissions अंतर्गतही tool block करतो. Hooks permission rules ने परवानगी दिलेल्या कृती अधिक मर्यादित करू शकतात. ते त्या सैल करू शकत नाहीत.

माझा hook का कार्यान्वित होत नाही?

ही तपासणी पुढील क्रमाने करा. प्रत्येक पायरीमध्ये प्रत्यक्ष दिसणारे लक्षण दिले आहे.

  • /hooks चालवा आणि अपेक्षित event अंतर्गत hook दिसत आहे का ते तपासा. मेनूमध्ये hook दिसत नसेल, तर settings file मध्ये JSON syntax error असण्याची शक्यता असते, कारण trailing commas आणि comments अनुमत नाहीत. तसेच ही file वर नमूद केलेल्या सहापैकी एखाद्या location मध्ये नसू शकते.
  • Matcher ची tool name सोबत तंतोतंत तुलना करा. Matchers case-sensitive असतात. त्यामुळे "bash" हा matcher Bash tool शी कधीही जुळत नाही.
  • वरील example 1 प्रमाणे sample input देऊन script manually चालवा. अपेक्षित नसलेला exit code मिळाल्यास दोष तुमच्या script मध्ये आहे. Claude Code त्याला decision म्हणून नव्हे, तर hook error म्हणून नोंदवते.
  • jq: command not found असा notice दिसल्यास त्या machine वर jq उपलब्ध नाही. तुमच्या स्वतःच्या script साठी command not found मिळाल्यास path resolve झालेला नाही. त्यामुळे ${CLAUDE_PROJECT_DIR} किंवा absolute path वापरा. Script अजिबात चालत नसेल, तर ती executable नसण्याची शक्यता आहे.
  • Hook valid JSON छापतो, पण काहीही घडत नाही. Shell-form hook sh -c द्वारे चालतो. तुमच्या shell profile मधून banner छापला जात असल्यास, तो banner तुमच्या JSON च्या आधी जोडला जातो. त्यामुळे stdout ची सुरुवात { ने होत नाही. Claude Code संपूर्ण output plain text म्हणून वाचते आणि decision दुर्लक्षित करते. Exit 0 असल्यास debug log वगळता कुठेही काही नोंदवले जात नाही. Profile मधील कोणतेही echo interactive shells मध्येच चालेल, अशी अट लावा.
  • तरीही समस्या सुटत नसेल, तर claude --debug-file /tmp/claude.log सह session सुरू करा आणि दुसऱ्या terminal मध्ये tail -f /tmp/claude.log चालवा. Debug log मध्ये कोणते hooks जुळले, प्रत्येकाने कोणता exit code परत केला आणि stdout व stderr मध्ये काय लिहिले, याची नोंद असते.

FAQ

Claude Code hook आणि CLAUDE.md instruction यांच्यात काय फरक आहे?

CLAUDE.md instruction हा model च्या context मधील मजकूर असतो. त्यामुळे तो conversation आणि सध्याच्या request सोबत model चे लक्ष मिळवण्यासाठी स्पर्धा करतो. Model त्याचे या दोन्हींच्या तुलनेत मूल्यमापन करू शकतो. Hook ही shell command असते. Claude Code ती आपल्या lifecycle मधील ठरावीक टप्प्यावर चालवतो. त्यामुळे model ने काहीही ठरवले तरी त्या event च्या प्रत्येक वेळी ती execute होते. Preference साठी instruction वापरा. नेहमी होणे आवश्यक असलेल्या step साठी किंवा कधीही होऊ नये अशा action साठी hook वापरा.

Claude Code ला विशिष्ट shell command चालवण्यापासून कसे थांबवायचे?

PreToolUse hook नोंदवा आणि Bash matcher वापरा. हा matcher command .tool_input.command मधून वाचतो, stderr वर कारण लिहितो आणि 2 ने exit करतो. Claude Code call रद्द करतो आणि तुमचे कारण model ला दाखवतो. हे permission-mode तपासण्यापूर्वी घडते. त्यामुळे bypassPermissions mode मध्येही deny लागू राहतो. Command string वरचे pattern matching हे security boundary नसून guardrail आहे. कारण तोच command pattern ला न जुळणाऱ्या स्वरूपात लिहिता येतो. त्यामुळे त्यास permission rules आणि unprivileged account यांचा आधार द्या.

माझा hook वैध JSON दाखवतो, पण काहीही का घडत नाही?

याचे सर्वात सामान्य कारण shell profile असते. args field नसलेला hook sh -c मार्फत चालतो. काही profiles प्रत्येक shell सुरू होताना banner दाखवतात. त्यामुळे तुमच्या JSON च्या आधी तो stdout वर लिहिला जातो. Output आता { ने सुरू होत नसल्यामुळे Claude Code त्यातील सर्व मजकूर plain text मानतो आणि decision दुर्लक्षित करतो. तसेच exit 0 झाल्यावर transcript मध्ये काहीही नोंदवले जात नाही. तुमच्या profile मधील कोणतेही echo interactive-shell test ने संरक्षित करा. त्यानंतर claude --debug-file /tmp/claude.log मधील debug log वाचून दुरुस्तीची खात्री करा.

Shared server वर Claude Code hooks चालवणे सुरक्षित आहे का?

Hooks Claude Code सुरू करणाऱ्या user च्या अधिकारांनी चालतात. त्यामुळे त्या account ला जे काही करता येते ते hook करू शकतो. जोखीम कमी करण्यासाठी दोन सवयी पुरेशा ठरतात: agent ला मर्यादित sudo policy असलेल्या स्वतंत्र unprivileged account म्हणून चालवा आणि repository मधील workspace trust dialog स्वीकारण्यापूर्वी त्याचा hooks block वाचा. कारण project hooks .claude/settings.json मध्ये समाविष्ट असतात. यापैकी एकही hook चालू नये असे असल्यास settings file मध्ये "disableAllHooks": true सेट करा.