Skip to content

Instantly share code, notes, and snippets.

@ericclemmons
Last active December 19, 2025 05:17
Show Gist options
  • Select an option

  • Save ericclemmons/2a23cc0595c7570fd08f4fa2d3ddef48 to your computer and use it in GitHub Desktop.

Select an option

Save ericclemmons/2a23cc0595c7570fd08f4fa2d3ddef48 to your computer and use it in GitHub Desktop.
#!/usr/bin/env bash
set -euo pipefail
COMMIT_MSG_FILE="$1"
COMMIT_SOURCE="${2-}"
# Allow opting out for a single commit or CI.
if [ "${OPENCODE_COMMIT_MSG_DISABLE:-}" = "1" ]; then
exit 0
fi
# Skip merge/squash/amend flows; they already have meaningful defaults.
case "$COMMIT_SOURCE" in
merge|squash|commit)
exit 0
;;
esac
# If there's already a non-comment, non-empty line, do nothing.
if grep -qvE '^[[:space:]]*($|#)' "$COMMIT_MSG_FILE"; then
exit 0
fi
# Only generate if opencode is available.
if ! command -v opencode >/dev/null 2>&1; then
exit 0
fi
MODEL="${OPENCODE_COMMIT_MODEL:-opencode/grok-code}"
# Write the prompt to a temp file
PROMPT_FILE="$(mktemp)"
cat > "$PROMPT_FILE" <<EOF
Write a git commit message.
Rules:
- Line 1: subject (max 72 chars), imperative mood.
- Then a blank line.
- Then an optional body in Markdown (bullets OK). Keep lines <= 72 chars when possible.
- Output ONLY the commit message. Do not wrap in code fences.
- **DO NOT MAKE ANY TOOL CALLS OR PERFORM ANY GIT OR FILE OPERATIONS**
Context:
Branch: $(git symbolic-ref --quiet --short HEAD 2>/dev/null || echo "DETACHED")
Staged changes (stat):
$(git diff --staged --stat 2>/dev/null || true)
Staged diff:
$(git diff --staged 2>/dev/null | head -c 8000 || true)
If there are no staged changes, still generate a sensible message.
EOF
printf "🤖 Generating default commit message (model: %s)…\n" "$MODEL" >&2
# Run opencode with permissions that deny file/git operations
MESSAGE="$(OPENCODE_PERMISSION='{"bash":"deny","edit":"deny","write":"deny","webfetch":"deny","external_directory":"deny"}' opencode run --model "$MODEL" "$(cat "$PROMPT_FILE")" 2>/dev/null || true)"
rm "$PROMPT_FILE"
# Write the generated message to the commit message file
if [ -n "$MESSAGE" ]; then
MESSAGE="${MESSAGE%$'\n'}"$'\n\n'"🤖 Generated by $MODEL"
ORIGINAL="$(cat "$COMMIT_MSG_FILE")"
printf "%s\n\n%s" "$MESSAGE" "$ORIGINAL" > "$COMMIT_MSG_FILE"
fi
# WORKAROUND: opencode appears to stage files even with bash/edit/write denied
# when run inside a git hook (but not when run manually with the same command).
# This corrupts the git index, causing "invalid object" errors.
# Nuclear fix: rebuild the index from HEAD to unstage any files opencode touched.
#
# 🚨 I've isolated this to **ONLY HAPPEN WHEN OPENCODE EXECUTES INSIDE THE GIT HOOK**
rm -f .git/index
git reset --quiet 2>/dev/null || true
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment