SSD Nodes Learn 🎉 VPS $5.50/মাস থেকে
নির্দেশিকা Matt Connorদ্বারা Matt Connor · আপডেট করা হয়েছে 2026-08-15

Claude Code hooks কীভাবে কাজ করে এবং সেটআপ করবেন

Claude Code hooks কীভাবে কাজ করে তা জানুন। মডেলের মতামতের তোয়াক্কা না করে কীভাবে নির্দিষ্ট কমান্ড রান করবেন, exit code 2 দিয়ে টুল কল বাতিল করবেন এবং নিরাপত্তার ঝুঁকিগুলো বুঝুন।

Claude Code hook কী

Claude Code hook হলো এমন কিছু shell command যা Claude Code তার নিজস্ব lifecycle-এর নির্দিষ্ট সময়ে নিজে থেকেই চালায়। hook এবং rules file-এর মধ্যে মূল পার্থক্য এখানেই। CLAUDE.md-এর কোনো নির্দেশনা হলো পরামর্শ, যা মডেল তার context-এর অন্যান্য বিষয়ের সাথে মিলিয়ে বিবেচনা করে। অন্যদিকে, hook হলো কোড, যা মডেলের মতামতের তোয়াক্কা না করেই কার্যকর হয়। যদি আপনার agent বারবার formatter এড়িয়ে যায়, তবে তাকে আরও কঠোর নির্দেশনা দেওয়ার প্রয়োজন নেই। আপনার একটি hook প্রয়োজন।

এই মেকানিজমটি বেশ সহজ। আপনি একটি settings file-এ event name-এর অধীনে একটি command register করবেন। যখন সেই event ঘটে, Claude Code আপনার command-টি চালায় এবং event-এর ডেটা standard input (stdin)-এ JSON (JavaScript object notation) হিসেবে লিখে দেয়। আপনার command সেই ডেটা পড়ে, কাজ সম্পন্ন করে এবং একটি exit status প্রদান করে। একটি PreToolUse hook থেকে exit 2 দিলে তা tool call-টি কার্যকর হওয়ার আগেই বাতিল করে দেয় এবং আপনার script standard error (stderr)-এ যা লেখে, তা কারণ হিসেবে মডেলের কাছে ফেরত পাঠানো হয়।

এখানে উল্লিখিত event name এবং field name-গুলো Claude Code hooks reference থেকে নেওয়া হয়েছে, যা আগস্ট 2026-এ release 2.1.232-এর সাথে মিলিয়ে দেখা হয়েছে। এই বিষয়টি দ্রুত পরিবর্তিত হয়, তাই যেকোনো blog post থেকে JSON কপি করার আগে আপনার নিজের version-এর জন্য reference যাচাই করে নিন। claude --version ব্যবহার করে আপনার নিজেরগুলো print করুন।

হুক কনফিগারেশন যেখানে থাকে

একটি হুক হলো সেটিংস ফাইলের ভেতরে থাকা একটি JSON ব্লক। এটি ছয়টি ভিন্ন স্থানে থাকতে পারে এবং ফাইলের স্কোপই হলো হুকের স্কোপ।

  • ~/.claude/settings.json: আপনার মেশিনের প্রতিটি প্রজেক্টের জন্য, অন্য কারো জন্য নয়।
  • .claude/settings.json: একটি নির্দিষ্ট প্রজেক্টের জন্য, যা রিপোজিটরিতে কমিট করা থাকে, ফলে যারা এটি ক্লোন করবে তারা সবাই হুকটি পাবে।
  • .claude/settings.local.json: একটি নির্দিষ্ট প্রজেক্টের জন্য, শুধুমাত্র আপনার মেশিনে।
  • ম্যানেজড পলিসি সেটিংস: পুরো প্রতিষ্ঠানের জন্য, যা একজন অ্যাডমিনিস্ট্রেটর সেট করেন।
  • hooks/hooks.json একটি প্লাগইনের ভেতরে, যা প্লাগইনটি সক্রিয় থাকা অবস্থায় কার্যকর থাকে।
  • স্কিল বা সাব-এজেন্ট ফ্রন্টম্যাটার, যা সেই কম্পোনেন্টটি সক্রিয় থাকা অবস্থায় কার্যকর থাকে।

এই ফাইলগুলো থেকে আসা হুক এন্ট্রিগুলো একে অপরকে ওভাররাইড না করে মার্জ বা একত্রিত হয়। একটি প্রজেক্ট সেটিংস ফাইল আপনার ইউজার সেটিংসের হুকগুলোকে প্রতিস্থাপন না করে সেগুলোর সাথে নতুন হুক যোগ করে, তাই একটি ইভেন্টে বিভিন্ন ফাইল থেকে আসা একাধিক হুক থাকতে পারে। "disableAllHooks": true সেটিংসটি সেট করলে এগুলো বন্ধ হয়ে যায়, তবে একটি ব্যতিক্রম আছে: ম্যানেজড পলিসি সেটিংস থেকে আসা হুকগুলো চলতে থাকে, যদি না সেই সেটিংটি ম্যানেজড সেটিংসের ভেতরেও প্রয়োগ করা হয়।

