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โ
| Event | When It Fires | Recommended Use |
|---|---|---|
SessionStart | Session begins | Load context, check config, verify prerequisites |
UserPromptSubmit | User sends a message | PII detection, governance audit |
PreToolUse | Before tool execution | Block dangerous commands โ ๏ธ |
PostToolUse | After tool execution | Validate tool output |
PreCompact | Before context compaction | Save critical context |
SubagentStart | Sub-agent spawns | Track agent delegation |
SubagentStop | Sub-agent completes | Validate sub-agent output |
Stop | Session ends | Scan 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โ
{
"version": 1,
"hooks": {
"SessionStart": [
{
"type": "command",
"bash": "./hooks/fai-secrets-scanner/scan-secrets.sh",
"cwd": ".",
"env": {
"HOOK_MODE": "warn"
},
"timeoutSec": 10
}
]
}
}
Configuration Fieldsโ
| Field | Required | Description |
|---|---|---|
version | โ | Always 1 |
hooks.<event> | โ | Array of commands for this event |
type | โ | Always "command" |
bash | โ | Path to the script |
cwd | โ | Working directory (usually ".") |
env | No | Environment 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
#!/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โ
| Hook | Event | Purpose |
|---|---|---|
fai-secrets-scanner | Stop | 25+ credential patterns |
fai-tool-guardian | PreToolUse | Block destructive commands |
fai-governance-audit | UserPromptSubmit | Data governance |
fai-license-checker | SessionStart | OSS license compliance |
fai-waf-compliance | Stop | WAF pillar validation |
fai-session-logger | SessionStart + Stop | Audit trail |
fai-cost-tracker | PreToolUse | Token/cost monitoring |
fai-pii-redactor | UserPromptSubmit | PII removal |
fai-token-budget-enforcer | PreToolUse | Token limit enforcement |
fai-output-validator | Stop | Output 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โ
- Always set a timeout โ hooks should never hang the session (10s max for PreToolUse)
- Support both warn and block modes โ let users choose via
HOOK_MODEenv var - Read from stdin โ that's how tool call data arrives for PreToolUse hooks
- Exit 0 for pass, exit 1 for block โ standard convention
- Log clearly โ use emoji prefixes (๐จ โ ๏ธ โ ) for quick scanning
- Prefer SessionStart โ run expensive checks once, not per tool call
- Test with edge cases โ empty input, malformed JSON, unicode
See Alsoโ
- Create a Hook Guide โ step-by-step tutorial
- Plugins โ bundle hooks into distributable packages
- Security WAF โ security pillar guidelines