In diesem Referenzartikel werden die verfügbaren Hooktypen mit Beispielen beschrieben, einschließlich ihrer Eingabe- und Ausgabeformate, bewährten Skriptmethoden und erweiterten Mustern für Protokollierung, Sicherheitserzwingung und externe Integrationen. Allgemeine Informationen zum Erstellen von Hooks finden Sie unter Verwenden von Hooks mit GitHub Copilot-Agenten.
Hook-Typen
Sitzungsstart-Hook
Wird ausgeführt, wenn eine neue Agentsitzung beginnt oder wenn eine vorhandene Sitzung fortgesetzt wird.
**Eingabe-JSON:**
{
"timestamp": 1704614400000,
"cwd": "/path/to/project",
"source": "new",
"initialPrompt": "Create a new feature"
}
{
"timestamp": 1704614400000,
"cwd": "/path/to/project",
"source": "new",
"initialPrompt": "Create a new feature"
}
**Felder:**
*
timestamp: Unix-Zeitstempel in Millisekunden
*
cwd: Aktuelles Arbeitsverzeichnis
*
source: Entweder "new" (neue Sitzung), "resume" (fortgesetzte Sitzung) oder "startup"
*
initialPrompt: Die anfängliche Eingabeaufforderung des Benutzers (sofern angegeben)
**Ausgabe:** Ignoriert (kein Rückgabewert verarbeitet)
**Beispiel-Hook:**
{
"type": "command",
"bash": "./scripts/session-start.sh",
"powershell": "./scripts/session-start.ps1",
"cwd": "scripts",
"timeoutSec": 30
}
{
"type": "command",
"bash": "./scripts/session-start.sh",
"powershell": "./scripts/session-start.ps1",
"cwd": "scripts",
"timeoutSec": 30
}
**Beispielskript (Bash):**
#!/bin/bash INPUT=$(cat) SOURCE=$(echo "$INPUT" | jq -r '.source') TIMESTAMP=$(echo "$INPUT" | jq -r '.timestamp') echo "Session started from $SOURCE at $TIMESTAMP" >> session.log
#!/bin/bash
INPUT=$(cat)
SOURCE=$(echo "$INPUT" | jq -r '.source')
TIMESTAMP=$(echo "$INPUT" | jq -r '.timestamp')
echo "Session started from $SOURCE at $TIMESTAMP" >> session.log
Sitzungsende-Hook
Wird ausgeführt, wenn die Agentsitzung abgeschlossen oder beendet wird.
**Eingabe-JSON:**
{
"timestamp": 1704618000000,
"cwd": "/path/to/project",
"reason": "complete"
}
{
"timestamp": 1704618000000,
"cwd": "/path/to/project",
"reason": "complete"
}
**Felder:**
*
timestamp: Unix-Zeitstempel in Millisekunden
*
cwd: Aktuelles Arbeitsverzeichnis
*
reason: Eine von "complete", , "error"``"abort", , oder "timeout"``"user_exit"
**Ausgabe:** Ignoriert
**Beispielskript:**
#!/bin/bash INPUT=$(cat) REASON=$(echo "$INPUT" | jq -r '.reason') echo "Session ended: $REASON" >> session.log # Cleanup temporary files rm -rf /tmp/session-*
#!/bin/bash
INPUT=$(cat)
REASON=$(echo "$INPUT" | jq -r '.reason')
echo "Session ended: $REASON" >> session.log
# Cleanup temporary files
rm -rf /tmp/session-*
Gesendeter Webhook der Benutzeranfrage
Wird ausgeführt, wenn der Benutzer eine Eingabeaufforderung an den Agent sendet.
**Eingabe-JSON:**
{
"timestamp": 1704614500000,
"cwd": "/path/to/project",
"prompt": "Fix the authentication bug"
}
{
"timestamp": 1704614500000,
"cwd": "/path/to/project",
"prompt": "Fix the authentication bug"
}
**Felder:**
*
timestamp: Unix-Zeitstempel in Millisekunden
*
cwd: Aktuelles Arbeitsverzeichnis
*
prompt: Der genaue Text, den der Benutzer übermittelt hat
**Ausgabe:** Ignoriert (Eingabeaufforderungsänderung wird derzeit in Kunden-Hooks nicht unterstützt)
**Beispielskript:**
#!/bin/bash INPUT=$(cat) PROMPT=$(echo "$INPUT" | jq -r '.prompt') TIMESTAMP=$(echo "$INPUT" | jq -r '.timestamp') # Log to a structured file echo "$(date -d @$((TIMESTAMP/1000))): $PROMPT" >> prompts.log
#!/bin/bash
INPUT=$(cat)
PROMPT=$(echo "$INPUT" | jq -r '.prompt')
TIMESTAMP=$(echo "$INPUT" | jq -r '.timestamp')
# Log to a structured file
echo "$(date -d @$((TIMESTAMP/1000))): $PROMPT" >> prompts.log
Haken zur Verwendung vor Werkzeugen
Wird ausgeführt, bevor der Agent ein beliebiges Tool verwendet (z. B. bash, edit, view). Dies ist der leistungsfähigste Hook, da er Toolausführungen genehmigen oder verweigern kann.
**Eingabe-JSON:**
{
"timestamp": 1704614600000,
"cwd": "/path/to/project",
"toolName": "bash",
"toolArgs": "{\"command\":\"rm -rf dist\",\"description\":\"Clean build directory\"}"
}
{
"timestamp": 1704614600000,
"cwd": "/path/to/project",
"toolName": "bash",
"toolArgs": "{\"command\":\"rm -rf dist\",\"description\":\"Clean build directory\"}"
}
**Felder:**
*
timestamp: Unix-Zeitstempel in Millisekunden
*
cwd: Aktuelles Arbeitsverzeichnis
*
toolName: Name des aufgerufenen Tools (z. B. "bash", "edit", "view", "create")
*
toolArgs: JSON-Zeichenfolge mit den Argumenten des Tools
**Ausgabe-JSON (optional):**
{
"permissionDecision": "deny",
"permissionDecisionReason": "Destructive operations require approval"
}
{
"permissionDecision": "deny",
"permissionDecisionReason": "Destructive operations require approval"
}
**Ausgabefelder:**
*
permissionDecision: Entweder "allow", "deny" oder "ask" (nur "deny" wird derzeit verarbeitet)
*
permissionDecisionReason: Menschlich lesbare Erklärung für die Entscheidung
**Beispielhaken zum Blockieren gefährlicher Befehle:**
#!/bin/bash
INPUT=$(cat)
TOOL_NAME=$(echo "$INPUT" | jq -r '.toolName')
TOOL_ARGS=$(echo "$INPUT" | jq -r '.toolArgs')
# Log the tool use
echo "$(date): Tool=$TOOL_NAME Args=$TOOL_ARGS" >> tool-usage.log
# Check for dangerous patterns
if echo "$TOOL_ARGS" | grep -qE "rm -rf /|format|DROP TABLE"; then
echo '{"permissionDecision":"deny","permissionDecisionReason":"Dangerous command detected"}'
exit 0
fi
# Allow by default (or omit output to allow)
echo '{"permissionDecision":"allow"}'
#!/bin/bash
INPUT=$(cat)
TOOL_NAME=$(echo "$INPUT" | jq -r '.toolName')
TOOL_ARGS=$(echo "$INPUT" | jq -r '.toolArgs')
# Log the tool use
echo "$(date): Tool=$TOOL_NAME Args=$TOOL_ARGS" >> tool-usage.log
# Check for dangerous patterns
if echo "$TOOL_ARGS" | grep -qE "rm -rf /|format|DROP TABLE"; then
echo '{"permissionDecision":"deny","permissionDecisionReason":"Dangerous command detected"}'
exit 0
fi
# Allow by default (or omit output to allow)
echo '{"permissionDecision":"allow"}'
**Beispiel-Hook zum Erzwingen von Dateiberechtigungen:**
#!/bin/bash
INPUT=$(cat)
TOOL_NAME=$(echo "$INPUT" | jq -r '.toolName')
# Only allow editing specific directories
if [ "$TOOL_NAME" = "edit" ]; then
PATH_ARG=$(echo "$INPUT" | jq -r '.toolArgs' | jq -r '.path')
if [[ ! "$PATH_ARG" =~ ^(src/|test/) ]]; then
echo '{"permissionDecision":"deny","permissionDecisionReason":"Can only edit files in src/ or test/ directories"}'
exit 0
fi
fi
# Allow all other tools
#!/bin/bash
INPUT=$(cat)
TOOL_NAME=$(echo "$INPUT" | jq -r '.toolName')
# Only allow editing specific directories
if [ "$TOOL_NAME" = "edit" ]; then
PATH_ARG=$(echo "$INPUT" | jq -r '.toolArgs' | jq -r '.path')
if [[ ! "$PATH_ARG" =~ ^(src/|test/) ]]; then
echo '{"permissionDecision":"deny","permissionDecisionReason":"Can only edit files in src/ or test/ directories"}'
exit 0
fi
fi
# Allow all other tools
Haken nach der Verwendung des Werkzeugs
Wird ausgeführt, nachdem ein Tool die Ausführung abgeschlossen hat (ob erfolgreich oder fehlgeschlagen).
**Beispiel für JSON-Eingabe:**
{
"timestamp": 1704614700000,
"cwd": "/path/to/project",
"toolName": "bash",
"toolArgs": "{\"command\":\"npm test\"}",
"toolResult": {
"resultType": "success",
"textResultForLlm": "All tests passed (15/15)"
}
}
{
"timestamp": 1704614700000,
"cwd": "/path/to/project",
"toolName": "bash",
"toolArgs": "{\"command\":\"npm test\"}",
"toolResult": {
"resultType": "success",
"textResultForLlm": "All tests passed (15/15)"
}
}
**Felder:**
*
timestamp: Unix-Zeitstempel in Millisekunden
*
cwd: Aktuelles Arbeitsverzeichnis
*
toolName: Name des ausgeführten Tools
*
toolArgs: JSON-Zeichenfolge mit den Argumenten des Tools
*
toolResult: Ergebnisobjekt mit:
*
resultType: Entweder "success", "failure" oder "denied"
*
textResultForLlm: Der Ergebnistext, der dem Agent angezeigt wird
**Ausgabe:** Ignoriert (Ergebnisänderung wird zurzeit nicht unterstützt)
**Beispielskript zum Protokollieren von Toolausführungsstatistiken in einer CSV-Datei:**
Dieses Skript protokolliert Die Toolausführungsstatistiken in einer CSV-Datei und sendet eine E-Mail-Benachrichtigung, wenn ein Tool fehlschlägt.
#!/bin/bash
INPUT=$(cat)
TOOL_NAME=$(echo "$INPUT" | jq -r '.toolName')
RESULT_TYPE=$(echo "$INPUT" | jq -r '.toolResult.resultType')
# Track statistics
echo "$(date),${TOOL_NAME},${RESULT_TYPE}" >> tool-stats.csv
# Alert on failures
if [ "$RESULT_TYPE" = "failure" ]; then
RESULT_TEXT=$(echo "$INPUT" | jq -r '.toolResult.textResultForLlm')
echo "FAILURE: $TOOL_NAME - $RESULT_TEXT" | mail -s "Agent Tool Failed" admin@example.com
fi
#!/bin/bash
INPUT=$(cat)
TOOL_NAME=$(echo "$INPUT" | jq -r '.toolName')
RESULT_TYPE=$(echo "$INPUT" | jq -r '.toolResult.resultType')
# Track statistics
echo "$(date),${TOOL_NAME},${RESULT_TYPE}" >> tool-stats.csv
# Alert on failures
if [ "$RESULT_TYPE" = "failure" ]; then
RESULT_TEXT=$(echo "$INPUT" | jq -r '.toolResult.textResultForLlm')
echo "FAILURE: $TOOL_NAME - $RESULT_TEXT" | mail -s "Agent Tool Failed" admin@example.com
fi
Fehler bei der Hook-Funktion
Wird ausgeführt, wenn während der Agentausführung ein Fehler auftritt.
**Beispiel für JSON-Eingabe:**
{
"timestamp": 1704614800000,
"cwd": "/path/to/project",
"error": {
"message": "Network timeout",
"name": "TimeoutError",
"stack": "TimeoutError: Network timeout\n at ..."
}
}
{
"timestamp": 1704614800000,
"cwd": "/path/to/project",
"error": {
"message": "Network timeout",
"name": "TimeoutError",
"stack": "TimeoutError: Network timeout\n at ..."
}
}
**Felder:**
*
timestamp: Unix-Zeitstempel in Millisekunden
*
cwd: Aktuelles Arbeitsverzeichnis
*
error: Fehlerobjekt mit:
*
message:Fehlermeldung
*
name: Fehlertyp/Name
*
stack: Stapelablaufverfolgung (sofern verfügbar)
**Ausgabe:** Ignoriert (Fehlerbehandlungsänderung wird derzeit nicht unterstützt)
**Beispielskript, das Fehlerdetails in eine Protokolldatei extrahiert:**
#!/bin/bash INPUT=$(cat) ERROR_MSG=$(echo "$INPUT" | jq -r '.error.message') ERROR_NAME=$(echo "$INPUT" | jq -r '.error.name') echo "$(date): [$ERROR_NAME] $ERROR_MSG" >> errors.log
#!/bin/bash
INPUT=$(cat)
ERROR_MSG=$(echo "$INPUT" | jq -r '.error.message')
ERROR_NAME=$(echo "$INPUT" | jq -r '.error.name')
echo "$(date): [$ERROR_NAME] $ERROR_MSG" >> errors.log
Bewährte Methoden für Skripts
Eingabedaten lesen
In diesem Beispielskript werden JSON-Eingaben von Stdin in eine Variable gelesen und dann jq verwendet, um die Felder timestamp und cwd zu extrahieren.
**Bash:**
#!/bin/bash # Read JSON from stdin INPUT=$(cat) # Parse with jq TIMESTAMP=$(echo "$INPUT" | jq -r '.timestamp') CWD=$(echo "$INPUT" | jq -r '.cwd')
#!/bin/bash
# Read JSON from stdin
INPUT=$(cat)
# Parse with jq
TIMESTAMP=$(echo "$INPUT" | jq -r '.timestamp')
CWD=$(echo "$INPUT" | jq -r '.cwd')
**PowerShell**:
# Read JSON from stdin $input = [Console]::In.ReadToEnd() | ConvertFrom-Json # Access properties $timestamp = $input.timestamp $cwd = $input.cwd
# Read JSON from stdin
$input = [Console]::In.ReadToEnd() | ConvertFrom-Json
# Access properties
$timestamp = $input.timestamp
$cwd = $input.cwd
Ausgabe von JSON
Dieses Beispielskript zeigt, wie Sie gültige JSON aus Ihrem Hook-Skript ausgeben. Verwenden Sie jq -c in Bash für kompakte einzeilige Ausgabe oder ConvertTo-Json -Compress in PowerShell.
**Bash:**
#!/bin/bash
# Use jq to compact the JSON output to a single line
echo '{"permissionDecision":"deny","permissionDecisionReason":"Security policy violation"}' | jq -c
# Or construct with variables
REASON="Too dangerous"
jq -n --arg reason "$REASON" '{permissionDecision: "deny", permissionDecisionReason: $reason}'
#!/bin/bash
# Use jq to compact the JSON output to a single line
echo '{"permissionDecision":"deny","permissionDecisionReason":"Security policy violation"}' | jq -c
# Or construct with variables
REASON="Too dangerous"
jq -n --arg reason "$REASON" '{permissionDecision: "deny", permissionDecisionReason: $reason}'
**PowerShell**:
# Use ConvertTo-Json to compact the JSON output to a single line
$output = @{
permissionDecision = "deny"
permissionDecisionReason = "Security policy violation"
}
$output | ConvertTo-Json -Compress
# Use ConvertTo-Json to compact the JSON output to a single line
$output = @{
permissionDecision = "deny"
permissionDecisionReason = "Security policy violation"
}
$output | ConvertTo-Json -Compress
Fehlerbehandlung
In diesem Skriptbeispiel wird veranschaulicht, wie Fehler in Hook-Skripts behandelt werden.
**Bash:**
#!/bin/bash set -e # Exit on error INPUT=$(cat) # ... process input ... # Exit with 0 for success exit 0
#!/bin/bash
set -e # Exit on error
INPUT=$(cat)
# ... process input ...
# Exit with 0 for success
exit 0
**PowerShell**:
$ErrorActionPreference = "Stop"
try {
$input = [Console]::In.ReadToEnd() | ConvertFrom-Json
# ... process input ...
exit 0
} catch {
Write-Error $_.Exception.Message
exit 1
}
$ErrorActionPreference = "Stop"
try {
$input = [Console]::In.ReadToEnd() | ConvertFrom-Json
# ... process input ...
exit 0
} catch {
Write-Error $_.Exception.Message
exit 1
}
Behandeln von Timeouts
Hooks haben ein Standardtimeout von 30 Sekunden. Bei längeren Vorgängen erhöhen Sie timeoutSec:
{
"type": "command",
"bash": "./scripts/slow-validation.sh",
"timeoutSec": 120
}
{
"type": "command",
"bash": "./scripts/slow-validation.sh",
"timeoutSec": 120
}
Erweiterte Muster
Mehrere Hooks desselben Typs
Sie können mehrere Hooks für dasselbe Ereignis definieren. Sie werden in der Reihenfolge ausgeführt:
{
"version": 1,
"hooks": {
"preToolUse": [
{
"type": "command",
"bash": "./scripts/security-check.sh",
"comment": "Security validation - runs first"
},
{
"type": "command",
"bash": "./scripts/audit-log.sh",
"comment": "Audit logging - runs second"
},
{
"type": "command",
"bash": "./scripts/metrics.sh",
"comment": "Metrics collection - runs third"
}
]
}
}
{
"version": 1,
"hooks": {
"preToolUse": [
{
"type": "command",
"bash": "./scripts/security-check.sh",
"comment": "Security validation - runs first"
},
{
"type": "command",
"bash": "./scripts/audit-log.sh",
"comment": "Audit logging - runs second"
},
{
"type": "command",
"bash": "./scripts/metrics.sh",
"comment": "Metrics collection - runs third"
}
]
}
}
Bedingte Logik in Skripts
**Beispiel: Nur bestimmte Tools blockieren**
#!/bin/bash
INPUT=$(cat)
TOOL_NAME=$(echo "$INPUT" | jq -r '.toolName')
# Only validate bash commands
if [ "$TOOL_NAME" != "bash" ]; then
exit 0 # Allow all non-bash tools
fi
# Check bash command for dangerous patterns
COMMAND=$(echo "$INPUT" | jq -r '.toolArgs' | jq -r '.command')
if echo "$COMMAND" | grep -qE "rm -rf|sudo|mkfs"; then
echo '{"permissionDecision":"deny","permissionDecisionReason":"Dangerous system command"}'
fi
#!/bin/bash
INPUT=$(cat)
TOOL_NAME=$(echo "$INPUT" | jq -r '.toolName')
# Only validate bash commands
if [ "$TOOL_NAME" != "bash" ]; then
exit 0 # Allow all non-bash tools
fi
# Check bash command for dangerous patterns
COMMAND=$(echo "$INPUT" | jq -r '.toolArgs' | jq -r '.command')
if echo "$COMMAND" | grep -qE "rm -rf|sudo|mkfs"; then
echo '{"permissionDecision":"deny","permissionDecisionReason":"Dangerous system command"}'
fi
Strukturierte Protokollierung
**Beispiel: JSON-Linienformat**
#!/bin/bash
INPUT=$(cat)
TIMESTAMP=$(echo "$INPUT" | jq -r '.timestamp')
TOOL_NAME=$(echo "$INPUT" | jq -r '.toolName')
RESULT_TYPE=$(echo "$INPUT" | jq -r '.toolResult.resultType')
# Output structured log entry
jq -n \
--arg ts "$TIMESTAMP" \
--arg tool "$TOOL_NAME" \
--arg result "$RESULT_TYPE" \
'{timestamp: $ts, tool: $tool, result: $result}' >> logs/audit.jsonl
#!/bin/bash
INPUT=$(cat)
TIMESTAMP=$(echo "$INPUT" | jq -r '.timestamp')
TOOL_NAME=$(echo "$INPUT" | jq -r '.toolName')
RESULT_TYPE=$(echo "$INPUT" | jq -r '.toolResult.resultType')
# Output structured log entry
jq -n \
--arg ts "$TIMESTAMP" \
--arg tool "$TOOL_NAME" \
--arg result "$RESULT_TYPE" \
'{timestamp: $ts, tool: $tool, result: $result}' >> logs/audit.jsonl
Integration in externe Systeme
**Beispiel: Senden von Benachrichtigungen an Slack**
#!/bin/bash
INPUT=$(cat)
ERROR_MSG=$(echo "$INPUT" | jq -r '.error.message')
WEBHOOK_URL="https://hooks.slack.com/services/YOUR/WEBHOOK/URL"
curl -X POST "$WEBHOOK_URL" \
-H 'Content-Type: application/json' \
-d "{\"text\":\"Agent Error: $ERROR_MSG\"}"
#!/bin/bash
INPUT=$(cat)
ERROR_MSG=$(echo "$INPUT" | jq -r '.error.message')
WEBHOOK_URL="https://hooks.slack.com/services/YOUR/WEBHOOK/URL"
curl -X POST "$WEBHOOK_URL" \
-H 'Content-Type: application/json' \
-d "{\"text\":\"Agent Error: $ERROR_MSG\"}"
Beispielhafte Anwendungsfälle
Compliance-Prüfpfad
Protokollieren Sie alle Agentaktionen für Complianceanforderungen, indem Sie Protokollskripts verwenden:
{
"version": 1,
"hooks": {
"sessionStart": [{"type": "command", "bash": "./audit/log-session-start.sh"}],
"userPromptSubmitted": [{"type": "command", "bash": "./audit/log-prompt.sh"}],
"preToolUse": [{"type": "command", "bash": "./audit/log-tool-use.sh"}],
"postToolUse": [{"type": "command", "bash": "./audit/log-tool-result.sh"}],
"sessionEnd": [{"type": "command", "bash": "./audit/log-session-end.sh"}]
}
}
{
"version": 1,
"hooks": {
"sessionStart": [{"type": "command", "bash": "./audit/log-session-start.sh"}],
"userPromptSubmitted": [{"type": "command", "bash": "./audit/log-prompt.sh"}],
"preToolUse": [{"type": "command", "bash": "./audit/log-tool-use.sh"}],
"postToolUse": [{"type": "command", "bash": "./audit/log-tool-result.sh"}],
"sessionEnd": [{"type": "command", "bash": "./audit/log-session-end.sh"}]
}
}
Kostenverfolgung
Nachverfolgen der Toolnutzung für die Kostenzuteilung:
#!/bin/bash
INPUT=$(cat)
TOOL_NAME=$(echo "$INPUT" | jq -r '.toolName')
TIMESTAMP=$(echo "$INPUT" | jq -r '.timestamp')
USER=${USER:-unknown}
echo "$TIMESTAMP,$USER,$TOOL_NAME" >> /var/log/copilot/usage.csv
#!/bin/bash
INPUT=$(cat)
TOOL_NAME=$(echo "$INPUT" | jq -r '.toolName')
TIMESTAMP=$(echo "$INPUT" | jq -r '.timestamp')
USER=${USER:-unknown}
echo "$TIMESTAMP,$USER,$TOOL_NAME" >> /var/log/copilot/usage.csv
Code-Qualitätserzwingung
Verhindern Sie Commits, die gegen Codestandards verstoßen:
#!/bin/bash
INPUT=$(cat)
TOOL_NAME=$(echo "$INPUT" | jq -r '.toolName')
if [ "$TOOL_NAME" = "edit" ] || [ "$TOOL_NAME" = "create" ]; then
# Run linter before allowing edits
npm run lint-staged
if [ $? -ne 0 ]; then
echo '{"permissionDecision":"deny","permissionDecisionReason":"Code does not pass linting"}'
fi
fi
#!/bin/bash
INPUT=$(cat)
TOOL_NAME=$(echo "$INPUT" | jq -r '.toolName')
if [ "$TOOL_NAME" = "edit" ] || [ "$TOOL_NAME" = "create" ]; then
# Run linter before allowing edits
npm run lint-staged
if [ $? -ne 0 ]; then
echo '{"permissionDecision":"deny","permissionDecisionReason":"Code does not pass linting"}'
fi
fi
Benachrichtigungssystem
Senden von Benachrichtigungen zu wichtigen Ereignissen:
#!/bin/bash INPUT=$(cat) PROMPT=$(echo "$INPUT" | jq -r '.prompt') # Notify on production-related prompts if echo "$PROMPT" | grep -iq "production"; then echo "ALERT: Production-related prompt: $PROMPT" | mail -s "Agent Alert" team@example.com fi
#!/bin/bash
INPUT=$(cat)
PROMPT=$(echo "$INPUT" | jq -r '.prompt')
# Notify on production-related prompts
if echo "$PROMPT" | grep -iq "production"; then
echo "ALERT: Production-related prompt: $PROMPT" | mail -s "Agent Alert" team@example.com
fi