বর্তমানে নিবন্ধিত প্রতিটি হুক দেখার জন্য সেশনের ভেতরে /hooks কমান্ডটি চালান। এটি ইভেন্ট অনুযায়ী হুকগুলোকে গ্রুপ করে দেখাবে এবং প্রতিটি হুকের সোর্স ফাইল ও ম্যাচারের তথ্য প্রদান করবে। এই মেনুটি শুধুমাত্র পড়ার জন্য (read-only), তাই হুক পরিবর্তন করতে হলে আপনাকে সেটিংস ফাইলটি এডিট করতে হবে। ফাইল ওয়াচার সাধারণত রিস্টার্ট ছাড়াই এডিটগুলো শনাক্ত করে নেয়।

Claude Code-এ কী কী hook event বিদ্যমান

Release 2.1.232-এ একত্রিশটি ইভেন্টের তালিকা রয়েছে, যা SessionStart থেকে শুরু করে SessionEnd পর্যন্ত বিস্তৃত এবং এগুলো compaction, subagents, worktrees ও configuration file-এর বিষয়গুলো কভার করে। সার্ভারের কাজে এর মধ্যে কয়েকটি ব্যবহৃত হয়।

  • PreToolUse: কোনো tool call কার্যকর হওয়ার আগে। এটিই একমাত্র ইভেন্ট যা প্রক্রিয়াটিকে আটকে (block) রাখতে পারে।
  • PostToolUse: কোনো tool call সফল হওয়ার পরে। যদি এটি ব্যর্থ হয়, তবে PostToolUseFailure ট্রিগার হয়; তাই যে hook-কে প্রতিটি ফলাফল পর্যবেক্ষণ করতে হয়, সেটির জন্য উভয়ই প্রয়োজন।
  • PermissionRequest: যখন কোনো tool call-এর জন্য অনুমতির সিদ্ধান্তের প্রয়োজন হয়, অর্থাৎ যে মুহূর্তে approval prompt প্রদর্শিত হওয়ার কথা।
  • UserPromptSubmit: যখন আপনি কোনো prompt সাবমিট করেন, Claude সেটি প্রসেস করার আগে। এই hook যা কিছু stdout-এ প্রিন্ট করে, তা মডেলের context-এ যুক্ত হয়ে যায়।
  • SessionStart এবং SessionEnd: একটি session-এর শুরু ও শেষ পর্যায়ে। SessionStart ইভেন্টটি compaction-এর পরেও ট্রিগার হয়, যার matcher value হলো compact
  • Stop: যখন Claude তার প্রতিক্রিয়া (response) শেষ করে। এটি প্রতি turn-এ একবার ঘটে, প্রতিটি কাজ শেষ হওয়ার পর নয়।

প্রতিটি গ্রুপে একটি matcher থাকে যা নির্ধারণ করে কোন ঘটনাগুলোতে hook-টি চলবে। tool ইভেন্টগুলোর ক্ষেত্রে এটি tool-এর নাম অনুযায়ী ফিল্টার করে, তাই "Edit|Write" শুধুমাত্র file edit-এর সময় ট্রিগার হয় এবং অন্য কোনো ক্ষেত্রে নয়। Matcher-গুলো case sensitive। একটি খালি matcher প্রতিটি ঘটনার ক্ষেত্রেই ট্রিগার হয়। MCP (model context protocol) সার্ভারের টুলগুলোর নাম mcp__<server>__<tool> হিসেবে থাকে, তাই "mcp__github__.*"-এর একটি matcher নির্দিষ্ট একটি সার্ভারের টুলগুলোকে ধরে ফেলে এবং অন্যগুলোকে অপরিবর্তিত রাখে।

Stop hook ব্যবহারের ক্ষেত্রে একটি সতর্কবার্তা জানা থাকা প্রয়োজন। একটি Stop hook যা প্রক্রিয়াকে আটকে রাখে, তা মডেলকে পুনরায় কাজে পাঠিয়ে দেয় এবং Claude Code আটবার টানা আটকে রাখার পর hook-টিকে override করে ফেলে। hook input থেকে stop_hook_active ফিল্ডটি পড়ুন এবং এটি true হলে exit 0 দিন, অন্যথায় আপনার hook-টি সেই সীমা (cap) পর্যন্ত পৌঁছানো না পর্যন্ত লুপে চলতে থাকবে।

stdin-এ একটি হুক যা গ্রহণ করে

