-
Notifications
You must be signed in to change notification settings - Fork 2.8k
feat: implement Claude Code-style hooks system #10785
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
Add lifecycle hooks for tool execution with 12 event types: - PreToolUse, PostToolUse, PostToolUseFailure, PermissionRequest - SessionStart, SessionEnd, Stop, SubagentStart, SubagentStop - UserPromptSubmit, Notification, PreCompact Core implementation: - HookManager service with config loading, validation, and execution - HookExecutor for shell command execution with timeout, stdin JSON, env vars - HookConfigLoader with project/global/mode-specific precedence - HookMatcher for pattern matching (exact, regex, glob) - ToolExecutionHooks adapter for pipeline interception Tool pipeline integration: - PreToolUse hooks can block or modify tool input - PostToolUse/PostToolUseFailure for non-blocking notifications - PermissionRequest hooks before approval prompts Webview UI: - Hooks tab in Settings with enable/disable toggles - Hook Activity log with real-time status updates - Reload config and open folder actions Includes comprehensive tests for all components. Relates to: Claude Code hooks feature parity
Review of commit
Mention @roomote in a comment to request specific changes to this pull request or fix all unresolved issues. |
| timestamp: exec.timestamp.toISOString(), | ||
| hookId: exec.hook.id, | ||
| event: exec.event, | ||
| toolName: exec.result.hook.matcher ? undefined : undefined, // Tool name is in context, not easily accessible here |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This ternary expression always evaluates to undefined regardless of the condition (exec.result.hook.matcher ? undefined : undefined). The comment suggests this was intentional because extracting the tool name is difficult, but the condition serves no purpose and makes the code misleading. Consider simplifying to just toolName: undefined to make the intent clear, or actually extracting the tool name if it's available in the execution context.
| toolName: exec.result.hook.matcher ? undefined : undefined, // Tool name is in context, not easily accessible here | |
| toolName: undefined, // Tool name is in context, not easily accessible here |
Fix it with Roo Code or mention @roomote and request a fix.
Update Hooks UI to explicitly document that matchers use Roo Code internal tool IDs (e.g. write_to_file, execute_command) rather than display labels. Add regression test ensuring display labels do not unintentionally match internal IDs.
Add open project/global folder buttons at bottom Move reload to bottom Add enable-all toggle (with new message type) Convert hooks list to accordion + per-hook logs
- Add switch, status dot, and delete button to HooksSettings UI - Implement backend support for hook deletion - Add safeWriteText utility - Update translation strings - Add UI and backend tests for new functionality
Implement hooks experimental flag with conditional UI rendering and backend functionality gating. Fix missing experimental settings translations for hooks feature. Fix hook discovery issue by initializing HookManager when experiment is toggled on.
Move the periodic hooks configuration reload from the HooksSettings component to the main App component. This ensures that hooks are reloaded every 5 seconds whenever the feature is enabled, regardless of which settings tab is currently active.
- Add 'Create New Hook' button above 'Open Global Folder' button - Remove borders from hook items to match flat MCP styling - Implement hooksCreateNew message handler to create example.yaml - Fix YAML template indentation to use standard 2-space format - Add translation strings for new UI elements
- Add hooksEnabled check to all ToolExecutionHooks methods - Hooks do not execute when master toggle is off - Update Task.ts to inject hooksEnabled getter - Add hooksEnabled to GlobalSettings schema and ExtensionState - UI hides hook list when master toggle is disabled - Add comprehensive tests for toggle enforcement (15 tests)
Add hook ID to each activity log entry for easier identification of which hook was triggered. Styled with monospace font and link color.
Add hook-related UI strings to all 17 supported locales: - de, es, fr, ca, hi, id, it, ja, ko, nl, pl, pt-BR, ru, tr, vi, zh-CN, zh-TW Includes translations for: - hooks section (~50 keys) - experimental.HOOKS feature toggle
Replace Pickaxe with FishingHook icon from lucide-react. Upgrade lucide-react from 0.518.0 to 0.562.0 for FishingHook support.
Remove hooks from experimental flags and make it a core feature: - Remove HOOKS from ExperimentId enum and experimentsSchema - Initialize HookManager unconditionally in ClineProvider - Remove experiment checks from webviewMessageHandler - Always show Hooks tab in SettingsView - Add dynamic initialization with file watchers (no restart required) - Update translations to remove restart requirement text - Add comprehensive tests for dynamic hook initialization The master 'Enable Hooks' toggle in HooksSettings controls execution.
- Add getToolsForGroup() helper to expand group names to tool lists - Update HookMatcher to support group names like "edit", "read", "browser" - Group names are case-insensitive and expand to all tools in the group - Unknown group names log a warning but don't break the hook - Add comprehensive tests for group expansion functionality Supported groups: read, edit, browser, command, mcp, modes
src/services/hooks/HookMatcher.ts
Outdated
| } else { | ||
| // Not a group, keep as-is, but warn if it looks like it was intended as a group | ||
| console.warn(`Unknown tool group "${pattern}". Treating as literal tool name.`) | ||
| return pattern | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This console.warn is triggered for every pattern that isn't a known group name, including valid tool names like read_file, apply_diff, etc. The comment says "warn if it looks like it was intended as a group" but the code warns unconditionally. This will cause console spam when users configure hooks for specific tools.
Consider removing the warning entirely, or only warning for patterns that closely resemble group names (e.g., levenshtein distance to known groups).
| } else { | |
| // Not a group, keep as-is, but warn if it looks like it was intended as a group | |
| console.warn(`Unknown tool group "${pattern}". Treating as literal tool name.`) | |
| return pattern | |
| } | |
| } else { | |
| // Not a group - this is a normal tool name, keep as-is | |
| return pattern | |
| } |
Fix it with Roo Code or mention @roomote and request a fix.
…group matchers - Replace raw config display with interactive controls for Events, Matchers, and Timeout - Add backend support for updating hook configurations via hooksUpdateHook message - Implement atomic YAML/JSON writing with event migration logic (moving hooks between keys) - Add multi-select checkboxes for lifecycle events (PreToolUse, PostToolUse, etc.) - Add tool group matchers (read, edit, etc.) with custom pattern fallback - Add timeout preset dropdown (15s - 60m) - Add comprehensive tests for config writing and UI interaction
- Update hooksSetAllEnabled tests to match global hooksEnabled toggle behavior\n- Add IHookManager.updateHook to test mocks after interface change\n- Narrow hooksUpdateHook events to HookEventType via schema validation
…ase 2) - Refactor YAML structure to be hook-centric (array-based) instead of event-keyed - Remove version key from schema and code - Add "Copy Hook" functionality to duplicate hooks - Enhance Settings UI: - Add event tooltips with descriptions - Add editable hook ID field with validation - Add multi-line command editing - Add "Copy" button - Update config loader to support both new and legacy formats (read-only compatibility) - Update config writer to always emit new format - Add comprehensive tests for migration, copy logic, and new UI components
- Keep multiple events for same hook id when definitions match\n- Expand matcher groups when combined with | (e.g. read|edit)\n- Add regression tests for both cases
Send hook-centric enabledHooks state to webview (one entry per id) and expose aggregated events[] for UI rendering. Adds regression test for ClineProvider hooks state shaping.
Stream hook stdout/stderr into chat with terminal-style HookExecution blocks.\n\nAdds hookExecutionOutputStatus protocol and persisted hook_execution rows with truncated summaries.
Summary
This PR implements a Claude Code-compatible hooks system for Roo Code, enabling users to run custom shell commands at key lifecycle events during AI assistant interactions.
Features
Core Hooks System
Configuration
.roo/hooks.jsonComponents
HookConfigLoader: Loads and merges hooks from project/global/mode configsHookExecutor: Executes hooks as subprocesses with JSON input/outputHookMatcher: Matches events against hook matchers (tool names, patterns)HookManager: Orchestrates hook discovery and executionToolExecutionHooks: Integration with tool execution lifecycleSecurity
Documentation
See hooks-prd.md for full PRD including:
Testing
All components include comprehensive unit tests:
HookConfigLoader.spec.tsHookExecutor.spec.tsHookManager.spec.tsHookMatcher.spec.tswebviewMessageHandler.hooks.spec.tsRelated
Addresses community request for event-driven automation (Discussion #6147)
Important
Implements a Claude Code-compatible hooks system in Roo Code, enabling custom shell command execution at lifecycle events, with configuration, management, and UI integration.
PreToolUse,PostToolUse,ToolError, etc..roo/hooks.jsonand global settings.HookManager,HookExecutor,HookMatcher,ToolExecutionHooksclasses for managing and executing hooks.HookConfigLoaderfor loading and merging hook configurations.HooksSettingscomponent to manage hooks in the settings UI.HookManager,HookExecutor,HookMatcher, andHookConfigLoader.This description was created by
for 22eda99. You can customize this summary. It will automatically update as commits are pushed.