Lifecycle Hooks
Lifecycle hooks provide interception points throughout the Claude Copilot workflow, enabling validation, transformation, and monitoring at critical execution phases.
Overview
The lifecycle hooks system consists of three primary hook types:
| Hook Type | When It Fires | Primary Use Cases |
|---|---|---|
| PreToolUse | Before any tool executes | Security validation, argument preprocessing, permission checks |
| PostToolUse | After tool completes | Result transformation, logging, error enrichment |
| UserPromptSubmit | Before prompt processing | Context injection, skill detection, prompt preprocessing |
Hook Architecture
User Prompt
│
▼
┌─────────────────────┐
│ UserPromptSubmit │ → Context injection, skill signals
└─────────────────────┘
│
▼
┌─────────────────────┐
│ Tool Selection │
└─────────────────────┘
│
▼
┌─────────────────────┐
│ PreToolUse │ → Security checks, preprocessing
└─────────────────────┘
│
▼
┌─────────────────────┐
│ Tool Execution │
└─────────────────────┘
│
▼
┌─────────────────────┐
│ PostToolUse │ → Logging, result transformation
└─────────────────────┘
│
▼
Response
PreToolUse Hook
Intercepts tool calls before execution for security validation and preprocessing.
Actions
| Action | Effect |
|---|---|
ALLOW |
Tool call proceeds normally |
WARN |
Proceed with warning logged |
BLOCK |
Tool call rejected with reason |
TRANSFORM |
Modify tool arguments before execution |
Built-in Rules
| Rule ID | Category | Purpose |
|---|---|---|
secret-detection |
security | Block hardcoded secrets (API keys, tokens) |
destructive-command |
security | Block dangerous commands (rm -rf /, DROP DATABASE) |
sensitive-file-protection |
security | Block edits to .env, credentials files |
credential-url |
security | Block URLs with embedded credentials |
git-secret-commit |
security | Prevent committing secrets to git |
path-normalization |
preprocessing | Normalize file paths |
metadata-enrichment |
preprocessing | Add timestamp and context metadata |
API
import {
registerSecurityRule,
evaluatePreToolUse,
SecurityAction
} from 'hooks';
// Register a custom rule
registerSecurityRule({
id: 'custom-rule',
name: 'Custom Security Rule',
description: 'Block specific patterns',
enabled: true,
priority: 75, // Higher priority runs first (1-100)
evaluate: (context) => {
if (context.toolInput.content?.includes('UNSAFE')) {
return {
action: SecurityAction.BLOCK,
ruleName: 'custom-rule',
reason: 'Unsafe pattern detected',
severity: 'high'
};
}
return null; // No violation
}
});
// Evaluate a tool call
const result = await evaluatePreToolUse('Write', {
file_path: 'config.ts',
content: 'const key = "secret";'
});
if (!result.allowed) {
console.log('Blocked:', result.violations);
}
Configuration
Rules can be registered, toggled, and removed at runtime:
import {
toggleSecurityRule,
unregisterSecurityRule,
getSecurityRules
} from 'hooks';
// Disable a rule
toggleSecurityRule('secret-detection', false);
// Remove a rule
unregisterSecurityRule('custom-rule');
// List all active rules
const rules = getSecurityRules();
PostToolUse Hook
Processes tool results after execution for logging, transformation, and error handling.
Actions
| Action | Effect |
|---|---|
PASSTHROUGH |
Result unchanged |
TRANSFORM |
Modify result before returning |
ENRICH |
Add metadata to result |
SUPPRESS |
Suppress result (for logging-only rules) |
Built-in Rules
| Rule ID | Purpose |
|---|---|
basic-logging |
Log tool calls with timing |
error-enrichment |
Add context to error messages |
slow-execution |
Warn on slow tool calls (>5s) |
result-sanitization |
Redact sensitive data from results |
activity-tracking |
Track tool usage patterns |
API
import {
registerPostToolUseRule,
evaluatePostToolUse,
PostToolAction
} from 'hooks';
// Register a logging rule
registerPostToolUseRule({
id: 'custom-logger',
name: 'Custom Logger',
description: 'Log all file operations',
enabled: true,
priority: 50,
evaluate: (context) => {
if (context.toolName === 'Write' || context.toolName === 'Edit') {
console.log(`File operation: ${context.toolName}`, context.duration);
}
return {
action: PostToolAction.PASSTHROUGH
};
}
});
UserPromptSubmit Hook
Preprocesses user prompts before they reach the agent, enabling context injection and skill detection.
Actions
| Action | Effect |
|---|---|
CONTINUE |
Process prompt normally |
TRANSFORM |
Modify prompt content |
INJECT_CONTEXT |
Add context to prompt |
SIGNAL_SKILL |
Trigger skill loading |
BLOCK |
Reject prompt with message |
Built-in Rules
| Rule ID | Purpose |
|---|---|
whitespace-normalization |
Clean up prompt formatting |
file-pattern-detection |
Detect file references for skill matching |
keyword-detection |
Detect keywords for skill signals |
task-context-injection |
Add current task context |
explicit-skill-request |
Detect /skill-name requests |
API
import {
registerUserPromptSubmitRule,
evaluateUserPromptSubmit,
PromptAction
} from 'hooks';
// Register a context injection rule
registerUserPromptSubmitRule({
id: 'project-context',
name: 'Project Context',
description: 'Inject project-specific context',
enabled: true,
priority: 60,
evaluate: (context) => {
if (context.prompt.includes('deploy')) {
return {
action: PromptAction.INJECT_CONTEXT,
context: 'Note: This project uses Kubernetes for deployment.',
reason: 'Deployment context detected'
};
}
return { action: PromptAction.CONTINUE };
}
});
Skill Signals
The UserPromptSubmit hook can signal that specific skills should be loaded:
{
action: PromptAction.SIGNAL_SKILL,
skills: [
{ name: 'kubernetes', confidence: 0.85 },
{ name: 'deployment', confidence: 0.7 }
]
}
Security Hooks MCP Tools
Security hooks are also exposed as MCP tools for runtime management.
Available Tools
| Tool | Purpose |
|---|---|
hook_list_security |
List active security rules (optional: includeDisabled, ruleId) |
hook_test_security |
Dry-run test a tool call against rules (without executing) |
hook_register_security |
Register custom rules or resetToDefaults |
hook_toggle_security |
Enable/disable a specific rule by ruleId |
Default Rule Detection Patterns
| Rule | Detects |
|---|---|
secret-detection |
AWS keys (AKIA...), Google API keys (AIza...), GitHub tokens (ghp_...), Stripe keys (sk_live_...), JWT tokens, private keys |
destructive-command |
rm -rf /, DROP DATABASE/TABLE, TRUNCATE TABLE, shutdown commands, fork bombs, chmod 777 |
sensitive-file-protection |
.env files, credentials files, SSH/SSL keys, cloud provider configs, database files |
credential-url |
URLs with embedded credentials (http://user:pass@host) |
Custom Rule Registration
hook_register_security({
rules: [{
id: "internal-api-key",
name: "Internal API Key Detection",
description: "Detects internal API key patterns",
priority: 85, // 1-100, higher runs first
patterns: ["INTERNAL_[A-Z0-9]{32}"],
severity: "critical", // low, medium, high, critical
action: "block" // allow, warn, block
}]
})
Configuration File
Rules can also be defined in .claude/hooks/security-rules.json:
{
"version": "1.0.0",
"rules": [
{
"id": "custom-pattern",
"name": "Custom Pattern",
"description": "Project-specific detection",
"enabled": true,
"priority": 85,
"patterns": ["YOUR_PATTERN_HERE"],
"action": "block",
"severity": "critical"
}
]
}
Priority Guidelines
| Range | Use Case |
|---|---|
| 90-100 | Critical security (secrets, keys) |
| 80-89 | High priority (sensitive files, credentials) |
| 70-79 | Medium priority (destructive commands) |
| 50-69 | Low priority (code quality) |
| 1-49 | Informational (warnings only) |
Initialization
Hooks are automatically initialized on server startup. For manual initialization:
import { initializeAllHooks } from 'hooks';
// Initialize all hook systems
initializeAllHooks();
To get a summary of registered hooks:
import { getHooksSummary } from 'hooks';
const summary = getHooksSummary();
console.log('PreToolUse rules:', summary.preToolUse.total);
console.log('PostToolUse rules:', summary.postToolUse.total);
console.log('UserPromptSubmit rules:', summary.userPromptSubmit.total);
Best Practices
- Priority Ordering: Security rules should have higher priority (70-100) than preprocessing rules (30-50)
- Fail-Safe: Rules that throw errors are caught and logged; they don't block execution
- Performance: Keep rule evaluation fast (<10ms) to avoid latency
- Idempotency: Rules should be safe to run multiple times
- Logging: Use the built-in logging rules rather than custom console.log
Troubleshooting
Hook Not Firing
- Verify the hook is registered:
getSecurityRules()/getPostToolUseRules() - Check if the hook is enabled:
rule.enabled === true - Verify priority ordering (higher priority runs first)
Rule Blocking Incorrectly
- Use
testSecurityRules()for dry-run testing - Check the
matchedPatternin the violation result - Adjust pattern specificity or add exceptions
Performance Issues
- Check rule evaluation time in logs
- Simplify regex patterns
- Use early returns for non-matching cases