যখন Claude npm test চালানোর প্রস্তুতি নেয়, তখন Bash-এ থাকা একটি PreToolUse হুক stdin-এ নিচের তথ্যগুলো পড়ে:

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

প্রতিটি ইভেন্টে session_id, cwd, permission_mode, transcript_path এবং hook_event_name থাকে। টুল ইভেন্টগুলো এর সাথে tool_name, tool_input এবং tool_use_id যুক্ত করে। অন্যান্য ইভেন্টগুলোতে নিজস্ব ফিল্ড থাকে: UserPromptSubmit-এ prompt টেক্সট থাকে এবং SessionStart-এ startup, resume, clear, compact অথবা fork-এর একটি source থাকে।

শেল স্ক্রিপ্টের ভেতরে এটি পড়ার সাধারণ উপায় হলো jq, কিন্তু একটি মিনিমাল সার্ভার ইমেজে এটি থাকে না। তাই Ubuntu এবং Debian-এ sudo apt install -y jq ব্যবহার করে প্রথমে এটি ইনস্টল করে নিন।

চলমান টুল কলে এক্সিট স্ট্যাটাস যেভাবে কাজ করে

এর তিনটি ফলাফল হতে পারে।

  • Exit 0 মানে হলো আপনার হুক কোনো আপত্তি জানাচ্ছে না। PreToolUse-এর ক্ষেত্রে এটি অনুমোদনের সমতুল্য নয় এবং স্বাভাবিক পারমিশন ফ্লো তখনও কার্যকর থাকে। UserPromptSubmit এবং SessionStart-এর ক্ষেত্রে, stdout মডেলের কনটেক্সটে যুক্ত হয়।
  • Exit 2 যেসব ইভেন্ট ব্লক করা সম্ভব, সেগুলোর ক্ষেত্রে অ্যাকশনটিকে আটকে দেয় (যার মধ্যে PreToolUse অন্তর্ভুক্ত) এবং stderr-এর বিষয়বস্তু মডেলকে কারণ হিসেবে দেখানো হয়। যেসব ইভেন্ট ব্লক করা যায় না, যেমন PostToolUse, সেগুলোর ক্ষেত্রে ব্লক করার বিষয়টি উপেক্ষা করা হয়, যদিও stderr ফিডব্যাক হিসেবে মডেলের কাছে পৌঁছায়।
  • অন্য যেকোনো এক্সিট কোড একটি নন-ব্লকিং এরর। অ্যাকশনটি চলতে থাকে। ট্রান্সক্রিপ্টে একটি হুক এরর নোটিশ দেখা যায়, যেখানে Failed with non-blocking status code: টেক্সটের পরে stderr-এর প্রথম লাইনটি থাকে।

ব্লক করা বা চুপ থাকার বাইরে অন্য কিছু করতে চাইলে, Exit 0 ব্যবহার করুন এবং stdout-এ একটি JSON অবজেক্ট প্রিন্ট করুন। একটি PreToolUse হুক permissionDecision ব্যবহার করে সিদ্ধান্ত নেয়:

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

"allow" ইন্টারঅ্যাক্টিভ প্রম্পট এড়িয়ে যায়, "deny" কলটি বাতিল করে এবং কারণটি মডেলের কাছে পাঠায়, এবং "ask" প্রম্পটটিকে স্বাভাবিকভাবে দেখায়। প্রতি হুকের জন্য একটি স্টাইল বেছে নিন। Exit 2-এর সাথে stdout-এ JSON সিদ্ধান্ত মিশ্রিত করলে এমন ফলাফল পাওয়া যায় যা আপনাকে আলাদাভাবে যাচাই করতে হবে।

যখন একাধিক হুক একটি ইভেন্টের সাথে মিলে যায়, তখন সেগুলো সমান্তরালভাবে চলে এবং প্রতিটি হুক সম্পূর্ণ হওয়া পর্যন্ত কাজ করে। একটি হুকের deny তার অন্য হুকগুলোকে থামায় না; তাই একটি গার্ডরেল হুক যখন কোনো কল প্রত্যাখ্যান করে, তখনও একটি লগিং হুক তার লাইন লিখতে পারে। Claude Code তখন উত্তরগুলোকে একত্রিত করে এবং সবচেয়ে কঠোর সিদ্ধান্তটি গ্রহণ করে, যার ক্রম হলো: deny, defer, ask, allow।

উদাহরণ 1: একটি ধ্বংসাত্মক কমান্ড চলার আগেই তা আটকে দেওয়া

আপনার প্রজেক্টে এটিকে .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"
          }
        ]
      }
    ]
  }
}

স্ক্রিপ্টটিকে বিশ্বাস করার আগে নিজে পরীক্ষা করে দেখুন, কারণ যে হুক তার নিজের ইনপুটে ক্র্যাশ করে তা কোনো নিরাপত্তাই দেয় না:

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

