How to Use These Samples
Each sample is designed to be:- Copy-and-paste ready: Use them directly or as starting points
- Educational: Learn hook concepts through progressive complexity
- Practical: Solve real development workflow challenges
Beginner Examples
Perfect for getting started with hooks. These examples demonstrate core concepts with straightforward logic.1. Project Type Detection
Hook:TaskStart
Copy
Ask AI
#!/usr/bin/env bash
# Project Type Detection Hook
#
# Overview: Automatically detects project type at task start and injects relevant
# coding standards and best practices into the AI context. This helps Cline understand
# your project structure and apply appropriate conventions from the beginning.
#
# Demonstrates: Basic hook input/output, file system checks, conditional logic,
# and context injection to guide AI behavior.
input=$(cat)
# Read basic JSON structure and detect project type
context=""
# Check for different project indicators
if [[ -f "package.json" ]]; then
if grep -q "react" package.json; then
context="PROJECT_TYPE: React application detected. Follow component-based architecture and use functional components."
elif grep -q "express" package.json; then
context="PROJECT_TYPE: Express.js API detected. Follow RESTful patterns and proper middleware structure."
else
context="PROJECT_TYPE: Node.js project detected. Use proper npm scripts and dependency management."
fi
elif [[ -f "requirements.txt" ]] || [[ -f "pyproject.toml" ]]; then
context="PROJECT_TYPE: Python project detected. Follow PEP 8 standards and use virtual environments."
elif [[ -f "Cargo.toml" ]]; then
context="PROJECT_TYPE: Rust project detected. Follow Rust conventions and use proper error handling."
elif [[ -f "go.mod" ]]; then
context="PROJECT_TYPE: Go project detected. Follow Go conventions and use proper package structure."
fi
# Return the context to guide Cline's behavior
if [[ -n "$context" ]]; then
jq -n --arg ctx "$context" '{"cancel": false, "contextModification": $ctx}'
else
echo '{"cancel": false}'
fi
- Reading hook input with
input=$(cat) - Using file system checks to detect project type
- Returning context to influence AI behavior
- Basic JSON output with
jq
2. File Extension Validator
Hook:PreToolUse
Copy
Ask AI
#!/usr/bin/env bash
# File Extension Validator Hook
#
# Overview: Enforces TypeScript file extensions in TypeScript projects by blocking
# creation of .js and .jsx files. This prevents common mistakes where developers
# accidentally create JavaScript files when they should be using TypeScript.
#
# Demonstrates: PreToolUse blocking, parameter extraction, conditional validation,
# and providing clear error messages to guide users toward correct file extensions.
input=$(cat)
# Extract tool information
tool_name=$(echo "$input" | jq -r '.preToolUse.toolName')
# Only process file creation tools
if [[ "$tool_name" != "write_to_file" ]]; then
echo '{"cancel": false}'
exit 0
fi
# Check if this is a TypeScript project
if [[ ! -f "tsconfig.json" ]]; then
echo '{"cancel": false}'
exit 0
fi
# Get the file path from tool parameters
file_path=$(echo "$input" | jq -r '.preToolUse.parameters.path // empty')
if [[ -z "$file_path" ]]; then
echo '{"cancel": false}'
exit 0
fi
# Block .js files in TypeScript projects
if [[ "$file_path" == *.js ]]; then
echo '{"cancel": true, "errorMessage": "JavaScript files (.js) are not allowed in TypeScript projects. Use .ts extension instead."}'
exit 0
fi
# Block .jsx files, suggest .tsx
if [[ "$file_path" == *.jsx ]]; then
echo '{"cancel": true, "errorMessage": "JSX files (.jsx) are not allowed in TypeScript projects. Use .tsx extension instead."}'
exit 0
fi
# Everything is OK
echo '{"cancel": false}'
- Extracting tool name and parameters
- Conditional logic based on project state
- Blocking operations with
"cancel": true - Providing helpful error messages
3. Basic Performance Monitor
Hook:PostToolUse
Copy
Ask AI
#!/usr/bin/env bash
# Basic Performance Monitor Hook
#
# Overview: Monitors tool execution times and logs operations that exceed a 3-second
# threshold. This helps identify performance bottlenecks and provides feedback to
# users about system resource issues that may be slowing down Cline's operations.
#
# Demonstrates: PostToolUse hook usage, arithmetic operations in bash, simple file
# logging, and conditional context injection based on performance metrics.
input=$(cat)
# Extract performance information
tool_name=$(echo "$input" | jq -r '.postToolUse.toolName')
execution_time=$(echo "$input" | jq -r '.postToolUse.executionTimeMs // 0')
success=$(echo "$input" | jq -r '.postToolUse.success')
# Log slow operations (threshold: 3 seconds)
if (( execution_time > 3000 )); then
# Create simple log directory
mkdir -p "$HOME/.cline_logs"
# Log the slow operation
echo "$(date -Iseconds): SLOW OPERATION - $tool_name took ${execution_time}ms" >> "$HOME/.cline_logs/performance.log"
# Provide feedback to user
context="PERFORMANCE: Operation $tool_name took ${execution_time}ms. Consider checking system resources if this happens frequently."
jq -n --arg ctx "$context" '{"cancel": false, "contextModification": $ctx}'
else
echo '{"cancel": false}'
fi
- Processing results after tool execution
- Basic arithmetic operations in bash
- Simple file logging
- Conditional context injection
Intermediate Examples
These examples demonstrate more advanced concepts including external tool integration, pattern matching, and structured logging.4. Code Quality with Linting
Hook:PreToolUse
Copy
Ask AI
#!/usr/bin/env bash
# Code Quality Linting Hook
#
# Overview: Integrates ESLint and Flake8 to enforce code quality standards before
# files are written. Blocks file creation if linting errors are detected, ensuring
# all code meets quality standards. Supports TypeScript, JavaScript, and Python files.
#
# Demonstrates: External tool integration, temporary file handling, regex pattern
# matching, and comprehensive error reporting with actionable feedback.
input=$(cat)
tool_name=$(echo "$input" | jq -r '.preToolUse.toolName')
# Only lint file write operations
if [[ "$tool_name" != "write_to_file" ]]; then
echo '{"cancel": false}'
exit 0
fi
file_path=$(echo "$input" | jq -r '.preToolUse.parameters.path // empty')
# Skip non-code files
if [[ ! "$file_path" =~ \.(ts|tsx|js|jsx|py|rs)$ ]]; then
echo '{"cancel": false}'
exit 0
fi
# Get file content from the tool parameters
content=$(echo "$input" | jq -r '.preToolUse.parameters.content // empty')
if [[ -z "$content" ]]; then
echo '{"cancel": false}'
exit 0
fi
# Create temporary file for linting
temp_file=$(mktemp)
echo "$content" > "$temp_file"
# Run appropriate linter based on file extension
lint_errors=""
if [[ "$file_path" =~ \.(ts|tsx)$ ]] && command -v eslint > /dev/null; then
lint_output=$(eslint "$temp_file" --format=json 2>/dev/null || true)
if [[ "$lint_output" != "[]" ]] && [[ -n "$lint_output" ]]; then
error_count=$(echo "$lint_output" | jq '.[0].errorCount // 0')
if (( error_count > 0 )); then
messages=$(echo "$lint_output" | jq -r '.[0].messages[] | "\(.line):\(.column) \(.message)"')
lint_errors="ESLint errors found:\n$messages"
fi
fi
elif [[ "$file_path" =~ \.py$ ]] && command -v flake8 > /dev/null; then
lint_output=$(flake8 "$temp_file" 2>/dev/null || true)
if [[ -n "$lint_output" ]]; then
lint_errors="Flake8 errors found:\n$lint_output"
fi
fi
# Cleanup
rm -f "$temp_file"
# Block if linting errors found
if [[ -n "$lint_errors" ]]; then
error_message="Code quality check failed. Please fix these issues:\n\n$lint_errors"
jq -n --arg msg "$error_message" '{"cancel": true, "errorMessage": $msg}'
else
echo '{"cancel": false}'
fi
- Temporary file creation and cleanup
- External tool integration (eslint, flake8)
- Complex pattern matching with regex
- Structured error reporting
5. Security Scanner
Hook:PreToolUse
Copy
Ask AI
#!/usr/bin/env bash
# Security Scanner Hook
#
# Overview: Scans file content for hardcoded secrets (API keys, tokens, passwords)
# before files are written. Blocks creation of files containing secrets except in
# safe locations like .env.example files or documentation, preventing credential leaks.
#
# Demonstrates: Pattern matching with regex arrays, file path exception handling,
# security-focused validation, and clear user guidance in error messages.
input=$(cat)
tool_name=$(echo "$input" | jq -r '.preToolUse.toolName')
# Only check file operations
if [[ "$tool_name" != "write_to_file" ]]; then
echo '{"cancel": false}'
exit 0
fi
content=$(echo "$input" | jq -r '.preToolUse.parameters.content // empty')
file_path=$(echo "$input" | jq -r '.preToolUse.parameters.path // empty')
# Skip if no content
if [[ -z "$content" ]]; then
echo '{"cancel": false}'
exit 0
fi
# Define secret patterns (simplified for readability)
secrets_found=""
# Check for API keys
if echo "$content" | grep -qi "api[_-]*key.*[=:].*['\"][a-z0-9_-]{10,}['\"]"; then
secrets_found+="- API key pattern detected\n"
fi
# Check for tokens
if echo "$content" | grep -qi "token.*[=:].*['\"][a-z0-9_-]{10,}['\"]"; then
secrets_found+="- Token pattern detected\n"
fi
# Check for passwords
if echo "$content" | grep -qi "password.*[=:].*['\"][^'\"]{8,}['\"]"; then
secrets_found+="- Password pattern detected\n"
fi
# Allow secrets in safe files
safe_patterns=("\.env\.example$" "\.env\.template$" "/docs/" "\.md$")
is_safe_file=false
for safe_pattern in "${safe_patterns[@]}"; do
if [[ "$file_path" =~ $safe_pattern ]]; then
is_safe_file=true
break
fi
done
if [[ -n "$secrets_found" ]] && [[ "$is_safe_file" == false ]]; then
error_message="🔒 SECURITY ALERT: Potential secrets detected in $file_path
$secrets_found
Please use environment variables or a secrets management service instead."
jq -n --arg msg "$error_message" '{"cancel": true, "errorMessage": $msg}'
else
echo '{"cancel": false}'
fi
- Pattern arrays and iteration
- File path exception handling
- Security-focused validation
- Clear user guidance in error messages
6. Git Workflow Assistant
Hook:PostToolUse
Copy
Ask AI
#!/usr/bin/env bash
# Git Workflow Assistant Hook
#
# Overview: Analyzes file modifications and provides intelligent git workflow suggestions
# based on file types and current branch. Encourages best practices like feature branches
# for components and test branches for test files, with actionable git commands.
#
# Demonstrates: Git integration, branch analysis, file path pattern matching, and
# contextual suggestions to guide users toward better git practices.
input=$(cat)
tool_name=$(echo "$input" | jq -r '.postToolUse.toolName')
success=$(echo "$input" | jq -r '.postToolUse.success')
# Only process successful file modifications
if [[ "$success" != "true" ]] || [[ "$tool_name" != "write_to_file" && "$tool_name" != "replace_in_file" ]]; then
echo '{"cancel": false}'
exit 0
fi
# Check if we're in a git repository
if ! git rev-parse --git-dir > /dev/null 2>&1; then
echo '{"cancel": false}'
exit 0
fi
file_path=$(echo "$input" | jq -r '.postToolUse.parameters.path // empty')
current_branch=$(git branch --show-current 2>/dev/null || echo "main")
# Analyze file type and suggest appropriate branch naming
context=""
if [[ "$file_path" == *"component"* ]] && [[ "$current_branch" == "main" || "$current_branch" == "master" ]]; then
component_name=$(basename "$file_path" .tsx .ts .jsx .js)
context="GIT_WORKFLOW: Consider creating a feature branch: git checkout -b feature/add-${component_name,,}-component"
elif [[ "$file_path" == *"test"* ]] || [[ "$file_path" == *"spec"* ]]; then
if [[ "$current_branch" == "main" || "$current_branch" == "master" ]]; then
context="GIT_WORKFLOW: Consider creating a test branch: git checkout -b test/add-tests-$(basename "$(dirname "$file_path")")"
fi
fi
# Add staging guidance
if [[ -n "$context" ]]; then
context="$context After completing changes, use 'git add $file_path' to stage for commit."
else
context="GIT_WORKFLOW: File modified: $file_path. Use 'git add $file_path' when ready to commit."
fi
jq -n --arg ctx "$context" '{"cancel": false, "contextModification": $ctx}'
- Git repository detection
- Branch analysis and suggestions
- File path analysis for context
- Actionable user guidance
Advanced Examples
These examples showcase sophisticated patterns including external integrations, asynchronous processing, and complex state management.7. Comprehensive Task Lifecycle Manager
Hook:TaskComplete
Copy
Ask AI
#!/usr/bin/env bash
# Comprehensive Task Lifecycle Manager Hook
#
# Overview: Tracks task completions by generating detailed markdown reports with
# workspace information and git state, and optionally sends webhook notifications
# to external systems. Perfect for enterprise environments requiring audit trails.
#
# Demonstrates: Complex data extraction, structured report generation, markdown
# heredocs, asynchronous webhook notifications, and robust error handling.
input=$(cat)
# Extract task metadata using proper API field paths
task_id=$(echo "$input" | jq -r '.taskId')
ulid=$(echo "$input" | jq -r '.taskComplete.taskMetadata.ulid // "unknown"')
completion_time=$(echo "$input" | jq -r '.timestamp')
# Create completion report directory with error handling
reports_dir="$HOME/.cline_reports"
if [[ ! -d "$(dirname "$reports_dir")" ]]; then
echo '{"cancel": false, "errorMessage": "Cannot access home directory"}'
exit 0
fi
mkdir -p "$reports_dir" || exit 0
# Generate safe, unique report filename
safe_task_id=$(echo "$task_id" | tr -cd '[:alnum:]_-' | head -c 50)
report_file="$reports_dir/completion_$(date +%Y%m%d_%H%M%S)_${safe_task_id}.md"
# Collect comprehensive workspace information
git_branch=$(git branch --show-current 2>/dev/null || echo "No git repository")
git_status_count=$(git status --porcelain 2>/dev/null | wc -l || echo "0")
project_name=$(basename "$PWD")
# Generate detailed completion report
cat > "$report_file" << EOF
# Cline Task Completion Report
**Task ID:** $task_id
**ULID:** $ulid
**Completed:** $(date -Iseconds)
**Completion Time:** $completion_time
## Workspace Information
- **Project:** $project_name
- **Git Branch:** $git_branch
- **Modified Files:** $git_status_count
## Completion Status
✅ Task completed successfully
## Next Steps
- Review changes made during this task
- Consider committing changes if appropriate
- Run tests to verify functionality
EOF
# Send webhook notification if configured
webhook_url="${COMPLETION_WEBHOOK_URL:-}"
if [[ -n "$webhook_url" ]]; then
payload=$(jq -n \
--arg task_id "$task_id" \
--arg ulid "$ulid" \
--arg workspace "$project_name" \
--arg timestamp "$completion_time" \
'{
event: "task_completed",
task_id: $task_id,
ulid: $ulid,
workspace: $workspace,
timestamp: $timestamp
}')
# Send notification in background with timeout
(curl -X POST \
-H "Content-Type: application/json" \
-d "$payload" \
"$webhook_url" \
--max-time 5 \
--silent > /dev/null 2>&1) &
fi
context="TASK_COMPLETED: ✅ Task $task_id finished successfully. Report saved to: $(basename "$report_file")"
jq -n --arg ctx "$context" '{"cancel": false, "contextModification": $ctx}'
- Complex data extraction and validation
- Structured report generation
- Asynchronous webhook notifications
- Error handling and resource management
8. Intelligent User Input Enhancer
Hook:UserPromptSubmit
Copy
Ask AI
#!/usr/bin/env bash
# Intelligent User Input Enhancer Hook
#
# Overview: Analyzes user prompts to detect potentially harmful commands, logs user
# activity for analytics, and intelligently injects project and git context based on
# prompt keywords. Provides safety guards while enhancing AI responses with relevant context.
#
# Demonstrates: UserPromptSubmit hook usage, multi-pattern safety validation, intelligent
# context detection from prompts, structured JSON logging, and dynamic suggestion generation.
input=$(cat)
user_prompt=$(echo "$input" | jq -r '.userPromptSubmit.prompt')
task_id=$(echo "$input" | jq -r '.taskId')
user_id=$(echo "$input" | jq -r '.userId')
# Log user activity for analytics
activity_log="$HOME/.cline_user_activity/$(date +%Y-%m-%d).log"
mkdir -p "$(dirname "$activity_log")"
activity_entry=$(jq -n \
--arg timestamp "$(date -Iseconds)" \
--arg task_id "$task_id" \
--arg user_id "$user_id" \
--arg prompt_length "${#user_prompt}" \
'{
timestamp: $timestamp,
task_id: $task_id,
user_id: $user_id,
prompt_length: ($prompt_length | tonumber),
workspace: env.PWD
}')
echo "$activity_entry" >> "$activity_log"
context_modifications=""
cancel_request=false
# Safety validation
harmful_patterns=("rm -rf" "delete.*all" "format.*drive" "sudo.*passwd")
for pattern in "${harmful_patterns[@]}"; do
if echo "$user_prompt" | grep -qi "$pattern"; then
cancel_request=true
error_message="🚨 SAFETY ALERT: Potentially harmful command detected. Please review your request."
break
fi
done
# Intelligent context enhancement
if [[ "$cancel_request" == false ]]; then
# Detect project context
if echo "$user_prompt" | grep -qi "file\|directory\|folder"; then
if [[ -f "package.json" ]]; then
project_name=$(jq -r '.name // "unknown"' package.json 2>/dev/null)
context_modifications+="PROJECT_CONTEXT: Working in Node.js project '$project_name'. "
elif [[ -f "requirements.txt" ]]; then
context_modifications+="PROJECT_CONTEXT: Working in Python project. "
fi
fi
# Git context enhancement
if echo "$user_prompt" | grep -qi "git\|commit\|branch" && git rev-parse --git-dir > /dev/null 2>&1; then
current_branch=$(git branch --show-current 2>/dev/null)
uncommitted=$(git status --porcelain | wc -l)
context_modifications+="GIT_CONTEXT: On branch '$current_branch' with $uncommitted uncommitted changes. "
fi
# Tool suggestions
if echo "$user_prompt" | grep -qi "search.*code\|find.*function"; then
context_modifications+="SUGGESTION: Consider using search_files tool for code exploration. "
fi
fi
# Return response
if [[ "$cancel_request" == true ]]; then
jq -n --arg msg "$error_message" '{"cancel": true, "errorMessage": $msg}'
else
if [[ -n "$context_modifications" ]]; then
jq -n --arg ctx "$context_modifications" '{"cancel": false, "contextModification": $ctx}'
else
echo '{"cancel": false}'
fi
fi
- User interaction analysis and logging
- Multi-pattern safety validation
- Intelligent context detection
- Dynamic suggestion generation
9. Multi-Service Integration Hub
Hook:PostToolUse
Copy
Ask AI
#!/usr/bin/env bash
# Multi-Service Integration Hub Hook
#
# Overview: Detects file modifications by type (dependencies, CI/CD, frontend, backend, tests)
# and sends asynchronous webhook notifications to multiple external services like Slack and
# CI/CD systems. Enables seamless integration of Cline operations into enterprise workflows.
#
# Demonstrates: Advanced pattern matching with associative arrays, multi-service webhook
# orchestration, asynchronous background processing, and enterprise notification patterns.
input=$(cat)
tool_name=$(echo "$input" | jq -r '.postToolUse.toolName')
success=$(echo "$input" | jq -r '.postToolUse.success')
file_path=$(echo "$input" | jq -r '.postToolUse.parameters.path // empty')
# Only process successful file operations
if [[ "$success" != "true" ]] || [[ "$tool_name" != "write_to_file" && "$tool_name" != "replace_in_file" ]]; then
echo '{"cancel": false}'
exit 0
fi
# Define workflow triggers
declare -A triggers=(
["package\\.json|yarn\\.lock"]="dependencies"
["\\.github/workflows/"]="ci_cd"
["src/.*component"]="frontend"
["api/.*\\.(ts|js)"]="backend"
[".*\\.(test|spec)\\."]="testing"
)
# Determine triggered workflows
triggered_workflows=""
for pattern in "${!triggers[@]}"; do
if [[ "$file_path" =~ $pattern ]]; then
workflow_type="${triggers[$pattern]}"
triggered_workflows+="$workflow_type "
fi
done
context="WORKFLOW: File modified: $file_path"
if [[ -n "$triggered_workflows" ]]; then
# Slack notification (async)
slack_webhook="${SLACK_WEBHOOK_URL:-}"
if [[ -n "$slack_webhook" ]]; then
slack_payload=$(jq -n \
--arg file "$file_path" \
--arg workflows "$triggered_workflows" \
--arg workspace "$(basename "$PWD")" \
'{
text: ("🔧 Cline modified `" + $file + "` in " + $workspace),
color: "good",
fields: [{
title: "Triggered Workflows",
value: $workflows,
short: true
}]
}')
(curl -X POST -H "Content-Type: application/json" -d "$slack_payload" "$slack_webhook" --max-time 5 --silent > /dev/null 2>&1) &
fi
# CI/CD webhook (async)
ci_webhook="${CI_WEBHOOK_URL:-}"
if [[ -n "$ci_webhook" ]]; then
ci_payload=$(jq -n \
--arg file "$file_path" \
--arg workflows "$triggered_workflows" \
'{
event: "file_modified",
file_path: $file,
workflows: ($workflows | split(" "))
}')
(curl -X POST -H "Content-Type: application/json" -d "$ci_payload" "$ci_webhook" --max-time 5 --silent > /dev/null 2>&1) &
fi
context+=" Triggered workflows: $triggered_workflows. Notifications sent to configured services."
fi
jq -n --arg ctx "$context" '{"cancel": false, "contextModification": $ctx}'
- Multi-service integration patterns
- Asynchronous webhook orchestration
- Complex workflow detection
- Enterprise notification systems
Usage Tips
Running Multiple Hooks
You can use multiple hooks together by creating separate files for each hook type:Copy
Ask AI
# Create hooks directory
mkdir -p .clinerules/hooks
# Create multiple hooks
touch .clinerules/hooks/PreToolUse
touch .clinerules/hooks/PostToolUse
touch .clinerules/hooks/TaskStart
# Make them executable
chmod +x .clinerules/hooks/*
Environment Configuration
Set up environment variables for external integrations:Copy
Ask AI
# Add to your .bashrc or .zshrc
export SLACK_WEBHOOK_URL="https://hooks.slack.com/services/..."
export JIRA_URL="https://yourcompany.atlassian.net"
export JIRA_USER="[email protected]"
export JIRA_TOKEN="your-api-token"
export CI_WEBHOOK_URL="https://your-ci-system.com/hooks/cline"
Testing Your Hooks
Test hooks manually by simulating their input:Copy
Ask AI
# Test a PreToolUse hook
echo '{
"clineVersion": "1.0.0",
"hookName": "PreToolUse",
"timestamp": "2024-01-01T12:00:00Z",
"taskId": "test",
"workspaceRoots": ["/path/to/workspace"],
"userId": "test-user",
"preToolUse": {
"toolName": "write_to_file",
"parameters": {
"path": "test.js",
"content": "console.log(\"test\");"
}
}
}' | .clinerules/hooks/PreToolUse

