Skip to main content

Create a Hook

Build an automated guardrail triggered by Copilot session lifecycle events โ€” scanning for secrets, blocking dangerous commands, or enforcing governance.

Prerequisitesโ€‹

  • FrootAI repo cloned
  • Node.js 22+
  • Bash (for hook scripts)

Step 1: Create the Hook Folderโ€‹

HOOK_NAME="fai-my-security-hook"
mkdir -p hooks/${HOOK_NAME}

Step 2: Create hooks.jsonโ€‹

hooks/fai-my-security-hook/hooks.json
{
"version": 1,
"hooks": {
"SessionStart": [
{
"type": "command",
"bash": "./hooks/fai-my-security-hook/check.sh",
"cwd": ".",
"env": {
"HOOK_MODE": "warn"
},
"timeoutSec": 10
}
]
}
}

:::warning Avoid PreToolUse PreToolUse hooks fire on every tool call, adding ~5 seconds of delay each time. Use SessionStart for upfront checks instead. Only use PreToolUse for critical security audits. :::

Step 3: Write the Hook Scriptโ€‹

hooks/fai-my-security-hook/check.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}"
"sk-[a-zA-Z0-9]{48}"
"ghp_[a-zA-Z0-9]{36}"
)

for pattern in "${PATTERNS[@]}"; do
if grep -rqE "$pattern" --include="*.py" --include="*.js" .; 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)"
fi

echo "โœ… Security check passed"
exit 0

Make it executable:

chmod +x hooks/${HOOK_NAME}/check.sh

Step 4: Available Events Referenceโ€‹

EventInputTimeoutUse Case
SessionStartEmpty stdin5sConfig loading, prerequisites
UserPromptSubmitUser prompt on stdin10sPII detection, governance
PreToolUse{"toolName":"...","toolInput":"..."}10sBlock dangerous commands
PostToolUseTool output on stdin10sValidate tool results
PreCompactContext on stdin5sSave critical context
SubagentStartAgent metadata on stdin5sTrack delegation
SubagentStopAgent output on stdin5sValidate sub-agent output
StopSession metadata on stdin30sSecrets scan, audit log

Step 5: Wire into a Manifestโ€‹

fai-manifest.json
{
"primitives": {
"hooks": ["../../hooks/fai-my-security-hook/"]
}
}

Step 6: Validateโ€‹

npm run validate:primitives

# Test the script manually
echo '{"toolName":"test","toolInput":"hello"}' | bash hooks/${HOOK_NAME}/check.sh

Best Practicesโ€‹

  1. Always set a timeout โ€” hooks should not hang the session
  2. Support warn and block modes โ€” let users choose via HOOK_MODE
  3. Exit 0 for pass, exit 1 for block โ€” standard convention
  4. Log clearly โ€” use emoji prefixes (๐Ÿšจ โš ๏ธ โœ…)
  5. Prefer SessionStart โ€” run expensive checks once, not per tool call

See Alsoโ€‹