আপনার stderr-এ Blocked by policy: লাইনটি এবং 2 এক্সিট কোড দেখা উচিত। এটিকে ls -la-এর মতো একটি ক্ষতিকারক নয় এমন কমান্ড দিয়ে পরীক্ষা করুন, সেক্ষেত্রে কোনো আউটপুট আসা উচিত নয় এবং এক্সিট কোড হওয়া উচিত 0। একটি সেশনে, প্রত্যাখ্যাত কলটি ট্রান্সক্রিপ্টে আপনার দেওয়া কারণসহ প্রদর্শিত হবে এবং মডেল সেই বার্তাটি পড়ে নিজেকে মানিয়ে নেবে।

একটি বৈশিষ্ট্যের কারণে এটি করা কার্যকর: PreToolUse হুকগুলো পারমিশন-মোড চেক করার আগেই কার্যকর হয়, প্রতিটি পারমিশন মোডেই এটি ঘটে, তাই bypassPermissions মোডেও এই নিষেধাজ্ঞা কার্যকর থাকে। এটিই হুকটিকে Claude Code auto mode এবং এর পারমিশন সেটিংস-এর পাশাপাশি কার্যকর করে তোলে, যেখানে প্রম্পট কমিয়ে দেওয়া হলেও হুকটি ঠিকই কাজ করে।

এটি আসলে কী, সে বিষয়ে সৎ থাকুন। কমান্ড স্ট্রিংয়ের ওপর প্যাটার্ন ম্যাচিং হলো এজেন্টের অসাবধানতা রোধ করার একটি গার্ডরেল, এটি এজেন্টের চতুরতার বিরুদ্ধে কোনো সীমানা নয়, কারণ একই কমান্ড এমনভাবে লেখা সম্ভব যা আপনার grep কখনোই দেখতে পাবে না। কঠোর নিয়মগুলো পারমিশন সিস্টেম এবং যে অ্যাকাউন্টের অধীনে প্রসেসটি চলছে, সেখানেই থাকা উচিত।

উদাহরণ 2: প্রতিটি এডিটের পর ফরম্যাট এবং লিন্ট করা

একটি PostToolUse এবং একটি Edit|Write ম্যাচারের সমন্বয়ে যেকোনো ফাইল-এডিটিং টুলের পর এটি কার্যকর হয়। এটিকে .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 ফাইলে ভুল ইনডেন্টেশনসহ একটি ফাংশন যোগ করতে বলুন, তারপর ফাইলটি ওপেন করুন। এটি ফরম্যাট হয়ে ফিরে আসবে। এটিই আপনার প্রমাণ যে হুকটি কাজ করেছে, কারণ একটি সফল হুক কনভারসেশনে কিছু দেখায় না।

এখানে exit 2 কোনো কিছু আনডু (undo) করে না। PostToolUse টুলটি কার্যকর হওয়ার পরেই চলে, তাই এডিটটি যেকোনোভাবেই ডিস্কে থেকে যায়। exit 2 ব্যবহারের সুবিধা হলো, ruff check আউটপুটটি ফিডব্যাক হিসেবে মডেলের কাছে পৌঁছায়, ফলে মডেলটি নতুন করে কোনো ভুল করার পরিবর্তে নিজেই সেই ত্রুটি সংশোধন করে নেয়। কমিট করার সময় লিন্ট ফেইল হওয়া এবং এজেন্টের একই টার্নে ত্রুটি সংশোধন করার মধ্যে এটাই পার্থক্য।

এখানে দুটি ম্যাচারের সীমাবদ্ধতা গুরুত্বপূর্ণ। Edit|Write শেল কমান্ডের মাধ্যমে পরিবর্তিত ফাইলগুলো দেখতে পায় না এবং Claude প্রায়শই Bash-এর মাধ্যমে ফাইল লেখে, তাই এই সীমাবদ্ধতাটি বাস্তব। প্রতিটি কলের কভারেজের জন্য Bash-কেও ম্যাচ করুন এবং স্ক্রিপ্টটিকে git status --porcelain ব্যবহার করে পরিবর্তিত ফাইলের তালিকা তৈরি করতে বলুন। প্রতি টার্নে একবার কভারেজের জন্য, স্ক্যানটিকে একটি Stop হুকে রাখুন।

উদাহরণ 3: অডিট করার জন্য প্রতিটি টুল কল লগ করা

PostToolUse-এ একটি খালি ম্যাচার প্রতিটি টুলের ওপর কাজ করে। রেকর্ডটি হোম ডিরেক্টরির কোনো ফাইলে না পাঠিয়ে সিস্টেম জার্নালে পাঠালে তা এজেন্টের নিজস্ব শেলের নাগালের বাইরে থাকে:

