Skip to content

Instantly share code, notes, and snippets.

@searls
Last active February 23, 2026 08:54
Show Gist options
  • Select an option

  • Save searls/841837b0e3ecd0461c292a0d1639a49f to your computer and use it in GitHub Desktop.

Select an option

Save searls/841837b0e3ecd0461c292a0d1639a49f to your computer and use it in GitHub Desktop.
I got sick of trying to figure out the best time to commit code between me and Claude. I simultaneously found bugs in Claude's checkpoint and rewind system. So now I just auto-commit on every turn with the title being whatever claude just said and the body being whatever my prompt was. (I also often want to go back and replay my prompts when Cla…
#!/bin/bash
# Auto commits after each Claude turn if:
# - A STOP hook is configured that runs this script
# - A <repo_root>.claude/auto_commit.json file has key "enabled" set to `true`
set -euo pipefail
INPUT=$(cat)
# Find git root; bail if not a repo
GIT_ROOT=$(git rev-parse --show-toplevel 2>/dev/null) || exit 0
# Check .claude/auto_commit.json opt-in
CONFIG="$GIT_ROOT/.claude/auto_commit.json"
if [ ! -f "$CONFIG" ]; then exit 0; fi
ENABLED=$(jq -r '.enabled // false' "$CONFIG" 2>/dev/null)
if [ "$ENABLED" != "true" ]; then exit 0; fi
# Don't commit during a stop-hook continuation
STOP_ACTIVE=$(echo "$INPUT" | jq -r '.stop_hook_active // false')
if [ "$STOP_ACTIVE" = "true" ]; then exit 0; fi
# Bail if nothing changed
git -C "$GIT_ROOT" diff --quiet HEAD 2>/dev/null \
&& git -C "$GIT_ROOT" diff --cached --quiet 2>/dev/null \
&& exit 0
# Extract user prompt and assistant summary from transcript
TRANSCRIPT=$(echo "$INPUT" | jq -r '.transcript_path // empty')
HEADLINE=""
BODY=""
if [ -n "$TRANSCRIPT" ] && [ -f "$TRANSCRIPT" ]; then
PROMPT=$(jq -rs '
[.[] | select(.type=="user" and (.message.content | type == "string"))]
| last
| .message.content // empty
' "$TRANSCRIPT" 2>/dev/null || true)
RESPONSE=$(jq -rs '
[.[] | select(.type=="assistant")]
| last
| [.message.content[] | select(.type=="text") | .text]
| join("")
' "$TRANSCRIPT" 2>/dev/null || true)
HEADLINE=$(echo "$PROMPT" | head -1 | head -c 72)
fi
# Fallbacks
[ -z "$HEADLINE" ] && HEADLINE="auto-commit $(date +%Y-%m-%d\ %H:%M)"
[ -z "$PROMPT" ] && PROMPT="(no prompt)"
[ -z "$RESPONSE" ] && RESPONSE="(no response)"
BODY=$(printf '> %s\n\nResponse:\n%s' "$PROMPT" "$RESPONSE")
git -C "$GIT_ROOT" add -A
git -C "$GIT_ROOT" commit -m "$HEADLINE" -m "$BODY" --no-verify || true
{
"hooks": {
"Stop": [
{
"hooks": [
{
"type": "command",
"command": "~/.claude/hooks/auto_commit.sh"
}
]
}
],
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment