MCPcopy
hub / github.com/anthropics/claude-code / RuleEngine

Class RuleEngine

plugins/hookify/core/rule_engine.py:27–273  ·  view source on GitHub ↗

Evaluates rules against hook input data.

Source from the content-addressed store, hash-verified

25
26
27class RuleEngine:
28 """Evaluates rules against hook input data."""
29
30 def __init__(self):
31 """Initialize rule engine."""
32 # No need for instance cache anymore - using global lru_cache
33 pass
34
35 def evaluate_rules(self, rules: List[Rule], input_data: Dict[str, Any]) -> Dict[str, Any]:
36 """Evaluate all rules and return combined results.
37
38 Checks all rules and accumulates matches. Blocking rules take priority
39 over warning rules. All matching rule messages are combined.
40
41 Args:
42 rules: List of Rule objects to evaluate
43 input_data: Hook input JSON (tool_name, tool_input, etc.)
44
45 Returns:
46 Response dict with systemMessage, hookSpecificOutput, etc.
47 Empty dict {} if no rules match.
48 """
49 hook_event = input_data.get('hook_event_name', '')
50 blocking_rules = []
51 warning_rules = []
52
53 for rule in rules:
54 if self._rule_matches(rule, input_data):
55 if rule.action == 'block':
56 blocking_rules.append(rule)
57 else:
58 warning_rules.append(rule)
59
60 # If any blocking rules matched, block the operation
61 if blocking_rules:
62 messages = [f"**[{r.name}]**\n{r.message}" for r in blocking_rules]
63 combined_message = "\n\n".join(messages)
64
65 # Use appropriate blocking format based on event type
66 if hook_event == 'Stop':
67 return {
68 "decision": "block",
69 "reason": combined_message,
70 "systemMessage": combined_message
71 }
72 elif hook_event in ['PreToolUse', 'PostToolUse']:
73 return {
74 "hookSpecificOutput": {
75 "hookEventName": hook_event,
76 "permissionDecision": "deny"
77 },
78 "systemMessage": combined_message
79 }
80 else:
81 # For other events, just show message
82 return {
83 "systemMessage": combined_message
84 }

Callers 5

mainFunction · 0.90
mainFunction · 0.90
mainFunction · 0.90
mainFunction · 0.90
rule_engine.pyFile · 0.85

Calls

no outgoing calls

Tested by

no test coverage detected