Files
claude-code/hooks/scripts/session-end.sh
OpenCode Test f07022ca60 Add SessionEnd hook for automatic session summarization
Implements automatic memory extraction when Claude Code sessions end:
- Add SessionEnd hook to hooks.json with 120s timeout
- Create session-end.sh wrapper that parses hook input and runs summarizer
- Create summarize-transcript.py that:
  - Loads transcript from Claude's storage
  - Skips trivial sessions (<3 user messages)
  - Extracts paths/facts via heuristics
  - Uses Claude CLI (subscription auth) for decisions/preferences
  - Saves to memory files with deduplication
  - Updates history index with summarized flag

Uses `claude -p --model haiku` for LLM extraction, leveraging
existing subscription credentials instead of requiring API key.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-03 14:17:51 -08:00

55 lines
1.8 KiB
Bash
Executable File

#!/bin/bash
# Session end hook - triggers summarization of the conversation
# Receives JSON via stdin with session_id, transcript_path, reason
#
# Uses Claude CLI with subscription credentials for LLM extraction.
# Heuristic extraction (paths, facts) always runs.
# LLM extraction (decisions, preferences) runs if claude CLI is available.
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
LOG_FILE="${HOME}/.claude/logs/session-end.log"
# Ensure log directory exists
mkdir -p "$(dirname "$LOG_FILE")"
log() {
echo "[$(date -Iseconds)] $*" >> "$LOG_FILE"
}
# Read JSON input from stdin
INPUT=$(cat)
# Parse JSON fields
SESSION_ID=$(echo "$INPUT" | python3 -c "import sys, json; print(json.load(sys.stdin).get('session_id', ''))" 2>/dev/null || echo "")
TRANSCRIPT_PATH=$(echo "$INPUT" | python3 -c "import sys, json; print(json.load(sys.stdin).get('transcript_path', ''))" 2>/dev/null || echo "")
REASON=$(echo "$INPUT" | python3 -c "import sys, json; print(json.load(sys.stdin).get('reason', ''))" 2>/dev/null || echo "")
log "SessionEnd triggered: session=$SESSION_ID reason=$REASON"
# Validate required fields
if [[ -z "$SESSION_ID" || -z "$TRANSCRIPT_PATH" ]]; then
log "ERROR: Missing session_id or transcript_path"
exit 0 # Exit cleanly - don't break session exit
fi
# Check if transcript exists
if [[ ! -f "$TRANSCRIPT_PATH" ]]; then
log "ERROR: Transcript not found at $TRANSCRIPT_PATH"
exit 0
fi
# Run summarization script in background to not block session exit
# The script will handle its own error logging
nohup python3 "${SCRIPT_DIR}/summarize-transcript.py" \
--session-id "$SESSION_ID" \
--transcript "$TRANSCRIPT_PATH" \
--reason "$REASON" \
>> "$LOG_FILE" 2>&1 &
log "Summarization started in background (PID: $!)"
# Return success - don't block session exit
exit 0