Skip to main content

Hooks

Hooks are automated checks that run at specific points during a Copilot session. They provide guardrails โ€” scanning for secrets, blocking dangerous commands, detecting PII, and enforcing governance policies.

Available Eventsโ€‹

EventWhen It FiresRecommended Use
SessionStartSession beginsLoad context, check config, verify prerequisites
UserPromptSubmitUser sends a messagePII detection, governance audit
PreToolUseBefore tool executionBlock dangerous commands โš ๏ธ
PostToolUseAfter tool executionValidate tool output
PreCompactBefore context compactionSave critical context
SubagentStartSub-agent spawnsTrack agent delegation
SubagentStopSub-agent completesValidate sub-agent output
StopSession endsScan for leaked secrets, audit logging

:::warning Never Use PreToolUse in Production PreToolUse hooks spawn a process for every tool call, adding ~5 seconds of delay each time. Use SessionStart for upfront validation instead. Only use PreToolUse during development or security audits where the delay is acceptable. :::

Folder Structureโ€‹

Every hook lives in its own folder under hooks/:

hooks/
fai-secrets-scanner/
hooks.json # Required โ€” event configuration
scan-secrets.sh # Required โ€” the script to execute
README.md # Recommended โ€” documentation

hooks.json Configurationโ€‹

hooks/fai-secrets-scanner/hooks.json
{
"version": 1,
"hooks": {
"SessionStart": [
{
"type": "command",
"bash": "./hooks/fai-secrets-scanner/scan-secrets.sh",
"cwd": ".",
"env": {
"HOOK_MODE": "warn"
},
"timeoutSec": 10
}
]
}
}

Configuration Fieldsโ€‹

FieldRequiredDescription
versionโœ…Always 1
hooks.<event>โœ…Array of commands for this event
typeโœ…Always "command"
bashโœ…Path to the script
cwdโœ…Working directory (usually ".")
envNoEnvironment variables passed to script
timeoutSecโœ…Max seconds before kill (5โ€“60)

Writing Hook Scriptsโ€‹

Hook scripts receive input on stdin and communicate results via exit codes:

  • Exit 0 โ€” check passed, allow action to proceed
  • Exit 1 โ€” check failed, block the action
hooks/fai-secrets-scanner/scan-secrets.sh
#!/usr/bin/env bash
set -euo pipefail

MODE="${HOOK_MODE:-warn}"
FINDINGS=0

# Scan for common secret patterns
PATTERNS=(
"AKIA[0-9A-Z]{16}" # AWS access key
"sk-[a-zA-Z0-9]{48}" # OpenAI API key
"ghp_[a-zA-Z0-9]{36}" # GitHub PAT
"password\s*=\s*['\"][^'\"]+['\"]" # Hardcoded passwords
)

for pattern in "${PATTERNS[@]}"; do
if grep -rqE "$pattern" --include="*.py" --include="*.js" --include="*.ts" .; then
echo "๐Ÿšจ Secret pattern detected: $pattern"
FINDINGS=$((FINDINGS + 1))
fi
done

if [ "$FINDINGS" -gt 0 ]; then
if [ "$MODE" = "block" ]; then
echo "โŒ Blocked: $FINDINGS secret(s) found"
exit 1
fi
echo "โš ๏ธ Warning: $FINDINGS potential secret(s) found"
fi

echo "โœ… Secrets scan passed"
exit 0

Existing FrootAI Hooksโ€‹

HookEventPurpose
fai-secrets-scannerStop25+ credential patterns
fai-tool-guardianPreToolUseBlock destructive commands
fai-governance-auditUserPromptSubmitData governance
fai-license-checkerSessionStartOSS license compliance
fai-waf-complianceStopWAF pillar validation
fai-session-loggerSessionStart + StopAudit trail
fai-cost-trackerPreToolUseToken/cost monitoring
fai-pii-redactorUserPromptSubmitPII removal
fai-token-budget-enforcerPreToolUseToken limit enforcement
fai-output-validatorStopOutput quality checking

:::tip Recommended: SessionStart SessionStart is the safest and fastest event. Use it for prerequisite checks, configuration loading, and initial security scans. It fires only once per session with no performance penalty. :::

Wiring Hooks into Playsโ€‹

Reference hooks in fai-manifest.json:

{
"primitives": {
"hooks": [
"../../hooks/fai-secrets-scanner/",
"../../hooks/fai-tool-guardian/"
]
}
}

Or in a plugin's plugin.json:

{
"hooks": ["../../hooks/fai-secrets-scanner/"]
}

Best Practicesโ€‹

  1. Always set a timeout โ€” hooks should never hang the session (10s max for PreToolUse)
  2. Support both warn and block modes โ€” let users choose via HOOK_MODE env var
  3. Read from stdin โ€” that's how tool call data arrives for PreToolUse hooks
  4. Exit 0 for pass, exit 1 for block โ€” standard convention
  5. Log clearly โ€” use emoji prefixes (๐Ÿšจ โš ๏ธ โœ…) for quick scanning
  6. Prefer SessionStart โ€” run expensive checks once, not per tool call
  7. Test with edge cases โ€” empty input, malformed JSON, unicode

See Alsoโ€‹