#!/usr/bin/env pwsh # session-handoff PostToolUse hook (PowerShell). # # Reads PostToolUse JSON from stdin, detects whether the just-completed # Bash tool call was a substantive `git commit`, and on hit emits JSON to # stdout with `additionalContext` so Claude Code surfaces a system reminder # in the next agent iteration ("substantive commit — consider session-handoff # write-mode"). # # Substantive heuristic (mirrors session-handoff SKILL.md): # prefix NOT in (meta:|docs:|style:|chore:|fix typo) AND # (body > 200 chars OR files > 3) # # Silent skip on: malformed JSON, no command, --amend, failed commit, # non-git cwd, trivial prefix, below thresholds. Never blocks the tool call # (PostToolUse cannot, by design). $ErrorActionPreference = 'Stop' # Read stdin try { $raw = [Console]::In.ReadToEnd() if ([string]::IsNullOrWhiteSpace($raw)) { exit 0 } $hook = $raw | ConvertFrom-Json -ErrorAction Stop } catch { exit 0 } # Only Bash tool, only git commit (not --amend) $cmd = $hook.tool_input.command if (-not $cmd) { exit 0 } if ($cmd -notmatch '(?$null if ($inside -ne 'true') { exit 0 } # Parse last commit $subject = (& git -C $cwd log -1 --format='%s').Trim() # PowerShell collapses multi-line subprocess output into string[] — join back so # .Length below is char count, not line count. $body = ((& git -C $cwd log -1 --format='%b') -join "`n") $files = ((& git -C $cwd diff-tree --no-commit-id --name-only -r HEAD) | Measure-Object).Count # Trivial-prefix check (Conventional Commits prefix before optional scope + colon) $prefix = $subject -replace '^([a-z]+)(\([^)]+\))?:.*$','$1' $trivial = @('meta','docs','style','chore') if ($trivial -contains $prefix) { exit 0 } if ($subject -match 'fix\s+typo') { exit 0 } # Threshold check (chars for body, count for files) $bodyLen = if ($body) { $body.Length } else { 0 } if ($bodyLen -le 200 -and $files -le 3) { exit 0 } # Substantive — emit JSON $msg = "Substantive commit detected on " + $cwd + ": ``" + $subject + "`` (" + $files + " files changed, body " + $bodyLen + " chars). Consider invoking session-handoff write-mode to update .tasks/NEXT_SESSION.md." @{ hookSpecificOutput = @{ hookEventName = 'PostToolUse' additionalContext = $msg } systemMessage = 'session-handoff: substantive commit detected' suppressOutput = $false } | ConvertTo-Json -Compress -Depth 5 | Write-Output