Last active
February 23, 2026 08:54
-
-
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…
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/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 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| { | |
| "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