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 |
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 β documentationhooks.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 0Existing 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 |
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