Automating Claude Code Sessions with Custom Hooks
I recently set up two hooks for Claude Code that have transformed my development workflow. Here's how I configured automatic version control checkpoints and real-time notifications for my coding sessions.
The Setup
My hook configuration lives in .claude/settings.json
and consists of two main components:
{
"hooks": {
"Stop": [
{
"matcher": "",
"hooks": [
{
"type": "command",
"command": "/Users/dimitri.missoh/.claude/create-jj-checkpoint.sh"
}
]
}
],
"PostToolUse": [
{
"matcher": "Bash|Edit|MultiEdit|Write",
"hooks": [
{
"type": "command",
"command": "jq -r '\"\\(.tool_input.command // \"\") - \\(.tool_input.description // \"\") - \\(.tool_response.stdout // \"\") - \\(.tool_response.content // \"\")\"' | /Users/dimitri.missoh/.claude/notification.sh"
}
]
}
]
}
}
1. Automatic Jujutsu Checkpoints on Session Stop
When I end a Claude Code session, the Stop
hook automatically creates a Jujutsu (jj) checkpoint of my work. This ensures I never lose changes between sessions.
The hook triggers create-jj-checkpoint.sh
, which performs these steps:
# Get working directory from Claude environment or fallback to PWD
WORK_DIR="${CLAUDE_WORKING_DIRECTORY:-${PWD:-$(pwd)}}"
# Check if jj is installed and we're in a jj repository
if ! command -v jj >/dev/null 2>&1; then
echo "Warning: jj (Jujutsu) is not installed. Skipping checkpoint."
exit 0
fi
# Check for changes using jj diff and status
JJ_DIFF=$(jj diff --stat 2>&1)
JJ_STATUS=$(jj status --no-pager 2>&1)
# Skip if working copy is clean
if echo "$JJ_STATUS" | grep -q "working copy is clean"; then
echo "No changes detected. Skipping checkpoint."
exit 0
fi
# Create checkpoint with timestamp and session ID
TIMESTAMP=$(date "+%Y-%m-%d %H:%M:%S")
DESCRIPTION="Code checkpoint - $TIMESTAMP (session: ${CLAUDE_SESSION_ID:-unknown})"
jj new
jj describe -m "$DESCRIPTION"
Key features:
- Gracefully handles non-jj repositories
- Skips checkpoints when there are no changes
- Maintains a rotating log of the last 10 operations
- Includes session metadata in commit messages
2. Real-Time Notifications for Tool Operations
The PostToolUse
hook fires after specific tool operations (Bash, Edit, MultiEdit, Write) and sends Mac notifications about completed tasks.
The notification pipeline:
- Captures tool input/output to a temporary file
- Extracts command details, descriptions, and results using
jq
- Sends a notification via
terminal-notifier
with a fun frog sound
The notification script (notification.sh
) is simple but effective:
#!/bin/bash
MESSAGE=$1
# Show Mac notifications using terminal-notifier
echo "${MESSAGE}" | terminal-notifier -title "Assisted Job Done!" -sound frog
This keeps me informed about what Claude is doing, especially during long-running operations or when I'm multitasking.
Prerequisites
To use this setup, you'll need to install:
-
Jujutsu (jj) - A Git-compatible version control system
- Install via Homebrew:
brew install jj
- Or visit: https://github.com/martinvonz/jj
- For Git repos, run
jj git colocate
to enable jj alongside Git
- Install via Homebrew:
-
terminal-notifier - Command-line tool for macOS notifications
- Install via Homebrew:
brew install terminal-notifier
- Or visit: https://github.com/julienXX/terminal-notifier
- Install via Homebrew:
Why This Works
The combination creates a seamless development experience:
- Never lose work: Automatic checkpoints capture every coding session
- Stay informed: Desktop notifications for completed operations
- Zero friction: Everything happens automatically in the background
- Full visibility: Detailed logs help debug any issues
The hooks respect my workflow - they only checkpoint when there are actual changes and handle edge cases gracefully. The notification system keeps me in the loop without being intrusive.
This setup has become an essential part of my Claude Code workflow, providing both safety nets and real-time awareness of AI-assisted development progress.
Dimitri Missoh | 2025-07-27