Skip to main content

Commit Task ID Enforcement Specification

Version: 1.0.0 Status: ACTIVE Created: 2026-01-28 Author: Protocol Specification Agent (T2689)

RFC 2119 Conformance

The key words “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”, “SHOULD NOT”, “RECOMMENDED”, “MAY”, and “OPTIONAL” in this document are to be interpreted as described in RFC 2119.

Part 1: Preamble

1.1 Purpose

This specification defines the commit-msg hook implementation for enforcing task ID inclusion in commit messages, implementing provenance requirements IMPL-003 and CONT-002 from implementation and contribution protocols.

1.2 Evidence Base

  • T2686: Consensus decision (commit-msg hook with session scope, confidence 0.88)
  • T2684: Wave 0 audit (provenance tagging 0% enforcement)
  • Git log analysis: 100% voluntary adoption of (T####) pattern

Part 2: Commit-msg Hook Requirements (CMSG-*)

2.1 Core Hook Behavior

IDRequirementRationale
CMSG-001Hook MUST validate task ID presenceEnforces IMPL-003, CONT-002
CMSG-002Hook MUST accept (T####) patternPreserves existing convention
CMSG-003Hook MUST verify task ID exists via cleo existsPrevents invalid references
CMSG-005Hook MUST be bypassable via git commit --no-verifyEmergency escape hatch
CMSG-007Hook MUST provide auto-suggestion from focus contextDeveloper UX

2.2 Hook Lifecycle

1. Developer writes commit message

2. Git invokes .git/hooks/commit-msg

3. Hook reads commit message from file

4. Pattern extraction: grep -oE '\(T[0-9]+\)'

5. Task ID validation: cleo exists T####
   ├─ PASS → Check session scope → exit 0
   └─ FAIL → Suggest task ID → exit 1

Part 3: Pattern Validation (PATTERN-*)

3.1 Task ID Format

IDRequirementExample
PATTERN-001Hook MUST recognize (T####) format(T2688)
PATTERN-002Hook SHOULD accept task ID anywhere in messagePrefix, suffix, middle
PATTERN-004Hook MUST NOT accept lowercase (t####)Enforce consistency
PATTERN-005Hook MUST NOT accept without parenthesesDistinguish from noise

3.2 Pattern Extraction

Regex: \(T[0-9]+\)
TASK_IDS=$(grep -oE '\(T[0-9]+\)' "$MSG_FILE" | grep -oE 'T[0-9]+')

Part 4: Session Scope Integration (SCOPE-*)

4.1 Session Context

IDRequirement
SCOPE-001Hook SHOULD validate task ID belongs to session scope (Phase 2)
SCOPE-002Hook MUST read CLEO_SESSION environment variable
SCOPE-004Hook SHOULD use cleo focus show for current focused task
SCOPE-006Hook MUST NOT fail if no session is active

4.2 Auto-suggestion Logic

Priority:
  1. Current focused task (cleo focus show)
  2. Session scope tasks (if only one task)
  3. Branch name task ID (feature/T####-*)
  4. No suggestion (generic error)

Part 5: Bypass Policy (BYPASS-*)

5.1 Bypass Conditions

IDRequirementUse Case
BYPASS-001Hook MUST allow bypass via --no-verifyEmergency escape
BYPASS-002Hook MUST log all bypassesAudit trail
BYPASS-004Hook SHOULD auto-bypass merge/revert commitsReduced friction

5.2 Bypass Log Format

{
  "timestamp": "2026-01-28T08:45:00Z",
  "commit": "abc123def456",
  "user": "keaton",
  "message": "emergency fix",
  "justification": "emergency",
  "hook": "commit-msg"
}

Part 6: Installation

6.1 Via cleo init

# Copy hook template
cp .cleo/templates/git-hooks/commit-msg .git/hooks/commit-msg
chmod +x .git/hooks/commit-msg

6.2 Configuration

// .cleo/config.json
{
  "hooks": {
    "commitMsg": {
      "enabled": true,
      "sessionScopeValidation": false,
      "autoSuggestion": true,
      "bypassLogging": true
    }
  }
}

Part 7: Example Hook

#!/usr/bin/env bash
# .git/hooks/commit-msg

MSG_FILE="$1"
COMMIT_MSG=$(cat "$MSG_FILE")

# Extract task ID
TASK_ID=$(echo "$COMMIT_MSG" | grep -oE '\(T[0-9]+\)' | head -1 | grep -oE 'T[0-9]+')

if [[ -z "$TASK_ID" ]]; then
    FOCUSED_TASK=$(cleo focus show --format json 2>/dev/null | jq -r '.task.id // empty')

    if [[ -n "$FOCUSED_TASK" ]]; then
        echo "ERROR: No task ID in commit message"
        echo "Current focus: $FOCUSED_TASK"
        echo "Suggested format: $COMMIT_MSG ($FOCUSED_TASK)"
    else
        echo "WARNING: No task ID and no active focus"
    fi
    exit 1
fi

# Validate task exists
if ! cleo exists "$TASK_ID" >/dev/null 2>&1; then
    echo "ERROR: Task $TASK_ID not found"
    exit 1
fi

echo "✓ Commit linked to $TASK_ID"
exit 0

References