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>
55 lines
1.8 KiB
Bash
Executable File
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
|