#!/bin/bash # Copyright 2026 Marc-Antoine Ruel. All rights reserved. # Use of this source code is governed under the Apache License, Version 2.0 # that can be found in the LICENSE file. # Rejects malformed, overlong, or co-authored commit messages. set -euo pipefail print_commit_guidance() { printf '%s\n' \ 'Commit guidance for coding agents:' \ ' - Use a concise subject no longer than 120 characters.' \ ' - Separate an optional body from the subject with a blank line.' \ ' - When useful, explain the rationale and tradeoffs; do not restate the diff.' >&2 } if (($# != 1)); then printf '%s\n' 'Usage: commit-msg ' >&2 print_commit_guidance exit 2 fi message_file=$1 readonly message_file if [[ ! -f "$message_file" ]]; then printf 'Commit message file does not exist: %s\n' "$message_file" >&2 print_commit_guidance exit 2 fi if grep -Fq '\n' "$message_file"; then printf '%s\n' 'Commit messages must use actual line breaks, not literal \n sequences.' >&2 print_commit_guidance exit 1 fi if grep -Eiq '^co-authored-by: ' "$message_file"; then printf '%s\n' 'Commit messages must not contain Co-authored-by trailers.' >&2 print_commit_guidance exit 1 fi if ! awk ' /^[[:space:]]*#/ { next } !subject { if (NF) subject = 1 next } !separator { if (!NF) { separator = 1 next } invalid_separator = 1 next } END { exit !subject || invalid_separator } ' "$message_file"; then printf '%s\n' 'Commit messages need a subject and a blank line before any body.' >&2 print_commit_guidance exit 1 fi if ! awk ' /^[[:space:]]*#/ { next } NF && length($0) > 120 { printf "Commit message line %d is %d characters; maximum is 120.\n", NR, length($0) > "/dev/stderr" exit 1 } ' "$message_file"; then print_commit_guidance exit 1 fi