{
  "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 ব্যবহার করে এটি পড়ুন। আপনি প্রতিটি টুল কলের জন্য একটি করে JSON লাইন দেখতে পাবেন, যেখানে নতুনগুলো সবার শেষে থাকবে। যদি কিছু না দেখা যায়, তবে বুঝতে হবে হুকটি চলেনি; নিচের ট্রাবলশুটিং অংশে এর সমাধান দেওয়া হয়েছে।

ব্যর্থ হওয়া কলগুলো ক্যাপচার করতে PostToolUseFailure-এর নিচে একই ব্লক যোগ করুন, কারণ PostToolUse শুধুমাত্র সফল হওয়ার পরেই কাজ করে এবং সাধারণত ব্যর্থ কমান্ডগুলোই বেশি গুরুত্বপূর্ণ। হোম ডিরেক্টরির কোনো ফাইলে অ্যাপেন্ড না করে logger ব্যবহার করার কারণ হলো মালিকানা বা ওনারশিপ: একটি হুক এজেন্টের শেলের ব্যবহারকারীর পরিচয়েই চলে, তাই ওই ব্যবহারকারী যে ফাইলে কিছু যোগ করতে পারে, সেটি মুছে ফেলার ক্ষমতাও তার থাকে। জার্নালটি systemd-journald তার নিজস্ব অ্যাকাউন্টের মাধ্যমে লিখে থাকে।

একটি হুক কতক্ষণ চলতে পারে

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
  }
]

একটি কমান্ড হুক ডিফল্টভাবে 600 সেকেন্ড সময় পায়, যা দশ মিনিটের সমান। কিছু ইভেন্টের ক্ষেত্রে এই সময়সীমা কঠোরভাবে কমিয়ে দেওয়া হয়। SessionEnd হুকগুলো তাদের সবার মধ্যে মোট 1.5 সেকেন্ডের একটি বাজেট শেয়ার করে, তাই সেশনের শেষভাগের ক্লিনআপ কাজ দ্রুত হতে হবে। তবে হুকের ওপর একটি দীর্ঘ timeout সেট করলে সেই শেয়ার করা বাজেট বেড়ে সর্বোচ্চ 60 সেকেন্ড পর্যন্ত হতে পারে।

যে হুক তার সময়সীমা অতিক্রম করে, সেটি বাতিল হয়ে যায় এবং কোনো সিদ্ধান্ত প্রদান করে না। একটি PreToolUse গার্ডরেলের ক্ষেত্রে এর অর্থ হলো এটি কোনো কিছুকে বাধা দেয় না: টুল কলটি স্বাভাবিক অনুমতি প্রবাহে (permission flow) চলতে থাকে। এই কারণে গার্ডরেল স্ক্রিপ্টগুলো ছোট রাখুন। ধীরগতির কাজের জন্য যার জন্য কেউ অপেক্ষা করছে না, যেমন কোথাও লগ পাঠানো, সেক্ষেত্রে "async": true সেট করুন। এতে হুকটি টুল কলকে আটকে না রেখে ব্যাকগ্রাউন্ডে চলতে থাকবে।

Hooks, rules files, skills এবং MCP servers

চারটি বিষয় একে অপরের সাথে গুলিয়ে যায় কারণ এগুলোর প্রতিটিই এজেন্টের কাজের ধরন পরিবর্তন করে। এদের মধ্যে কেবল একটি বিষয় পরামর্শের ঊর্ধ্বে গিয়ে বাধ্যতামূলক হয়।

একটি rules file (CLAUDE.md, অথবা .claude/rules/-এর অধীনে থাকা কোনো ফাইল) হলো এমন টেক্সট যা মডেলের কনটেক্সটে লোড করা হয়। এটি আচরণকে প্রভাবিত করে কিন্তু কোনো কিছু বলবৎ করে না। দীর্ঘ কথোপকথন, বড় কোনো diff এবং নতুন ব্যবহারকারীর অনুরোধের ভিড়ে এর একটি লাইন হারিয়ে যেতে পারে। এটিই সেই সাধারণ কারণ যার ফলে এজেন্ট আপনার লিখে দেওয়া নির্দেশনা উপেক্ষা করে

একটি skill হলো নির্দেশনা এবং স্ক্রিপ্টের একটি ফোল্ডার, যা মডেল যখন প্রাসঙ্গিক মনে করে তখন লোড করে। এই বিচারবুদ্ধিই একটি skill-এর মূল ভিত্তি, এবং এটিই এর সীমাবদ্ধতা: সিদ্ধান্তটি শেষ পর্যন্ত মডেলই নেয়। আপনি Ponytail-এর মতো একটি skill-এ উভয় দিকই দেখতে পাবেন, যা এজেন্টকে কার্যকর ক্ষুদ্রতম পরিবর্তনের দিকে ধাবিত করে। এটি এমনভাবে পুরো কাজের পদ্ধতিকে প্রভাবিত করে যা কোনো hook-এর পক্ষে সম্ভব নয়, এবং এটি কেবল তখনই কাজ করে যখন মডেল এটি লোড করার সিদ্ধান্ত নেয়।

