-
Notifications
You must be signed in to change notification settings - Fork 520
Closed
Labels
bugSomething isn't workingSomething isn't workingduplicateThis issue or pull request already existsThis issue or pull request already exists
Description
Description:
I'm attempting to use hooks in the claude_agent_sdk to validate and log tool usage, but the hooks don't seem to be triggered at all. The code is based on the official example provided in the documentation: .
https://docs.claude.com/en/api/agent-sdk/python#hook-usage-example
Code Example:
from claude_agent_sdk import query, ClaudeAgentOptions, HookMatcher, HookContext
from typing import Any
import asyncio
import env_setup
env_setup.setup_anthropic_env()
async def validate_bash_command(
input_data: dict[str, Any],
tool_use_id: str | None,
context: HookContext
) -> dict[str, Any]:
"""Validate and potentially block dangerous bash commands."""
if input_data['tool_name'] == 'Bash':
command = input_data['tool_input'].get('command', '')
if 'rm -rf /' in command:
return {
'hookSpecificOutput': {
'hookEventName': 'PreToolUse',
'permissionDecision': 'deny',
'permissionDecisionReason': 'Dangerous command blocked'
}
}
return {}
async def log_tool_use(
input_data: dict[str, Any],
tool_use_id: str | None,
context: HookContext
) -> dict[str, Any]:
"""Log all tool usage for auditing."""
print(f"Tool used: {input_data.get('tool_name')}")
return {}
async def main():
options = ClaudeAgentOptions(
hooks={
'PreToolUse': [
HookMatcher(matcher='Bash', hooks=[validate_bash_command]),
HookMatcher(hooks=[log_tool_use]) # Applies to all tools
],
'PostToolUse': [
HookMatcher(hooks=[log_tool_use])
]
}
)
async for message in query(
prompt="Analyze this codebase",
options=options
):
print(message)
asyncio.run(main())
Expected Behavior:
validate_bash_command should run before executing the Bash tool.
log_tool_use should run before and after any tool usage.
Actual Behavior:
Hooks are not executed at all. No logging appears, and dangerous commands are not blocked.
Environment:
Python version: [e.g., 3.11]
claude_agent_sdk version: [0.1.1 & 0.1.0]
OS: [macOS]
Program some OUTPUT:
SystemMessage(subtype='init', data={'type': 'system', 'subtype': 'init', 'cwd': '/Users/zhangyongqiang01/Desktop/code/test/python/claude-code-sdk', 'session_id': '158badd7-7b61-412f-8cac-d7c3a6be3952', 'tools': ['Task', 'Bash', 'Glob', 'Grep', 'ExitPlanMode', 'Read', 'Edit', 'Write', 'NotebookEdit', 'WebFetch', 'TodoWrite', 'WebSearch', 'BashOutput', 'KillShell', 'SlashCommand'], 'mcp_servers': [], 'model': 'k2', 'permissionMode': 'default', 'slash_commands': ['compact', 'context', 'cost', 'init', 'output-style:new', 'pr-comments', 'release-notes', 'todos', 'review', 'security-review'], 'apiKeySource': 'none', 'output_style': 'default', 'agents': ['general-purpose', 'statusline-setup', 'output-style-setup'], 'uuid': 'ca7ce821-afb2-48e0-8a67-f32879155df2'})
AssistantMessage(content=[TextBlock(text="I'll analyze the codebase for you. Let me start by exploring the directory structure and understanding what this project contains.")], model='k2', parent_tool_use_id=None)
AssistantMessage(content=[ToolUseBlock(id='functions.TodoWrite:0', name='TodoWrite', input={'todos': [{'id': '1', 'task': 'Explore directory structure and identify project type', 'status': 'pending'}, {'id': '2', 'task': 'Analyze key configuration files (package.json, requirements.txt, etc.)', 'status': 'pending'}, {'id': '3', 'task': 'Examine source code structure and main components', 'status': 'pending'}, {'id': '4', 'task': 'Identify dependencies and frameworks used', 'status': 'pending'}, {'id': '5', 'task': 'Summarize findings and project characteristics', 'status': 'pending'}]})], model='k2', parent_tool_use_id=None)
UserMessage(content=[ToolResultBlock(tool_use_id='functions.TodoWrite:0', content='<tool_use_error>InputValidationError: TodoWrite failed due to the following issues:\nThe required parameter `todos[0].content` is missing\nThe required parameter `todos[0].activeForm` is missing\nThe required parameter `todos[1].content` is missing\nThe required parameter `todos[1].activeForm` is missing\nThe required parameter `todos[2].content` is missing\nThe required parameter `todos[2].activeForm` is missing\nThe required parameter `todos[3].content` is missing\nThe required parameter `todos[3].activeForm` is missing\nThe required parameter `todos[4].content` is missing\nThe required parameter `todos[4].activeForm` is missing</tool_use_error>', is_error=True)], parent_tool_use_id=None)
AssistantMessage(content=[ToolUseBlock(id='functions.TodoWrite:1', name='TodoWrite', input={'todos': [{'id': '1', 'task': 'Explore directory structure and identify project type', 'content': 'Explore directory structure and identify project type', 'activeForm': 'text'}, {'id': '2', 'task': 'Analyze key configuration files (package.json, requirements.txt, etc.)', 'content': 'Analyze key configuration files (package.json, requirements.txt, etc.)', 'activeForm': 'text'}, {'id': '3', 'task': 'Examine source code structure and main components', 'content': 'Examine source code structure and main components', 'activeForm': 'text'}, {'id': '4', 'task': 'Identify dependencies and frameworks used', 'content': 'Identify dependencies and frameworks used', 'activeForm': 'text'}, {'id': '5', 'task': 'Summarize findings and project characteristics', 'content': 'Summarize findings and project characteristics', 'activeForm': 'text'}]})], model='k2', parent_tool_use_id=None)
UserMessage(content=[ToolResultBlock(tool_use_id='functions.TodoWrite:1', content='<tool_use_error>InputValidationError: TodoWrite failed due to the following issues:\nThe required parameter `todos[0].status` is missing\nThe required parameter `todos[1].status` is missing\nThe required parameter `todos[2].status` is missing\nThe required parameter `todos[3].status` is missing\nThe required parameter `todos[4].status` is missing</tool_use_error>', is_error=True)], parent_tool_use_id=None)
AssistantMessage(content=[ToolUseBlock(id='functions.TodoWrite:2', name='TodoWrite', input={'todos': [{'id': '1', 'task': 'Explore directory structure and identify project type', 'content': 'Explore directory structure and identify project type', 'activeForm': 'text', 'status': 'pending'}, {'id': '2', 'task': 'Analyze key configuration files (package.json, requirements.txt, etc.)', 'content': 'Analyze key configuration files (package.json, requirements.txt, etc.)', 'activeForm': 'text', 'status': 'pending'}, {'id': '3', 'task': 'Examine source code structure and main components', 'content': 'Examine source code structure and main components', 'activeForm': 'text', 'status': 'pending'}, {'id': '4', 'task': 'Identify dependencies and frameworks used', 'content': 'Identify dependencies and frameworks used', 'activeForm': 'text', 'status': 'pending'}, {'id': '5', 'task': 'Summarize findings and project characteristics', 'content': 'Summarize findings and project characteristics', 'activeForm': 'text', 'status': 'pending'}]})], model='k2', parent_tool_use_id=None)
UserMessage(content=[ToolResultBlock(tool_use_id='functions.TodoWrite:2', content='Todos have been modified successfully. Ensure that you continue to use the todo list to track your progress. Please proceed with the current tasks if applicable', is_error=None)], parent_tool_use_id=None)
AssistantMessage(content=[ToolUseBlock(id='functions.TodoWrite:3', name='TodoWrite', input={'todos': [{'id': '1', 'task': 'Explore directory structure and identify project type', 'content': 'Explore directory structure and identify project type', 'activeForm': 'text', 'status': 'in_progress'}, {'id': '2', 'task': 'Analyze key configuration files (package.json, requirements.txt, etc.)', 'content': 'Analyze key configuration files (package.json, requirements.txt, etc.)', 'activeForm': 'text', 'status': 'pending'}, {'id': '3', 'task': 'Examine source code structure and main components', 'content': 'Examine source code structure and main components', 'activeForm': 'text', 'status': 'pending'}, {'id': '4', 'task': 'Identify dependencies and frameworks used', 'content': 'Identify dependencies and frameworks used', 'activeForm': 'text', 'status': 'pending'}, {'id': '5', 'task': 'Summarize findings and project characteristics', 'content': 'Summarize findings and project characteristics', 'activeForm': 'text', 'status': 'pending'}]})], model='k2', parent_tool_use_id=None)
UserMessage(content=[ToolResultBlock(tool_use_id='functions.TodoWrite:3', content='Todos have been modified successfully. Ensure that you continue to use the todo list to track your progress. Please proceed with the current tasks if applicable', is_error=None)], parent_tool_use_id=None)
AssistantMessage(content=[ToolUseBlock(id='functions.LS:4', name='LS', input={'path': '/Users/zhangyongqiang01/Desktop/code/test/python/claude-code-sdk'})], model='k2', parent_tool_use_id=None)
UserMessage(content=[ToolResultBlock(tool_use_id='functions.LS:4', content='<tool_use_error>Error: No such tool available: LS</tool_use_error>', is_error=True)], parent_tool_use_id=None)
AssistantMessage(content=[ToolUseBlock(id='functions.Bash:5', name='Bash', input={'command': 'ls -la /Users/zhangyongqiang01/Desktop/code/test/python/claude-code-sdk'})], model='k2', parent_tool_use_id=None)
UserMessage(content=[ToolResultBlock(tool_use_id='functions.Bash:5', content='total 96\ndrwxr-xr-x 17 zhangyongqiang01 staff 544 10 7 14:49 .\ndrwxr-xr-x 3 zhangyongqiang01 staff 96 9 28 20:02 ..\ndrwxr-xr-x 4 zhangyongqiang01 staff 128 9 29 16:33 .vscode\ndrwxr-xr-x 3 zhangyongqiang01 staff 96 9 29 17:41 __pycache__\n-rw-r--r-- 1 zhangyongqiang01 staff 1432 10 7 13:48 advanced_permission_control.py\n-rw-r--r-- 1 zhangyongqiang01 staff 432 9 29 19:43 claude_sdk_client.py\n-rw-r--r-- 1 zhangyongqiang01 staff 1449 9 29 19:46 continue_conversation.py\n-rw-r--r-- 1 zhangyongqiang01 staff 418 9 29 10:52 env_setup.py\n-rw-r--r-- 1 zhangyongqiang01 staff 1562 10 7 15:22 hook_use_example.py\n-rw-r--r-- 1 zhangyongqiang01 staff 783 9 29 10:47 mcp_server.py\n-rw-r--r-- 1 zhangyongqiang01 staff 530 9 29 10:53 query.py\ndrwxr-xr-x 3 zhangyongqiang01 staff 96 9 28 20:20 runtime\n-rw-r--r-- 1 zhangyongqiang01 staff 3324 9 30 15:58 streaming_input.py\n-rw-r--r-- 1 zhangyongqiang01 staff 3939 9 29 16:39 test_asyncio.py\n-rw-r--r-- 1 zhangyongqiang01 staff 1518 9 29 17:22 test_asyncio_2.py\n-rw-r--r-- 1 zhangyongqiang01 staff 285 9 29 16:30 tool.py\n-rw-r--r-- 1 zhangyongqiang01 staff 1193 10 7 13:45 use_interrupts.py', is_error=False)], parent_tool_use_id=None)
AssistantMessage(content=[ToolUseBlock(id='functions.Bash:6', name='Bash', input={'command': 'find /Users/zhangyongqiang01/Desktop/code/test/python/claude-code-sdk -name "*.py" | head -10'})], model='k2', parent_tool_use_id=None)
UserMessage(content=[ToolResultBlock(tool_use_id='functions.Bash:6', content='/Users/zhangyongqiang01/Desktop/code/test/python/claude-code-sdk/use_interrupts.py\n/Users/zhangyongqiang01/Desktop/code/test/python/claude-code-sdk/test_asyncio_2.py\n/Users/zhangyongqiang01/Desktop/code/test/python/claude-code-sdk/query.py\n/Users/zhangyongqiang01/Desktop/code/test/python/claude-code-sdk/runtime/web_server.py\n/Users/zhangyongqiang01/Desktop/code/test/python/claude-code-sdk/env_setup.py\n/Users/zhangyongqiang01/Desktop/code/test/python/claude-code-sdk/test_asyncio.py\n/Users/zhangyongqiang01/Desktop/code/test/python/claude-code-sdk/continue_conversation.py\n/Users/zhangyongqiang01/Desktop/code/test/python/claude-code-sdk/streaming_input.py\n/Users/zhangyongqiang01/Desktop/code/test/python/claude-code-sdk/hook_use_example.py\n/Users/zhangyongqiang01/Desktop/code/test/python/claude-code-sdk/tool.py', is_error=False)], parent_tool_use_id=None)
AssistantMessage(content=[ToolUseBlock(id='functions.Bash:7', name='Bash', input={'command': 'find /Users/zhangyongqiang01/Desktop/code/test/python/claude-code-sdk -name "requirements.txt" -o -name "setup.py" -o -name "pyproject.toml" -o -name "Pipfile" -o -name "environment.yml"'})], model='k2', parent_tool_use_id=None)
UserMessage(content=[ToolResultBlock(tool_use_id='functions.Bash:7', content='', is_error=False)], parent_tool_use_id=None)
AssistantMessage(content=[ToolUseBlock(id='functions.Read:8', name='Read', input={'path': '/Users/zhangyongqiang01/Desktop/code/test/python/claude-code-sdk/claude_sdk_client.py'})], model='k2', parent_tool_use_id=None)
UserMessage(content=[ToolResultBlock(tool_use_id='functions.Read:8', content='<tool_use_error>InputValidationError: Read failed due to the following issues:\nThe required parameter `file_path` is missing\nAn unexpected parameter `path` was provided</tool_use_error>', is_error=True)], parent_tool_use_id=None)
Metadata
Metadata
Assignees
Labels
bugSomething isn't workingSomething isn't workingduplicateThis issue or pull request already existsThis issue or pull request already exists