#!/bin/bash # post-tool-use.sh: Append an audit log entry after every tool call. # # Claude Code calls this script AFTER every tool execution. # The script receives a JSON object on stdin with two fields: # - tool_name: the name of the tool that ran (e.g., "Bash", "Read", "Write") # - tool_input: the arguments passed to the tool # # This script writes one line to hooks/audit.log: # 2026-03-30T04:12:33Z | Bash | ls -la /tmp # # The log is append-only. It grows during the session and persists between sessions. # Read it any time with: cat hooks/audit.log # # Exit code: # 0 Always. This hook does not block anything. # # Make this script executable: chmod +x hooks/post-tool-use.sh # Read the full JSON payload from stdin input=$(cat) # Extract the tool name tool_name=$(echo "$input" | python3 -c "import sys,json; print(json.load(sys.stdin).get('tool_name','unknown'))" 2>/dev/null || echo "unknown") # Extract the most relevant part of the tool input. # Different tools use different argument keys: # Bash -> command # Read -> file_path # Write -> file_path # Grep -> pattern # Fall back to a truncated string representation of the entire input dict. tool_input=$(echo "$input" | python3 -c " import sys, json d = json.load(sys.stdin).get('tool_input', {}) value = d.get('command') or d.get('file_path') or d.get('pattern') or str(d)[:120] print(value) " 2>/dev/null || echo "(parse error)") # Timestamp in UTC ISO 8601 timestamp=$(date -u +"%Y-%m-%dT%H:%M:%SZ") # Write the log directory relative to this script's location. # This keeps the log inside the repo regardless of where Claude Code is invoked from. log_dir="$(dirname "$0")" log_file="$log_dir/audit.log" # Append one line to the log file echo "$timestamp | $tool_name | $tool_input" >> "$log_file" exit 0