#!/usr/bin/env bash # Hook: PostToolUse (matcher: Bash) # # Scans bash command output for stack traces and error patterns. # When found, injects a search rubric telling the agent to check mem0 # for prior occurrences of the same error. # # This complements on_user_prompt.sh (which catches errors in the user's # typed message). This hook catches errors in COMMAND OUTPUT — e.g., # when `npm test` or `python script.py` fails with a traceback. # # Input: JSON on stdin with tool_name, tool_input, tool_output # Output: Context injected into Claude's next response (exit 0) set -uo pipefail INPUT=$(cat) TOOL_RESULT=$(echo "$INPUT" | jq -r '.tool_output // ""' 2>/dev/null || echo "") # Skip short output (< 50 chars unlikely to contain a real stack trace) if [ ${#TOOL_RESULT} -lt 50 ]; then exit 0 fi # Skip if this is a git commit (handled by on_post_commit.sh) COMMAND=$(echo "$INPUT" | jq -r '.tool_input.command // ""' 2>/dev/null || echo "") case "$COMMAND" in *"git commit"*|*"git merge"*|*"git rebase"*) exit 0 ;; esac # Detect stack traces and error patterns in command output HAS_ERROR="" if echo "$TOOL_RESULT" | grep -qiE '(Traceback \(most recent|Error:|Exception:|panic:|FAILED|fatal:|FAIL:| at .+\.[a-z]+:[0-9]+|error\[E[0-9]+\])'; then HAS_ERROR="true" fi if [ -z "$HAS_ERROR" ]; then exit 0 fi SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" . "$SCRIPT_DIR/_identity.sh" 2>/dev/null || true if [ -z "${MEM0_API_KEY:-}" ]; then exit 0 fi # Extract error class/message (first matching line) ERROR_LINE=$(echo "$TOOL_RESULT" | grep -iE '(Error:|Exception:|panic:|FAIL:|fatal:)' | head -1 | sed 's/^[[:space:]]*//' | cut -c1-120) # Extract file paths from stack trace frames TRACE_FILES=$(echo "$TOOL_RESULT" | grep -oE '([a-zA-Z0-9_./-]+\.(py|ts|tsx|js|jsx|rs|go|rb|java|sh))(:[0-9]+)?' | head -5 | sort -u) # Build file list for display FILE_DISPLAY="" if [ -n "$TRACE_FILES" ]; then FILE_DISPLAY=$(echo "$TRACE_FILES" | sed 's/^/ - /') fi USER_ID="$MEM0_RESOLVED_USER_ID" cat < $ERROR_LINE EOF if [ -n "$FILE_DISPLAY" ]; then cat </dev/null & exit 0