একটি MCP (model context protocol) server মডেলকে কল করার জন্য নতুন টুলস দেয়। এটি এজেন্টের কাজের পরিধি বাড়ায়। এটি এজেন্টকে কোনো কিছু করতে বাধ্য করে না এবং এটি একটি আলাদা প্রসেস যা আপনাকে পরিচালনা করতে হয়, যা নিজেই একটি কাজ: দেখুন VPS-এ MCP server চালানো

এই চারটির মধ্যে কেবল hook-ই মডেলের সিদ্ধান্ত ছাড়াই কার্যকর হয়। কোনো পছন্দের জন্য rules file এবং মডেল যখন কোনো পদ্ধতি প্রয়োগ করবে তখন তার জন্য skill ব্যবহার করুন। এমন ধাপের জন্য hook ব্যবহার করুন যা প্রতিবারই ঘটতে হবে, অথবা এমন কিছুর জন্য যা কখনোই ঘটা উচিত নয়। skill কখন rules file-এর চেয়ে কার্যকর হয়, তা সহ বিস্তারিত তুলনা রয়েছে skills, MCP এবং rules files-এর তুলনামূলক আলোচনায়

একটি plugin হলো পঞ্চম কোনো মেকানিজম নয়, বরং এটি প্যাকেজিংয়ের একটি মাধ্যম। এটি hook এবং skill-কে একত্রিত করে একটি ইনস্টলযোগ্য ইউনিটে পরিণত করে, যার মাধ্যমে একটি টিম প্রতিটি মেশিনে একই guardrail পৌঁছে দেয়: দেখুন Claude Code plugins কীভাবে কাজ করে

শেয়ার্ড VPS-এ নিরাপত্তার সিদ্ধান্ত

হুক (hook) হলো এমন কোড যা এজেন্ট ট্রিগার করে এবং এটি সেই ব্যবহারকারীর পরিচয়ে চলে যিনি Claude Code শুরু করেছেন। এটি সেই ব্যবহারকারীর এনভায়রনমেন্ট এবং ফাইল পারমিশন উত্তরাধিকার সূত্রে পায়। ল্যাপটপের ক্ষেত্রে এটি একটি ওয়ার্কফ্লোর বিষয়। কিন্তু এমন একটি VPS-এ যেখানে এজেন্ট স্বয়ংক্রিয়ভাবে চলে, সেখানে এটি চারটি ব্যবহারিক দিকসহ একটি নিরাপত্তার প্রশ্ন।

রিপোজিটরিতে থাকা হুক আপনার লেখা কোড নয়। .claude/settings.json কমিট করা থাকে, তাই কোনো রিপোজিটরি ক্লোন করে তার ভেতরে সেশন শুরু করলে রিপোজিটরির সাথে আসা হুকগুলো রেজিস্টার হতে পারে। Claude Code প্রজেক্টের হুকগুলোকে সেই ফোল্ডারের জন্য ওয়ার্কস্পেস ট্রাস্ট ডায়ালগের পেছনে আটকে রাখে, যার অর্থ হলো ট্রাস্ট গ্রহণ করার মুহূর্তেই আপনি সেগুলো চালানোর সিদ্ধান্ত নিচ্ছেন। প্রথমে hooks ব্লকটি পড়ুন।

একটি হুক টুলের সম্পূর্ণ ইনপুট দেখতে পায়। একটি অডিট হুক যা tool_input লগ করে, তা প্রতিটি কমান্ডের প্রতিটি আর্গুমেন্ট একটি ফাইলে লিখে রাখে, যার মধ্যে কমান্ড লাইনে থাকা যেকোনো টোকেনও অন্তর্ভুক্ত থাকতে পারে। সেই লগটিকে তখন সিক্রেটের মতোই সুরক্ষা দিতে হবে, যা AI এজেন্টের নাগালের বাইরে সিক্রেট রাখা-এর বৃহত্তর সমস্যার একটি অংশ।

একটি হুক মডেলের কনটেক্সটে লিখতে পারে। একটি SessionStart বা UserPromptSubmit হুক stdout-এ যা কিছু প্রিন্ট করে, তা কথোপকথনে যুক্ত হয়। যে হুক বাইরে থেকে, কোনো ইস্যু ট্র্যাকার বা লগ ফাইল থেকে টেক্সট পাইপ করে, তা মডেলের কাছে এমনভাবে অবিশ্বস্ত টেক্সট পৌঁছে দেয় যেন আপনি নিজেই তা টাইপ করেছেন। সেই stdout-কে আউটপুট হিসেবে না দেখে ইনপুট হিসেবে বিবেচনা করুন।

