gobby 0.2.5__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- gobby/__init__.py +3 -0
- gobby/adapters/__init__.py +30 -0
- gobby/adapters/base.py +93 -0
- gobby/adapters/claude_code.py +276 -0
- gobby/adapters/codex.py +1292 -0
- gobby/adapters/gemini.py +343 -0
- gobby/agents/__init__.py +37 -0
- gobby/agents/codex_session.py +120 -0
- gobby/agents/constants.py +112 -0
- gobby/agents/context.py +362 -0
- gobby/agents/definitions.py +133 -0
- gobby/agents/gemini_session.py +111 -0
- gobby/agents/registry.py +618 -0
- gobby/agents/runner.py +968 -0
- gobby/agents/session.py +259 -0
- gobby/agents/spawn.py +916 -0
- gobby/agents/spawners/__init__.py +77 -0
- gobby/agents/spawners/base.py +142 -0
- gobby/agents/spawners/cross_platform.py +266 -0
- gobby/agents/spawners/embedded.py +225 -0
- gobby/agents/spawners/headless.py +226 -0
- gobby/agents/spawners/linux.py +125 -0
- gobby/agents/spawners/macos.py +277 -0
- gobby/agents/spawners/windows.py +308 -0
- gobby/agents/tty_config.py +319 -0
- gobby/autonomous/__init__.py +32 -0
- gobby/autonomous/progress_tracker.py +447 -0
- gobby/autonomous/stop_registry.py +269 -0
- gobby/autonomous/stuck_detector.py +383 -0
- gobby/cli/__init__.py +67 -0
- gobby/cli/__main__.py +8 -0
- gobby/cli/agents.py +529 -0
- gobby/cli/artifacts.py +266 -0
- gobby/cli/daemon.py +329 -0
- gobby/cli/extensions.py +526 -0
- gobby/cli/github.py +263 -0
- gobby/cli/init.py +53 -0
- gobby/cli/install.py +614 -0
- gobby/cli/installers/__init__.py +37 -0
- gobby/cli/installers/antigravity.py +65 -0
- gobby/cli/installers/claude.py +363 -0
- gobby/cli/installers/codex.py +192 -0
- gobby/cli/installers/gemini.py +294 -0
- gobby/cli/installers/git_hooks.py +377 -0
- gobby/cli/installers/shared.py +737 -0
- gobby/cli/linear.py +250 -0
- gobby/cli/mcp.py +30 -0
- gobby/cli/mcp_proxy.py +698 -0
- gobby/cli/memory.py +304 -0
- gobby/cli/merge.py +384 -0
- gobby/cli/projects.py +79 -0
- gobby/cli/sessions.py +622 -0
- gobby/cli/tasks/__init__.py +30 -0
- gobby/cli/tasks/_utils.py +658 -0
- gobby/cli/tasks/ai.py +1025 -0
- gobby/cli/tasks/commits.py +169 -0
- gobby/cli/tasks/crud.py +685 -0
- gobby/cli/tasks/deps.py +135 -0
- gobby/cli/tasks/labels.py +63 -0
- gobby/cli/tasks/main.py +273 -0
- gobby/cli/tasks/search.py +178 -0
- gobby/cli/tui.py +34 -0
- gobby/cli/utils.py +513 -0
- gobby/cli/workflows.py +927 -0
- gobby/cli/worktrees.py +481 -0
- gobby/config/__init__.py +129 -0
- gobby/config/app.py +551 -0
- gobby/config/extensions.py +167 -0
- gobby/config/features.py +472 -0
- gobby/config/llm_providers.py +98 -0
- gobby/config/logging.py +66 -0
- gobby/config/mcp.py +346 -0
- gobby/config/persistence.py +247 -0
- gobby/config/servers.py +141 -0
- gobby/config/sessions.py +250 -0
- gobby/config/tasks.py +784 -0
- gobby/hooks/__init__.py +104 -0
- gobby/hooks/artifact_capture.py +213 -0
- gobby/hooks/broadcaster.py +243 -0
- gobby/hooks/event_handlers.py +723 -0
- gobby/hooks/events.py +218 -0
- gobby/hooks/git.py +169 -0
- gobby/hooks/health_monitor.py +171 -0
- gobby/hooks/hook_manager.py +856 -0
- gobby/hooks/hook_types.py +575 -0
- gobby/hooks/plugins.py +813 -0
- gobby/hooks/session_coordinator.py +396 -0
- gobby/hooks/verification_runner.py +268 -0
- gobby/hooks/webhooks.py +339 -0
- gobby/install/claude/commands/gobby/bug.md +51 -0
- gobby/install/claude/commands/gobby/chore.md +51 -0
- gobby/install/claude/commands/gobby/epic.md +52 -0
- gobby/install/claude/commands/gobby/eval.md +235 -0
- gobby/install/claude/commands/gobby/feat.md +49 -0
- gobby/install/claude/commands/gobby/nit.md +52 -0
- gobby/install/claude/commands/gobby/ref.md +52 -0
- gobby/install/claude/hooks/HOOK_SCHEMAS.md +632 -0
- gobby/install/claude/hooks/hook_dispatcher.py +364 -0
- gobby/install/claude/hooks/validate_settings.py +102 -0
- gobby/install/claude/hooks-template.json +118 -0
- gobby/install/codex/hooks/hook_dispatcher.py +153 -0
- gobby/install/codex/prompts/forget.md +7 -0
- gobby/install/codex/prompts/memories.md +7 -0
- gobby/install/codex/prompts/recall.md +7 -0
- gobby/install/codex/prompts/remember.md +13 -0
- gobby/install/gemini/hooks/hook_dispatcher.py +268 -0
- gobby/install/gemini/hooks-template.json +138 -0
- gobby/install/shared/plugins/code_guardian.py +456 -0
- gobby/install/shared/plugins/example_notify.py +331 -0
- gobby/integrations/__init__.py +10 -0
- gobby/integrations/github.py +145 -0
- gobby/integrations/linear.py +145 -0
- gobby/llm/__init__.py +40 -0
- gobby/llm/base.py +120 -0
- gobby/llm/claude.py +578 -0
- gobby/llm/claude_executor.py +503 -0
- gobby/llm/codex.py +322 -0
- gobby/llm/codex_executor.py +513 -0
- gobby/llm/executor.py +316 -0
- gobby/llm/factory.py +34 -0
- gobby/llm/gemini.py +258 -0
- gobby/llm/gemini_executor.py +339 -0
- gobby/llm/litellm.py +287 -0
- gobby/llm/litellm_executor.py +303 -0
- gobby/llm/resolver.py +499 -0
- gobby/llm/service.py +236 -0
- gobby/mcp_proxy/__init__.py +29 -0
- gobby/mcp_proxy/actions.py +175 -0
- gobby/mcp_proxy/daemon_control.py +198 -0
- gobby/mcp_proxy/importer.py +436 -0
- gobby/mcp_proxy/lazy.py +325 -0
- gobby/mcp_proxy/manager.py +798 -0
- gobby/mcp_proxy/metrics.py +609 -0
- gobby/mcp_proxy/models.py +139 -0
- gobby/mcp_proxy/registries.py +215 -0
- gobby/mcp_proxy/schema_hash.py +381 -0
- gobby/mcp_proxy/semantic_search.py +706 -0
- gobby/mcp_proxy/server.py +549 -0
- gobby/mcp_proxy/services/__init__.py +0 -0
- gobby/mcp_proxy/services/fallback.py +306 -0
- gobby/mcp_proxy/services/recommendation.py +224 -0
- gobby/mcp_proxy/services/server_mgmt.py +214 -0
- gobby/mcp_proxy/services/system.py +72 -0
- gobby/mcp_proxy/services/tool_filter.py +231 -0
- gobby/mcp_proxy/services/tool_proxy.py +309 -0
- gobby/mcp_proxy/stdio.py +565 -0
- gobby/mcp_proxy/tools/__init__.py +27 -0
- gobby/mcp_proxy/tools/agents.py +1103 -0
- gobby/mcp_proxy/tools/artifacts.py +207 -0
- gobby/mcp_proxy/tools/hub.py +335 -0
- gobby/mcp_proxy/tools/internal.py +337 -0
- gobby/mcp_proxy/tools/memory.py +543 -0
- gobby/mcp_proxy/tools/merge.py +422 -0
- gobby/mcp_proxy/tools/metrics.py +283 -0
- gobby/mcp_proxy/tools/orchestration/__init__.py +23 -0
- gobby/mcp_proxy/tools/orchestration/cleanup.py +619 -0
- gobby/mcp_proxy/tools/orchestration/monitor.py +380 -0
- gobby/mcp_proxy/tools/orchestration/orchestrate.py +746 -0
- gobby/mcp_proxy/tools/orchestration/review.py +736 -0
- gobby/mcp_proxy/tools/orchestration/utils.py +16 -0
- gobby/mcp_proxy/tools/session_messages.py +1056 -0
- gobby/mcp_proxy/tools/task_dependencies.py +219 -0
- gobby/mcp_proxy/tools/task_expansion.py +591 -0
- gobby/mcp_proxy/tools/task_github.py +393 -0
- gobby/mcp_proxy/tools/task_linear.py +379 -0
- gobby/mcp_proxy/tools/task_orchestration.py +77 -0
- gobby/mcp_proxy/tools/task_readiness.py +522 -0
- gobby/mcp_proxy/tools/task_sync.py +351 -0
- gobby/mcp_proxy/tools/task_validation.py +843 -0
- gobby/mcp_proxy/tools/tasks/__init__.py +25 -0
- gobby/mcp_proxy/tools/tasks/_context.py +112 -0
- gobby/mcp_proxy/tools/tasks/_crud.py +516 -0
- gobby/mcp_proxy/tools/tasks/_factory.py +176 -0
- gobby/mcp_proxy/tools/tasks/_helpers.py +129 -0
- gobby/mcp_proxy/tools/tasks/_lifecycle.py +517 -0
- gobby/mcp_proxy/tools/tasks/_lifecycle_validation.py +301 -0
- gobby/mcp_proxy/tools/tasks/_resolution.py +55 -0
- gobby/mcp_proxy/tools/tasks/_search.py +215 -0
- gobby/mcp_proxy/tools/tasks/_session.py +125 -0
- gobby/mcp_proxy/tools/workflows.py +973 -0
- gobby/mcp_proxy/tools/worktrees.py +1264 -0
- gobby/mcp_proxy/transports/__init__.py +0 -0
- gobby/mcp_proxy/transports/base.py +95 -0
- gobby/mcp_proxy/transports/factory.py +44 -0
- gobby/mcp_proxy/transports/http.py +139 -0
- gobby/mcp_proxy/transports/stdio.py +213 -0
- gobby/mcp_proxy/transports/websocket.py +136 -0
- gobby/memory/backends/__init__.py +116 -0
- gobby/memory/backends/mem0.py +408 -0
- gobby/memory/backends/memu.py +485 -0
- gobby/memory/backends/null.py +111 -0
- gobby/memory/backends/openmemory.py +537 -0
- gobby/memory/backends/sqlite.py +304 -0
- gobby/memory/context.py +87 -0
- gobby/memory/manager.py +1001 -0
- gobby/memory/protocol.py +451 -0
- gobby/memory/search/__init__.py +66 -0
- gobby/memory/search/text.py +127 -0
- gobby/memory/viz.py +258 -0
- gobby/prompts/__init__.py +13 -0
- gobby/prompts/defaults/expansion/system.md +119 -0
- gobby/prompts/defaults/expansion/user.md +48 -0
- gobby/prompts/defaults/external_validation/agent.md +72 -0
- gobby/prompts/defaults/external_validation/external.md +63 -0
- gobby/prompts/defaults/external_validation/spawn.md +83 -0
- gobby/prompts/defaults/external_validation/system.md +6 -0
- gobby/prompts/defaults/features/import_mcp.md +22 -0
- gobby/prompts/defaults/features/import_mcp_github.md +17 -0
- gobby/prompts/defaults/features/import_mcp_search.md +16 -0
- gobby/prompts/defaults/features/recommend_tools.md +32 -0
- gobby/prompts/defaults/features/recommend_tools_hybrid.md +35 -0
- gobby/prompts/defaults/features/recommend_tools_llm.md +30 -0
- gobby/prompts/defaults/features/server_description.md +20 -0
- gobby/prompts/defaults/features/server_description_system.md +6 -0
- gobby/prompts/defaults/features/task_description.md +31 -0
- gobby/prompts/defaults/features/task_description_system.md +6 -0
- gobby/prompts/defaults/features/tool_summary.md +17 -0
- gobby/prompts/defaults/features/tool_summary_system.md +6 -0
- gobby/prompts/defaults/research/step.md +58 -0
- gobby/prompts/defaults/validation/criteria.md +47 -0
- gobby/prompts/defaults/validation/validate.md +38 -0
- gobby/prompts/loader.py +346 -0
- gobby/prompts/models.py +113 -0
- gobby/py.typed +0 -0
- gobby/runner.py +488 -0
- gobby/search/__init__.py +23 -0
- gobby/search/protocol.py +104 -0
- gobby/search/tfidf.py +232 -0
- gobby/servers/__init__.py +7 -0
- gobby/servers/http.py +636 -0
- gobby/servers/models.py +31 -0
- gobby/servers/routes/__init__.py +23 -0
- gobby/servers/routes/admin.py +416 -0
- gobby/servers/routes/dependencies.py +118 -0
- gobby/servers/routes/mcp/__init__.py +24 -0
- gobby/servers/routes/mcp/hooks.py +135 -0
- gobby/servers/routes/mcp/plugins.py +121 -0
- gobby/servers/routes/mcp/tools.py +1337 -0
- gobby/servers/routes/mcp/webhooks.py +159 -0
- gobby/servers/routes/sessions.py +582 -0
- gobby/servers/websocket.py +766 -0
- gobby/sessions/__init__.py +13 -0
- gobby/sessions/analyzer.py +322 -0
- gobby/sessions/lifecycle.py +240 -0
- gobby/sessions/manager.py +563 -0
- gobby/sessions/processor.py +225 -0
- gobby/sessions/summary.py +532 -0
- gobby/sessions/transcripts/__init__.py +41 -0
- gobby/sessions/transcripts/base.py +125 -0
- gobby/sessions/transcripts/claude.py +386 -0
- gobby/sessions/transcripts/codex.py +143 -0
- gobby/sessions/transcripts/gemini.py +195 -0
- gobby/storage/__init__.py +21 -0
- gobby/storage/agents.py +409 -0
- gobby/storage/artifact_classifier.py +341 -0
- gobby/storage/artifacts.py +285 -0
- gobby/storage/compaction.py +67 -0
- gobby/storage/database.py +357 -0
- gobby/storage/inter_session_messages.py +194 -0
- gobby/storage/mcp.py +680 -0
- gobby/storage/memories.py +562 -0
- gobby/storage/merge_resolutions.py +550 -0
- gobby/storage/migrations.py +860 -0
- gobby/storage/migrations_legacy.py +1359 -0
- gobby/storage/projects.py +166 -0
- gobby/storage/session_messages.py +251 -0
- gobby/storage/session_tasks.py +97 -0
- gobby/storage/sessions.py +817 -0
- gobby/storage/task_dependencies.py +223 -0
- gobby/storage/tasks/__init__.py +42 -0
- gobby/storage/tasks/_aggregates.py +180 -0
- gobby/storage/tasks/_crud.py +449 -0
- gobby/storage/tasks/_id.py +104 -0
- gobby/storage/tasks/_lifecycle.py +311 -0
- gobby/storage/tasks/_manager.py +889 -0
- gobby/storage/tasks/_models.py +300 -0
- gobby/storage/tasks/_ordering.py +119 -0
- gobby/storage/tasks/_path_cache.py +110 -0
- gobby/storage/tasks/_queries.py +343 -0
- gobby/storage/tasks/_search.py +143 -0
- gobby/storage/workflow_audit.py +393 -0
- gobby/storage/worktrees.py +547 -0
- gobby/sync/__init__.py +29 -0
- gobby/sync/github.py +333 -0
- gobby/sync/linear.py +304 -0
- gobby/sync/memories.py +284 -0
- gobby/sync/tasks.py +641 -0
- gobby/tasks/__init__.py +8 -0
- gobby/tasks/build_verification.py +193 -0
- gobby/tasks/commits.py +633 -0
- gobby/tasks/context.py +747 -0
- gobby/tasks/criteria.py +342 -0
- gobby/tasks/enhanced_validator.py +226 -0
- gobby/tasks/escalation.py +263 -0
- gobby/tasks/expansion.py +626 -0
- gobby/tasks/external_validator.py +764 -0
- gobby/tasks/issue_extraction.py +171 -0
- gobby/tasks/prompts/expand.py +327 -0
- gobby/tasks/research.py +421 -0
- gobby/tasks/tdd.py +352 -0
- gobby/tasks/tree_builder.py +263 -0
- gobby/tasks/validation.py +712 -0
- gobby/tasks/validation_history.py +357 -0
- gobby/tasks/validation_models.py +89 -0
- gobby/tools/__init__.py +0 -0
- gobby/tools/summarizer.py +170 -0
- gobby/tui/__init__.py +5 -0
- gobby/tui/api_client.py +281 -0
- gobby/tui/app.py +327 -0
- gobby/tui/screens/__init__.py +25 -0
- gobby/tui/screens/agents.py +333 -0
- gobby/tui/screens/chat.py +450 -0
- gobby/tui/screens/dashboard.py +377 -0
- gobby/tui/screens/memory.py +305 -0
- gobby/tui/screens/metrics.py +231 -0
- gobby/tui/screens/orchestrator.py +904 -0
- gobby/tui/screens/sessions.py +412 -0
- gobby/tui/screens/tasks.py +442 -0
- gobby/tui/screens/workflows.py +289 -0
- gobby/tui/screens/worktrees.py +174 -0
- gobby/tui/widgets/__init__.py +21 -0
- gobby/tui/widgets/chat.py +210 -0
- gobby/tui/widgets/conductor.py +104 -0
- gobby/tui/widgets/menu.py +132 -0
- gobby/tui/widgets/message_panel.py +160 -0
- gobby/tui/widgets/review_gate.py +224 -0
- gobby/tui/widgets/task_tree.py +99 -0
- gobby/tui/widgets/token_budget.py +166 -0
- gobby/tui/ws_client.py +258 -0
- gobby/utils/__init__.py +3 -0
- gobby/utils/daemon_client.py +235 -0
- gobby/utils/git.py +222 -0
- gobby/utils/id.py +38 -0
- gobby/utils/json_helpers.py +161 -0
- gobby/utils/logging.py +376 -0
- gobby/utils/machine_id.py +135 -0
- gobby/utils/metrics.py +589 -0
- gobby/utils/project_context.py +182 -0
- gobby/utils/project_init.py +263 -0
- gobby/utils/status.py +256 -0
- gobby/utils/validation.py +80 -0
- gobby/utils/version.py +23 -0
- gobby/workflows/__init__.py +4 -0
- gobby/workflows/actions.py +1310 -0
- gobby/workflows/approval_flow.py +138 -0
- gobby/workflows/artifact_actions.py +103 -0
- gobby/workflows/audit_helpers.py +110 -0
- gobby/workflows/autonomous_actions.py +286 -0
- gobby/workflows/context_actions.py +394 -0
- gobby/workflows/definitions.py +130 -0
- gobby/workflows/detection_helpers.py +208 -0
- gobby/workflows/engine.py +485 -0
- gobby/workflows/evaluator.py +669 -0
- gobby/workflows/git_utils.py +96 -0
- gobby/workflows/hooks.py +169 -0
- gobby/workflows/lifecycle_evaluator.py +613 -0
- gobby/workflows/llm_actions.py +70 -0
- gobby/workflows/loader.py +333 -0
- gobby/workflows/mcp_actions.py +60 -0
- gobby/workflows/memory_actions.py +272 -0
- gobby/workflows/premature_stop.py +164 -0
- gobby/workflows/session_actions.py +139 -0
- gobby/workflows/state_actions.py +123 -0
- gobby/workflows/state_manager.py +104 -0
- gobby/workflows/stop_signal_actions.py +163 -0
- gobby/workflows/summary_actions.py +344 -0
- gobby/workflows/task_actions.py +249 -0
- gobby/workflows/task_enforcement_actions.py +901 -0
- gobby/workflows/templates.py +52 -0
- gobby/workflows/todo_actions.py +84 -0
- gobby/workflows/webhook.py +223 -0
- gobby/workflows/webhook_executor.py +399 -0
- gobby/worktrees/__init__.py +5 -0
- gobby/worktrees/git.py +690 -0
- gobby/worktrees/merge/__init__.py +20 -0
- gobby/worktrees/merge/conflict_parser.py +177 -0
- gobby/worktrees/merge/resolver.py +485 -0
- gobby-0.2.5.dist-info/METADATA +351 -0
- gobby-0.2.5.dist-info/RECORD +383 -0
- gobby-0.2.5.dist-info/WHEEL +5 -0
- gobby-0.2.5.dist-info/entry_points.txt +2 -0
- gobby-0.2.5.dist-info/licenses/LICENSE.md +193 -0
- gobby-0.2.5.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,632 @@
|
|
|
1
|
+
# Claude Code Hook Schemas Reference
|
|
2
|
+
|
|
3
|
+
This document defines the input and output schemas for all Claude Code hooks.
|
|
4
|
+
|
|
5
|
+
## Table of Contents
|
|
6
|
+
|
|
7
|
+
- [SessionStart Hook](#sessionstart-hook)
|
|
8
|
+
- [SessionEnd Hook](#sessionend-hook)
|
|
9
|
+
- [UserPromptSubmit Hook](#userpromptsubmit-hook)
|
|
10
|
+
- [PreToolUse Hook](#pretooluse-hook)
|
|
11
|
+
- [PostToolUse Hook](#posttooluse-hook)
|
|
12
|
+
- [PreCompact Hook](#precompact-hook)
|
|
13
|
+
- [Stop Hook](#stop-hook)
|
|
14
|
+
- [SubagentStart Hook](#subagentstart-hook)
|
|
15
|
+
- [SubagentStop Hook](#subagentstop-hook)
|
|
16
|
+
- [Notification Hook](#notification-hook)
|
|
17
|
+
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
## SessionStart Hook
|
|
21
|
+
|
|
22
|
+
**Trigger**: When a Claude Code session starts (startup, resume, `/clear`, or compact)
|
|
23
|
+
|
|
24
|
+
### Input Schema
|
|
25
|
+
|
|
26
|
+
```json
|
|
27
|
+
{
|
|
28
|
+
"session_id": "550e8400-e29b-41d4-a716-446655440000",
|
|
29
|
+
"transcript_path": "/Users/josh/.claude/projects/my-project/session.jsonl",
|
|
30
|
+
"hook_event_name": "SessionStart",
|
|
31
|
+
"source": "startup",
|
|
32
|
+
"machine_id": "847EB0AC-1A34-51F1-A15C-75F37C9ECE90"
|
|
33
|
+
}
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
**Fields:**
|
|
37
|
+
|
|
38
|
+
- `session_id` (string, optional): Unique session identifier (UUID format). **Note**: Only available when `source` is "resume", "clear", or "compact". On initial "startup", session_id is not yet generated.
|
|
39
|
+
- `transcript_path` (string, required): Path to the JSONL conversation transcript file
|
|
40
|
+
- `hook_event_name` (string, required): Always "SessionStart"
|
|
41
|
+
- `source` (string, required): How session started - one of:
|
|
42
|
+
- `"startup"`: Normal Claude Code launch (session_id not yet available)
|
|
43
|
+
- `"resume"`: From `--resume`, `--continue`, or `/resume` commands
|
|
44
|
+
- `"clear"`: From `/clear` command (new session)
|
|
45
|
+
- `"compact"`: From auto or manual compact operations
|
|
46
|
+
- `machine_id` (string, optional): Unique machine identifier
|
|
47
|
+
|
|
48
|
+
### Output Schema
|
|
49
|
+
|
|
50
|
+
**Option 1: Context Injection (Recommended)**
|
|
51
|
+
|
|
52
|
+
```json
|
|
53
|
+
{
|
|
54
|
+
"systemMessage": "## Session Started\n\n- **Session ID**: `550e8400-...`\n- Machine ID: `847EB0AC-...`"
|
|
55
|
+
}
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
**Option 2: Simple Status**
|
|
59
|
+
|
|
60
|
+
```json
|
|
61
|
+
{
|
|
62
|
+
"status": "session_started"
|
|
63
|
+
}
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
**Fields:**
|
|
67
|
+
|
|
68
|
+
- `systemMessage` (string, optional): Markdown text to inject into Claude's context (works for all hooks)
|
|
69
|
+
- `hookSpecificOutput.additionalContext` (string, optional): Alternative for SessionStart, UserPromptSubmit, PostToolUse only
|
|
70
|
+
- `status` (string, optional): Hook execution status
|
|
71
|
+
|
|
72
|
+
**Exit Codes:**
|
|
73
|
+
|
|
74
|
+
- `0`: Success (stdout added to Claude's context)
|
|
75
|
+
- `1`: Error (stderr logged, hook continues)
|
|
76
|
+
|
|
77
|
+
---
|
|
78
|
+
|
|
79
|
+
## SessionEnd Hook
|
|
80
|
+
|
|
81
|
+
**Trigger**: When a Claude Code session ends
|
|
82
|
+
|
|
83
|
+
### Input Schema
|
|
84
|
+
|
|
85
|
+
```json
|
|
86
|
+
{
|
|
87
|
+
"session_id": "550e8400-e29b-41d4-a716-446655440000",
|
|
88
|
+
"hook_event_name": "SessionEnd",
|
|
89
|
+
"reason": "clear",
|
|
90
|
+
"machine_id": "847EB0AC-1A34-51F1-A15C-75F37C9ECE90"
|
|
91
|
+
}
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
**Fields:**
|
|
95
|
+
|
|
96
|
+
- `session_id` (string, required): Session identifier that is ending
|
|
97
|
+
- `hook_event_name` (string, required): Always "SessionEnd"
|
|
98
|
+
- `reason` (string, required): Why session ended - one of:
|
|
99
|
+
- `"clear"`: User executed `/clear` command
|
|
100
|
+
- `"logout"`: User logged out
|
|
101
|
+
- `"prompt_input_exit"`: User exited via prompt
|
|
102
|
+
- `"other"`: Other reasons
|
|
103
|
+
- `machine_id` (string, optional): Unique machine identifier
|
|
104
|
+
|
|
105
|
+
### Output Schema
|
|
106
|
+
|
|
107
|
+
```json
|
|
108
|
+
{
|
|
109
|
+
"status": "session_ended"
|
|
110
|
+
}
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
**Fields:**
|
|
114
|
+
|
|
115
|
+
- `status` (string, optional): Hook execution status
|
|
116
|
+
|
|
117
|
+
**Exit Codes:**
|
|
118
|
+
|
|
119
|
+
- `0`: Success
|
|
120
|
+
- `1`: Error (logged but ignored)
|
|
121
|
+
|
|
122
|
+
---
|
|
123
|
+
|
|
124
|
+
## UserPromptSubmit Hook
|
|
125
|
+
|
|
126
|
+
**Trigger**: When user submits a prompt (before Claude processes it)
|
|
127
|
+
|
|
128
|
+
### Input Schema
|
|
129
|
+
|
|
130
|
+
```json
|
|
131
|
+
{
|
|
132
|
+
"session_id": "550e8400-e29b-41d4-a716-446655440000",
|
|
133
|
+
"prompt": "Write a function to calculate factorial",
|
|
134
|
+
"transcript_path": "/Users/josh/.claude/projects/my-project/session.jsonl",
|
|
135
|
+
"cwd": "/Users/josh/projects/my-project",
|
|
136
|
+
"permission_mode": "default",
|
|
137
|
+
"hook_event_name": "UserPromptSubmit",
|
|
138
|
+
"machine_id": "847EB0AC-1A34-51F1-A15C-75F37C9ECE90"
|
|
139
|
+
}
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
**Fields:**
|
|
143
|
+
|
|
144
|
+
- `session_id` (string, required): Current session identifier
|
|
145
|
+
- `prompt` (string, required): The user's submitted text
|
|
146
|
+
- `transcript_path` (string, required): Path to conversation transcript
|
|
147
|
+
- `cwd` (string, required): Current working directory
|
|
148
|
+
- `permission_mode` (string, required): Permission mode (e.g., "default", "acceptEdits")
|
|
149
|
+
- `hook_event_name` (string, required): Always "UserPromptSubmit"
|
|
150
|
+
- `machine_id` (string, optional): Unique machine identifier
|
|
151
|
+
|
|
152
|
+
### Output Schema
|
|
153
|
+
|
|
154
|
+
**Option 1: Approve (default)**
|
|
155
|
+
|
|
156
|
+
```json
|
|
157
|
+
{
|
|
158
|
+
"status": "approved"
|
|
159
|
+
}
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
**Option 2: Reject with feedback**
|
|
163
|
+
|
|
164
|
+
```json
|
|
165
|
+
{
|
|
166
|
+
"status": "rejected",
|
|
167
|
+
"message": "Prompt contains sensitive information"
|
|
168
|
+
}
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
**Option 3: Modify prompt**
|
|
172
|
+
|
|
173
|
+
```json
|
|
174
|
+
{
|
|
175
|
+
"status": "approved",
|
|
176
|
+
"modified_prompt": "Enhanced prompt with additional context..."
|
|
177
|
+
}
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
**Fields:**
|
|
181
|
+
|
|
182
|
+
- `status` (string, required): Either "approved" or "rejected"
|
|
183
|
+
- `message` (string, optional): Feedback message shown to user (if rejected)
|
|
184
|
+
- `modified_prompt` (string, optional): Replacement prompt text
|
|
185
|
+
|
|
186
|
+
**Exit Codes:**
|
|
187
|
+
|
|
188
|
+
- `0`: Success, prompt approved
|
|
189
|
+
- `2`: Block prompt and show stderr to user
|
|
190
|
+
- `1`: Error (logged)
|
|
191
|
+
|
|
192
|
+
---
|
|
193
|
+
|
|
194
|
+
## PreToolUse Hook
|
|
195
|
+
|
|
196
|
+
**Trigger**: Before Claude Code executes a tool
|
|
197
|
+
|
|
198
|
+
### Input Schema
|
|
199
|
+
|
|
200
|
+
```json
|
|
201
|
+
{
|
|
202
|
+
"session_id": "550e8400-e29b-41d4-a716-446655440000",
|
|
203
|
+
"tool_name": "Edit",
|
|
204
|
+
"tool_input": {
|
|
205
|
+
"file_path": "/path/to/file.py",
|
|
206
|
+
"old_string": "foo",
|
|
207
|
+
"new_string": "bar"
|
|
208
|
+
},
|
|
209
|
+
"machine_id": "847EB0AC-1A34-51F1-A15C-75F37C9ECE90"
|
|
210
|
+
}
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
**Fields:**
|
|
214
|
+
|
|
215
|
+
- `session_id` (string, required): Current session identifier
|
|
216
|
+
- `tool_name` (string, required): Name of tool about to execute (e.g., "Edit", "Bash", "Read")
|
|
217
|
+
- `tool_input` (object, optional): Tool parameters as key-value pairs
|
|
218
|
+
- `machine_id` (string, optional): Unique machine identifier
|
|
219
|
+
|
|
220
|
+
### Output Schema
|
|
221
|
+
|
|
222
|
+
**Option 1: Allow (default)**
|
|
223
|
+
|
|
224
|
+
```json
|
|
225
|
+
{
|
|
226
|
+
"status": "allowed"
|
|
227
|
+
}
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
**Option 2: Block with reason**
|
|
231
|
+
|
|
232
|
+
```json
|
|
233
|
+
{
|
|
234
|
+
"status": "blocked",
|
|
235
|
+
"reason": "Tool not permitted in this context"
|
|
236
|
+
}
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
**Fields:**
|
|
240
|
+
|
|
241
|
+
- `status` (string, required): Either "allowed" or "blocked"
|
|
242
|
+
- `reason` (string, optional): Explanation if blocked
|
|
243
|
+
|
|
244
|
+
**Exit Codes:**
|
|
245
|
+
|
|
246
|
+
- `0`: Success, tool allowed
|
|
247
|
+
- `2`: Block tool execution and show stderr to user
|
|
248
|
+
- `1`: Error (logged)
|
|
249
|
+
|
|
250
|
+
---
|
|
251
|
+
|
|
252
|
+
## PostToolUse Hook
|
|
253
|
+
|
|
254
|
+
**Trigger**: After Claude Code executes a tool
|
|
255
|
+
|
|
256
|
+
### Input Schema
|
|
257
|
+
|
|
258
|
+
```json
|
|
259
|
+
{
|
|
260
|
+
"session_id": "550e8400-e29b-41d4-a716-446655440000",
|
|
261
|
+
"tool_name": "Edit",
|
|
262
|
+
"tool_input": {
|
|
263
|
+
"file_path": "/path/to/file.py",
|
|
264
|
+
"old_string": "foo",
|
|
265
|
+
"new_string": "bar"
|
|
266
|
+
},
|
|
267
|
+
"tool_output": {
|
|
268
|
+
"success": true,
|
|
269
|
+
"message": "File updated successfully"
|
|
270
|
+
},
|
|
271
|
+
"machine_id": "847EB0AC-1A34-51F1-A15C-75F37C9ECE90"
|
|
272
|
+
}
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
**Fields:**
|
|
276
|
+
|
|
277
|
+
- `session_id` (string, required): Current session identifier
|
|
278
|
+
- `tool_name` (string, required): Name of tool that executed
|
|
279
|
+
- `tool_input` (object, optional): Tool parameters that were used
|
|
280
|
+
- `tool_output` (object, optional): Result returned by the tool
|
|
281
|
+
- `machine_id` (string, optional): Unique machine identifier
|
|
282
|
+
|
|
283
|
+
### Output Schema
|
|
284
|
+
|
|
285
|
+
```json
|
|
286
|
+
{
|
|
287
|
+
"status": "processed"
|
|
288
|
+
}
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
**Fields:**
|
|
292
|
+
|
|
293
|
+
- `status` (string, optional): Hook execution status
|
|
294
|
+
|
|
295
|
+
**Exit Codes:**
|
|
296
|
+
|
|
297
|
+
- `0`: Success
|
|
298
|
+
- `1`: Error (logged but tool execution continues)
|
|
299
|
+
|
|
300
|
+
---
|
|
301
|
+
|
|
302
|
+
## PreCompact Hook
|
|
303
|
+
|
|
304
|
+
**Trigger**: Before Claude Code compacts the conversation context
|
|
305
|
+
|
|
306
|
+
### Input Schema
|
|
307
|
+
|
|
308
|
+
```json
|
|
309
|
+
{
|
|
310
|
+
"session_id": "550e8400-e29b-41d4-a716-446655440000",
|
|
311
|
+
"transcript_path": "/Users/josh/.claude/projects/my-project/session.jsonl",
|
|
312
|
+
"hook_event_name": "PreCompact",
|
|
313
|
+
"trigger": "auto",
|
|
314
|
+
"custom_instructions": null,
|
|
315
|
+
"machine_id": "847EB0AC-1A34-51F1-A15C-75F37C9ECE90"
|
|
316
|
+
}
|
|
317
|
+
```
|
|
318
|
+
|
|
319
|
+
**Fields:**
|
|
320
|
+
|
|
321
|
+
- `session_id` (string, required): Current session identifier
|
|
322
|
+
- `transcript_path` (string, required): Path to conversation transcript
|
|
323
|
+
- `hook_event_name` (string, required): Always "PreCompact"
|
|
324
|
+
- `trigger` (string, required): How compact was triggered - one of:
|
|
325
|
+
- `"auto"`: Automatic compact (context window limit)
|
|
326
|
+
- `"manual"`: User manually triggered compact
|
|
327
|
+
- `custom_instructions` (string, optional): Custom instructions if manually triggered
|
|
328
|
+
- `machine_id` (string, optional): Unique machine identifier
|
|
329
|
+
|
|
330
|
+
### Output Schema
|
|
331
|
+
|
|
332
|
+
```json
|
|
333
|
+
{
|
|
334
|
+
"status": "ready_to_compact"
|
|
335
|
+
}
|
|
336
|
+
```
|
|
337
|
+
|
|
338
|
+
**Fields:**
|
|
339
|
+
|
|
340
|
+
- `status` (string, optional): Hook execution status
|
|
341
|
+
|
|
342
|
+
**Exit Codes:**
|
|
343
|
+
|
|
344
|
+
- `0`: Success
|
|
345
|
+
- `1`: Error (logged but compact continues)
|
|
346
|
+
|
|
347
|
+
---
|
|
348
|
+
|
|
349
|
+
## Stop Hook
|
|
350
|
+
|
|
351
|
+
**Trigger**: When Claude Code session is stopping
|
|
352
|
+
|
|
353
|
+
### Input Schema
|
|
354
|
+
|
|
355
|
+
```json
|
|
356
|
+
{
|
|
357
|
+
"session_id": "550e8400-e29b-41d4-a716-446655440000",
|
|
358
|
+
"reason": "user_exit",
|
|
359
|
+
"metadata": {},
|
|
360
|
+
"machine_id": "847EB0AC-1A34-51F1-A15C-75F37C9ECE90"
|
|
361
|
+
}
|
|
362
|
+
```
|
|
363
|
+
|
|
364
|
+
**Fields:**
|
|
365
|
+
|
|
366
|
+
- `session_id` (string, required): Session identifier being stopped
|
|
367
|
+
- `reason` (string, optional): Reason for stopping
|
|
368
|
+
- `metadata` (object, optional): Additional context about the stop
|
|
369
|
+
- `machine_id` (string, optional): Unique machine identifier
|
|
370
|
+
|
|
371
|
+
### Output Schema
|
|
372
|
+
|
|
373
|
+
```json
|
|
374
|
+
{
|
|
375
|
+
"status": "stopped"
|
|
376
|
+
}
|
|
377
|
+
```
|
|
378
|
+
|
|
379
|
+
**Fields:**
|
|
380
|
+
|
|
381
|
+
- `status` (string, optional): Hook execution status
|
|
382
|
+
|
|
383
|
+
**Exit Codes:**
|
|
384
|
+
|
|
385
|
+
- `0`: Success
|
|
386
|
+
- `1`: Error (logged)
|
|
387
|
+
|
|
388
|
+
---
|
|
389
|
+
|
|
390
|
+
## SubagentStart Hook
|
|
391
|
+
|
|
392
|
+
**Trigger**: When a subagent (spawned via Task tool) is starting
|
|
393
|
+
|
|
394
|
+
### Input Schema
|
|
395
|
+
|
|
396
|
+
```json
|
|
397
|
+
{
|
|
398
|
+
"session_id": "550e8400-e29b-41d4-a716-446655440000",
|
|
399
|
+
"subagent_id": "agent-abc123",
|
|
400
|
+
"agent_id": "task-executor",
|
|
401
|
+
"agent_transcript_path": "/Users/josh/.claude/projects/my-project/.claude/task-abc123.jsonl",
|
|
402
|
+
"metadata": {},
|
|
403
|
+
"machine_id": "847EB0AC-1A34-51F1-A15C-75F37C9ECE90"
|
|
404
|
+
}
|
|
405
|
+
```
|
|
406
|
+
|
|
407
|
+
**Fields:**
|
|
408
|
+
|
|
409
|
+
- `session_id` (string, required): Current session identifier (stored as `external_id` in Gobby)
|
|
410
|
+
- `subagent_id` (string, required): Unique identifier for the subagent instance
|
|
411
|
+
- `agent_id` (string, optional): Type/name of the subagent (e.g., "task-executor", "Explore", "Plan")
|
|
412
|
+
- `agent_transcript_path` (string, optional): Path to the subagent's conversation transcript
|
|
413
|
+
- `metadata` (object, optional): Additional context about the subagent
|
|
414
|
+
- `machine_id` (string, optional): Unique machine identifier
|
|
415
|
+
|
|
416
|
+
### Output Schema
|
|
417
|
+
|
|
418
|
+
```json
|
|
419
|
+
{
|
|
420
|
+
"status": "subagent_started"
|
|
421
|
+
}
|
|
422
|
+
```
|
|
423
|
+
|
|
424
|
+
**Fields:**
|
|
425
|
+
|
|
426
|
+
- `status` (string, optional): Hook execution status
|
|
427
|
+
|
|
428
|
+
**Exit Codes:**
|
|
429
|
+
|
|
430
|
+
- `0`: Success
|
|
431
|
+
- `1`: Error (logged)
|
|
432
|
+
|
|
433
|
+
**Use Cases:**
|
|
434
|
+
|
|
435
|
+
- Track when subagents are created
|
|
436
|
+
- Initialize subagent-specific state
|
|
437
|
+
- Inject context into subagent's conversation
|
|
438
|
+
- Log subagent creation for analytics
|
|
439
|
+
|
|
440
|
+
---
|
|
441
|
+
|
|
442
|
+
## SubagentStop Hook
|
|
443
|
+
|
|
444
|
+
**Trigger**: When a subagent (spawned via Task tool) is stopping
|
|
445
|
+
|
|
446
|
+
### Input Schema
|
|
447
|
+
|
|
448
|
+
```json
|
|
449
|
+
{
|
|
450
|
+
"session_id": "550e8400-e29b-41d4-a716-446655440000",
|
|
451
|
+
"subagent_id": "agent-abc123",
|
|
452
|
+
"agent_id": "task-executor",
|
|
453
|
+
"agent_transcript_path": "/Users/josh/.claude/projects/my-project/.claude/task-abc123.jsonl",
|
|
454
|
+
"reason": "task_completed",
|
|
455
|
+
"metadata": {},
|
|
456
|
+
"machine_id": "847EB0AC-1A34-51F1-A15C-75F37C9ECE90"
|
|
457
|
+
}
|
|
458
|
+
```
|
|
459
|
+
|
|
460
|
+
**Fields:**
|
|
461
|
+
|
|
462
|
+
- `session_id` (string, required): Current session identifier (stored as `external_id` in Gobby)
|
|
463
|
+
- `subagent_id` (string, required): Unique identifier for the subagent instance
|
|
464
|
+
- `agent_id` (string, optional): Type/name of the subagent (e.g., "task-executor", "Explore", "Plan")
|
|
465
|
+
- `agent_transcript_path` (string, optional): Path to the subagent's conversation transcript
|
|
466
|
+
- `reason` (string, optional): Why subagent is stopping
|
|
467
|
+
- `metadata` (object, optional): Additional context
|
|
468
|
+
- `machine_id` (string, optional): Unique machine identifier
|
|
469
|
+
|
|
470
|
+
### Output Schema
|
|
471
|
+
|
|
472
|
+
```json
|
|
473
|
+
{
|
|
474
|
+
"status": "subagent_stopped"
|
|
475
|
+
}
|
|
476
|
+
```
|
|
477
|
+
|
|
478
|
+
**Fields:**
|
|
479
|
+
|
|
480
|
+
- `status` (string, optional): Hook execution status
|
|
481
|
+
|
|
482
|
+
**Exit Codes:**
|
|
483
|
+
|
|
484
|
+
- `0`: Success
|
|
485
|
+
- `1`: Error (logged)
|
|
486
|
+
|
|
487
|
+
---
|
|
488
|
+
|
|
489
|
+
## Notification Hook
|
|
490
|
+
|
|
491
|
+
**Trigger**: When Claude Code sends a notification
|
|
492
|
+
|
|
493
|
+
### Input Schema
|
|
494
|
+
|
|
495
|
+
```json
|
|
496
|
+
{
|
|
497
|
+
"session_id": "550e8400-e29b-41d4-a716-446655440000",
|
|
498
|
+
"notification_type": "info",
|
|
499
|
+
"message": "Task completed successfully",
|
|
500
|
+
"severity": "info",
|
|
501
|
+
"metadata": {},
|
|
502
|
+
"machine_id": "847EB0AC-1A34-51F1-A15C-75F37C9ECE90"
|
|
503
|
+
}
|
|
504
|
+
```
|
|
505
|
+
|
|
506
|
+
**Fields:**
|
|
507
|
+
|
|
508
|
+
- `session_id` (string, required): Current session identifier
|
|
509
|
+
- `notification_type` (string, required): Type of notification
|
|
510
|
+
- `message` (string, required): Notification message text
|
|
511
|
+
- `severity` (string, optional): Severity level - one of:
|
|
512
|
+
- `"info"`: Informational message
|
|
513
|
+
- `"warning"`: Warning message
|
|
514
|
+
- `"error"`: Error message
|
|
515
|
+
- `metadata` (object, optional): Additional context
|
|
516
|
+
- `machine_id` (string, optional): Unique machine identifier
|
|
517
|
+
|
|
518
|
+
### Output Schema
|
|
519
|
+
|
|
520
|
+
```json
|
|
521
|
+
{
|
|
522
|
+
"status": "notification_received"
|
|
523
|
+
}
|
|
524
|
+
```
|
|
525
|
+
|
|
526
|
+
**Fields:**
|
|
527
|
+
|
|
528
|
+
- `status` (string, optional): Hook execution status
|
|
529
|
+
|
|
530
|
+
**Exit Codes:**
|
|
531
|
+
|
|
532
|
+
- `0`: Success
|
|
533
|
+
- `1`: Error (logged)
|
|
534
|
+
|
|
535
|
+
---
|
|
536
|
+
|
|
537
|
+
## Common Patterns
|
|
538
|
+
|
|
539
|
+
### Exit Codes Summary
|
|
540
|
+
|
|
541
|
+
| Exit Code | Meaning | Behavior |
|
|
542
|
+
|-----------|---------|----------|
|
|
543
|
+
| `0` | Success | Hook output processed normally |
|
|
544
|
+
| `1` | Error | Error logged, execution continues |
|
|
545
|
+
| `2` | Block | Blocks operation and shows stderr to user |
|
|
546
|
+
|
|
547
|
+
### Context Injection
|
|
548
|
+
|
|
549
|
+
**Recommended:** Use `systemMessage` at the top level (works for ALL hooks):
|
|
550
|
+
|
|
551
|
+
```json
|
|
552
|
+
{
|
|
553
|
+
"systemMessage": "Your markdown text here..."
|
|
554
|
+
}
|
|
555
|
+
```
|
|
556
|
+
|
|
557
|
+
**Alternative (limited):** Use `hookSpecificOutput.additionalContext` (only works for SessionStart, UserPromptSubmit, PostToolUse):
|
|
558
|
+
|
|
559
|
+
```json
|
|
560
|
+
{
|
|
561
|
+
"hookSpecificOutput": {
|
|
562
|
+
"hookEventName": "<HookName>",
|
|
563
|
+
"additionalContext": "Your markdown text here..."
|
|
564
|
+
}
|
|
565
|
+
}
|
|
566
|
+
```
|
|
567
|
+
|
|
568
|
+
**Important:** The `additionalContext` field does NOT work for `PreToolUse` hooks. Always prefer `systemMessage` for reliable context injection across all hook types.
|
|
569
|
+
|
|
570
|
+
The injected content appears in `<system-reminder>` tags in Claude's context window.
|
|
571
|
+
|
|
572
|
+
### Machine ID
|
|
573
|
+
|
|
574
|
+
The `machine_id` field is a unique, persistent identifier for the machine running Claude Code. It's useful for:
|
|
575
|
+
|
|
576
|
+
- Tracking sessions across multiple machines
|
|
577
|
+
- Machine-specific configuration
|
|
578
|
+
- Analytics and logging
|
|
579
|
+
|
|
580
|
+
Generated using hardware identifiers (MAC address, disk serial, etc.) and cached in `/tmp/gobby_machine_id.txt`.
|
|
581
|
+
|
|
582
|
+
---
|
|
583
|
+
|
|
584
|
+
## Implementation Notes
|
|
585
|
+
|
|
586
|
+
### Hook Execution Flow
|
|
587
|
+
|
|
588
|
+
1. **Claude Code** → Sends JSON input to hook script via stdin
|
|
589
|
+
2. **Hook Script** → Reads stdin, processes data
|
|
590
|
+
3. **Hook Script** → Writes JSON output to stdout
|
|
591
|
+
4. **Hook Script** → Exits with appropriate exit code
|
|
592
|
+
5. **Claude Code** → Processes output based on exit code
|
|
593
|
+
|
|
594
|
+
### Error Handling
|
|
595
|
+
|
|
596
|
+
Hooks should handle errors gracefully:
|
|
597
|
+
|
|
598
|
+
- Log errors to stderr (will appear in hook logs)
|
|
599
|
+
- Return appropriate exit code
|
|
600
|
+
- Provide helpful error messages to user if needed
|
|
601
|
+
|
|
602
|
+
### Best Practices
|
|
603
|
+
|
|
604
|
+
1. **Always validate input**: Check required fields exist before using them
|
|
605
|
+
2. **Use exit codes correctly**:
|
|
606
|
+
- `0` for normal operation
|
|
607
|
+
- `2` only when you need to block and notify user
|
|
608
|
+
- `1` for internal errors
|
|
609
|
+
3. **Keep processing fast**: Hooks block Claude Code execution
|
|
610
|
+
4. **Log useful information**: Use structured logging for debugging
|
|
611
|
+
5. **Test with sample data**: Use the schemas above to create test inputs
|
|
612
|
+
|
|
613
|
+
---
|
|
614
|
+
|
|
615
|
+
## Testing Hooks
|
|
616
|
+
|
|
617
|
+
Test hooks manually using echo and piping:
|
|
618
|
+
|
|
619
|
+
```bash
|
|
620
|
+
# Test SessionStart hook
|
|
621
|
+
echo '{"session_id": "test-123", "transcript_path": "/tmp/test.jsonl", "hook_event_name": "SessionStart", "source": "startup"}' | \
|
|
622
|
+
python .claude/hooks/session-start.py
|
|
623
|
+
|
|
624
|
+
# Test UserPromptSubmit hook
|
|
625
|
+
echo '{"session_id": "test-123", "prompt": "Hello", "hook_event_name": "UserPromptSubmit"}' | \
|
|
626
|
+
python .claude/hooks/user-prompt-submit.py
|
|
627
|
+
```
|
|
628
|
+
|
|
629
|
+
---
|
|
630
|
+
|
|
631
|
+
*Last Updated: 2025-11-17*
|
|
632
|
+
*Claude Code Version: Compatible with v2.0.43+ (SubagentStart hook support)*
|