Configures Claude Code lifecycle hooks and event handlers in settings.json for SessionStart, PreToolUse, PostToolUse, and 14 others; sets timeouts to prevent cancellations; debugs non-firing hooks.
npx claudepluginhub laurigates/claude-plugins --plugin agent-patterns-pluginThis skill is limited to using the following tools:
Configure Claude Code lifecycle hooks (all 17 events including SessionStart, Stop, PreToolUse, PostToolUse, PostToolUseFailure, PermissionRequest, WorktreeCreate, TeammateIdle, TaskCompleted, ConfigChange, and more) with proper timeout settings to prevent "Hook cancelled" errors during session management.
Guides Next.js Cache Components and Partial Prerendering (PPR) with cacheComponents enabled. Implements 'use cache', cacheLife(), cacheTag(), revalidateTag(), static/dynamic optimization, and cache debugging.
Guides building MCP servers enabling LLMs to interact with external services via tools. Covers best practices, TypeScript/Node (MCP SDK), Python (FastMCP).
Generates original PNG/PDF visual art via design philosophy manifestos for posters, graphics, and static designs on user request.
Configure Claude Code lifecycle hooks (all 17 events including SessionStart, Stop, PreToolUse, PostToolUse, PostToolUseFailure, PermissionRequest, WorktreeCreate, TeammateIdle, TaskCompleted, ConfigChange, and more) with proper timeout settings to prevent "Hook cancelled" errors during session management.
| Hook | Trigger | Default Timeout |
|---|---|---|
SessionStart | When Claude Code session begins | 600s (command) |
SessionEnd | When session ends or /clear runs | 600s (command) |
Stop | When main agent stops responding | 600s (command) |
SubagentStop | When a subagent (Task tool) finishes | 600s (command) |
PreToolUse | Before a tool executes | 600s (command) |
PostToolUse | After a tool completes | 600s (command) |
PostToolUseFailure | After a tool execution fails | 600s (command) |
PermissionRequest | When Claude requests permission for a tool | 600s (command) |
WorktreeCreate | New git worktree created via EnterWorktree | 600s (command) |
WorktreeRemove | Worktree removed after session exits | 600s (command) |
TeammateIdle | Teammate in agent team goes idle | 600s (command) |
TaskCompleted | Task in shared task list marked complete | 600s (command) |
ConfigChange | Claude Code settings change at runtime | 600s (command) |
Default timeouts: command = 600s, prompt = 30s, agent = 60s. Always set explicit timeouts — it documents intent.
| Type | How It Works | Default Timeout | Use When |
|---|---|---|---|
command | Runs a shell command, reads stdin, returns exit code/JSON | 600s | Deterministic rules |
http | Sends hook data to an HTTPS endpoint | 30s | Remote/centralized policy |
prompt | Single-turn LLM call, returns {ok: true/false} | 30s | Judgment on hook input data |
agent | Multi-turn subagent with tool access, returns {ok: true/false} | 60s | Verification needing file/tool access |
async: true on command hooks: fire-and-forget, does not block the operationonce: true on any hook handler: runs only once per session, subsequent triggers skippedFor full event reference, schemas, and examples, see .claude/rules/hooks-reference.md.
SessionEnd hook [bash ~/.claude/session-logger.sh] failed: Hook cancelled
Root cause: Hook execution exceeds the configured timeout. With the 2.1.50 default of 10 minutes, this is now less common — but explicitly setting "timeout" in your hook config is still recommended.
Solutions (in order of preference):
timeout field to hook configurationHooks are configured in .claude/settings.json:
~/.claude/settings.json<project>/.claude/settings.json{
"hooks": {
"SessionEnd": [
{
"matcher": "",
"hooks": [
{
"type": "command",
"command": "~/.claude/session-logger.sh",
"timeout": 120
}
]
}
],
"SessionStart": [
{
"matcher": "",
"hooks": [
{
"type": "command",
"command": "~/.claude/session-setup.sh",
"timeout": 180
}
]
}
],
"Stop": [
{
"matcher": "",
"hooks": [
{
"type": "command",
"command": "~/.claude/stop-hook-git-check.sh",
"timeout": 30
}
]
}
]
}
}
| Hook Type | Recommended Timeout | Use Case |
|---|---|---|
| SessionStart | 120–300s | Tests, linters, dependency checks |
| SessionEnd | 60–120s | Logging, cleanup, state saving |
| Stop / SubagentStop | 30–60s | Git status checks, quick validations |
| PreToolUse | 10–30s | Quick validations |
| PostToolUse | 30–120s | Logging, notifications |
| PermissionRequest | 5–15s | Keep fast for good UX |
The most portable and robust solution is to run slow operations in a background subshell and exit immediately:
#!/bin/bash
# ~/.claude/session-logger.sh
# Exits instantly, work continues in background
(
# All slow operations go here
echo "$(date): Session ended" >> ~/.claude/session.log
curl -s -X POST "https://api.example.com/log" -d "session_end=$(date)"
# Any other slow work...
) &>/dev/null &
exit 0
Why this works:
( ) creates a subshell for the commands& runs the subshell in background&>/dev/null prevents stdout/stderr from blockingexit 0 returns success immediatelyComparison of approaches:
| Approach | Portability | Speed | Notes |
|---|---|---|---|
( ) & | bash, zsh, sh | Instant | Recommended |
disown | Bash-only | Instant | Not POSIX |
nohup | POSIX | Slight overhead | Overkill for hooks |
If you need synchronous execution, add explicit timeout to settings:
cat ~/.claude/settings.json | jq '.hooks'
# Edit to add "timeout": <seconds> to each hook
| Optimization | Pattern |
|---|---|
| Background subshell | ( commands ) &>/dev/null & |
| Fast test modes | --bail=1, -x, --dots |
| Skip heavy operations | Conditional execution |
| Parallel execution | Use & and wait |
If you see:
[WARN] - (starship::utils): Executing command "...node" timed out.
This is a separate starship issue. Fix by adding to ~/.config/starship.toml:
command_timeout = 1000 # 1 second (default is 500ms)
For slow node version detection:
[nodejs]
disabled = false
detect_files = ["package.json"] # Skip .nvmrc to speed up detection
[command]
command_timeout = 2000 # Increase if still timing out
| Context | Command |
|---|---|
| View hooks config | cat ~/.claude/settings.json | jq '.hooks' |
| Test hook script | time bash ~/.claude/session-logger.sh |
| Find slow operations | bash -x ~/.claude/session-logger.sh 2>&1 | head -50 |
| Check starship config | starship config |
| Setting | Location | Default |
|---|---|---|
| Hook timeout | .claude/settings.json → hook → timeout | 10 minutes (600s) since 2.1.50 |
| Starship timeout | ~/.config/starship.toml → command_timeout | 500ms |
| Node detection | ~/.config/starship.toml → [nodejs] | Auto |
| Error | Cause | Fix |
|---|---|---|
| Hook cancelled | Timeout exceeded | Add explicit "timeout" (e.g. "timeout": 120) |
| Hook failed | Script error | Check exit code, add error handling |
| Command not found | Missing script | Verify script path and permissions |
| Permission denied | Script not executable | chmod +x ~/.claude/script.sh |
( ) &>/dev/null & and exit 0timeout field for hooks requiring synchronous executiontime bash ~/.claude/script.sh to measure execution&>/dev/null to prevent blocking on stdout/stderr/hooks menu - Use Claude Code's hook menu to reload settings after changes