প্রিভিলেজ বা সুবিধাই হলো আসল নিয়ন্ত্রণ। এজেন্টকে শুধুমাত্র প্রয়োজনীয় sudo রুলসহ একটি ডেডিকেটেড আনপ্রিভিলেজড ব্যবহারকারী হিসেবে চালান। একটি PreToolUse ডিনাই (deny) থাকা ভালো, তবে এটি ডিজাইন অনুযায়ী সর্বোচ্চ প্রচেষ্টার (best effort) ওপর ভিত্তি করে কাজ করে: রেফারেন্সে if ফিল্টার সম্পর্কেও একই কথা বলা হয়েছে এবং যখন আপনার কঠোরভাবে কোনো কিছু নিষিদ্ধ করার প্রয়োজন হয়, তখন পারমিশন সিস্টেম ব্যবহার করতে বলা হয়েছে। পারমিশন রুল এবং যে অ্যাকাউন্টের অধীনে প্রসেসটি চলে, সেগুলোই চাপের মুখে টিকে থাকে।

প্রতিটি কনফিগারেশনেই একটি বৈশিষ্ট্য কার্যকর থাকে। PreToolUse হুকগুলো প্রতিটি পারমিশন মোডে পারমিশন-মোড চেকের আগেই কার্যকর হয়, তাই deny রিটার্ন করা একটি হুক bypassPermissions মোডের অধীনেও টুলটিকে ব্লক করে দেয়। হুকগুলো পারমিশন রুল যা অনুমতি দেয় তাকে আরও কঠোর করতে পারে। কিন্তু তারা সেগুলোকে শিথিল করতে পারে না।

আমার হুক কেন কাজ করছে না?

নিচের ধাপগুলো ক্রমানুসারে অনুসরণ করুন। প্রতিটি ধাপে আপনি যে লক্ষণগুলো দেখতে পাবেন তা উল্লেখ করা হয়েছে।

  • /hooks চালান এবং নিশ্চিত করুন যে হুকটি আপনার প্রত্যাশিত ইভেন্টের অধীনে দেখা যাচ্ছে। মেনুতে হুক না থাকার অর্থ সাধারণত সেটিংস ফাইলে JSON সিনট্যাক্স ত্রুটি রয়েছে, কারণ এতে ট্রেইলিং কমা (trailing commas) বা কমেন্ট ব্যবহারের অনুমতি নেই, অথবা ফাইলটি উপরে উল্লিখিত ছয়টি লোকেশনের কোনোটিতে নেই।
  • টুল নামের সাথে ম্যাচারের তুলনা করুন। ম্যাচারে কেস সেন্সিটিভিটি কাজ করে, তাই "bash" কখনোই Bash টুলের সাথে মিলবে না।
  • উপরের 1 নম্বর উদাহরণের মতো স্যাম্পল ইনপুট দিয়ে স্ক্রিপ্টটি ম্যানুয়ালি চালান। আপনার প্রত্যাশার বাইরের কোনো এক্সিট কোড আসার অর্থ আপনার স্ক্রিপ্টে বাগ রয়েছে এবং Claude Code এটিকে সিদ্ধান্তের পরিবর্তে হুক ত্রুটি হিসেবে রিপোর্ট করে।
  • jq: command not found নোটিশ আসার অর্থ হলো সেই মেশিনে jq অনুপস্থিত। আপনার নিজের স্ক্রিপ্টের জন্য command not found আসার অর্থ হলো পাথটি সঠিকভাবে কাজ করছে না, তাই ${CLAUDE_PROJECT_DIR} অথবা একটি অ্যাবসোলিউট পাথ ব্যবহার করুন। যদি স্ক্রিপ্টটি একেবারেই রান না করে, তবে সম্ভবত এটি এক্সিকিউটেবল নয়।
  • হুকটি বৈধ JSON প্রিন্ট করছে কিন্তু কিছুই ঘটছে না। শেল-ফর্ম হুক sh -c-এর মাধ্যমে চলে, এবং যদি আপনার শেল প্রোফাইল কোনো ব্যানার প্রিন্ট করে, তবে সেই ব্যানারটি আপনার JSON-এর শুরুতে যুক্ত হয়ে যায়। ফলে stdout আর { দিয়ে শুরু হয় না, তাই Claude Code পুরো বিষয়টিকে সাধারণ টেক্সট হিসেবে পড়ে এবং সিদ্ধান্তটিকে উপেক্ষা করে। এক্সিট কোড 0 হলে ডিবাগ লগ ছাড়া কোথাও কিছু রিপোর্ট করা হয় না। আপনার প্রোফাইলের যেকোনো echo-কে এমনভাবে র‍্যাপ করুন যাতে এটি শুধুমাত্র ইন্টারঅ্যাক্টিভ শেলে রান করে।
  • যদি এখনো সমাধান না হয়: claude --debug-file /tmp/claude.log দিয়ে সেশন শুরু করুন এবং দ্বিতীয় একটি টার্মিনালে tail -f /tmp/claude.log চালান। ডিবাগ লগে রেকর্ড থাকবে কোন হুকগুলো ম্যাচ করেছে, প্রতিটি হুক কী এক্সিট কোড দিয়েছে এবং তারা stdout ও stderr-এ কী লিখেছে।

FAQ

Claude Code hook এবং CLAUDE.md instruction-এর মধ্যে পার্থক্য কী?

একটি CLAUDE.md instruction হলো মডেলের context-এ থাকা টেক্সট, তাই এটি কথোপকথন এবং বর্তমান অনুরোধের সাথে মনোযোগের জন্য প্রতিযোগিতা করে এবং মডেল সেগুলোকে বিবেচনায় নিতে পারে। একটি hook হলো এমন একটি shell command যা Claude Code তার lifecycle-এর একটি নির্দিষ্ট বিন্দুতে চালায়, তাই মডেল কী সিদ্ধান্ত নিল তা নির্বিশেষে এটি প্রতিটি ইভেন্টের সময় কার্যকর হয়। কোনো পছন্দের জন্য instruction ব্যবহার করুন। এমন কোনো পদক্ষেপের জন্য hook ব্যবহার করুন যা অবশ্যই ঘটতে হবে অথবা এমন কোনো কাজের জন্য যা কখনোই ঘটা উচিত নয়।

আমি কীভাবে Claude Code-কে একটি নির্দিষ্ট shell command চালানো থেকে বিরত রাখব?

একটি PreToolUse hook-কে একটি Bash matcher-এর সাথে রেজিস্টার করুন যা .tool_input.command থেকে কমান্ডটি পড়ে, stderr-এ একটি কারণ লেখে এবং 2 exit code প্রদান করে। Claude Code কলটি বাতিল করে এবং মডেলকে আপনার কারণটি দেখায়। এটি permission-mode চেক করার আগেই ঘটে, তাই bypassPermissions মোডেও এই নিষেধাজ্ঞা কার্যকর থাকে। কমান্ড স্ট্রিং-এর ওপর pattern matching একটি guardrail, কোনো security boundary নয়। কারণ একই কমান্ড এমনভাবে লেখা সম্ভব যা pattern-টি ধরতে পারে না। তাই এটিকে permission rule এবং একটি unprivileged account-এর মাধ্যমে সুরক্ষিত রাখুন।

আমার hook বৈধ JSON প্রিন্ট করে কিন্তু কিছুই ঘটে না। কেন?

সবচেয়ে সাধারণ কারণ হলো আপনার shell profile। একটি args ফিল্ডবিহীন hook sh -c-এর মাধ্যমে চলে এবং কিছু প্রোফাইল প্রতিটি shell-এ একটি ব্যানার প্রিন্ট করে, যা আপনার JSON-এর আগে stdout-এ চলে আসে। আউটপুটটি { দিয়ে শুরু না হওয়ায়, Claude Code পুরোটিকে সাধারণ টেক্সট হিসেবে গণ্য করে এবং সিদ্ধান্তটি উপেক্ষা করে। exit 0 হলে transcript-এ কিছুই রিপোর্ট করা হয় না। আপনার প্রোফাইলের যেকোনো echo-কে একটি interactive-shell টেস্ট দিয়ে সুরক্ষিত করুন, তারপর claude --debug-file /tmp/claude.log থেকে debug log পড়ে সমাধানটি নিশ্চিত করুন।

একটি shared server-এ Claude Code hook চালানো কি নিরাপদ?

Hook-গুলো সেই ব্যবহারকারীর পরিচয়ে চলে যিনি Claude Code শুরু করেছেন এবং সেই ব্যবহারকারীর file permission ব্যবহার করে। তাই একটি hook সেই account-এর ক্ষমতাপ্রাপ্ত যেকোনো কাজ করতে পারে। দুটি অভ্যাস অধিকাংশ ঝুঁকি কমায়: agent-টিকে একটি নির্দিষ্ট unprivileged account হিসেবে চালান যার sudo পলিসি সীমিত এবং যেকোনো repository-এর workspace trust ডায়ালগ গ্রহণ করার আগে তার hooks ব্লকটি পড়ুন, কারণ project hook-গুলো .claude/settings.json-এর ভেতরে থাকে। আপনি যদি কোনো hook-ই চালাতে না চান, তবে আপনার settings ফাইলে "disableAllHooks": true সেট করুন।