Rule Matching
Audience: Customer — this page documents how rules are matched against events.
This page documents how the rule engine evaluates conditions against events to detect violations.
Condition Structure
Each rule has one or more conditions. ALL conditions must match for a violation to be created (AND logic).
{
"conditions": [
{ "field": "toolInput", "operator": "contains", "value": "SELECT * FROM" },
{ "field": "language", "operator": "equals", "value": "sql" }
]
}
In this example, both conditions must be true: the tool input must contain "SELECT * FROM" and the language must be "sql".
Operators
| Operator | Description | Example |
|---|---|---|
equals |
Exact string match | { field: "toolName", operator: "equals", value: "Bash" } |
notEquals |
Not equal | { field: "toolSuccess", operator: "notEquals", value: "true" } |
contains |
Substring match (case-insensitive) | { field: "toolInput", operator: "contains", value: "password" } |
notContains |
Does not contain (case-insensitive) | { field: "toolInput", operator: "notContains", value: "test" } |
startsWith |
Starts with (case-insensitive) | { field: "filePath", operator: "startsWith", value: "src/" } |
endsWith |
Ends with (case-insensitive) | { field: "filePath", operator: "endsWith", value: ".env" } |
regex |
Regular expression match (case-insensitive) | { field: "toolInput", operator: "regex", value: "api[_-]?key\\s*=\\s*['\"]" } |
greaterThan |
Numeric greater than | { field: "toolInputSize", operator: "greaterThan", value: 10000 } |
lessThan |
Numeric less than | { field: "toolOutputSize", operator: "lessThan", value: 100 } |
greaterThanOrEqual |
Numeric >= | { field: "linesAdded", operator: "greaterThanOrEqual", value: 500 } |
lessThanOrEqual |
Numeric <= | { field: "toolDuration", operator: "lessThanOrEqual", value: 50 } |
Matchable Fields
These fields can be used in condition evaluation:
| Field | Source | Description |
|---|---|---|
toolInput |
Event | Content sent to the tool (stringified) |
toolOutput |
Event | Content returned from the tool (stringified) |
toolName |
Event | Tool name (Read, Write, Edit, Bash, etc.) |
filePath |
Event | Full file path |
fileName |
Derived | File name only (last path segment) |
fileExtension |
Derived | File extension (lowercase, no dot) |
fileDirectory |
Derived | Directory path (everything before file name) |
language |
Event | Programming language |
toolSuccess |
Event | Boolean — whether tool call succeeded |
| (any field) | Event | Any field on the event object via dot notation |
Derived Fields
Some fields are computed at match time:
fileName— Extracted fromfilePath(e.g.,/src/app/page.tsx→page.tsx)fileExtension— Extracted fromfilePath(e.g.,tsx)fileDirectory— Extracted fromfilePath(e.g.,/src/app)
Regex Matching
Regex conditions use JavaScript RegExp with case-insensitive flag (i):
const regex = new RegExp(condition.value, 'i');
return regex.test(eventValue);
Dev-Safe Filtering
For toolInput and toolOutput fields with regex matching, the engine applies dev-safe filtering:
- Test the original value against the regex
- If it matches, strip dev-safe patterns and test again
- Only count as a match if it still matches after stripping
Dev-safe patterns stripped:
http://localhost:PORThttp://127.0.0.1:PORThttp://0.0.0.0:PORT- Bare
localhost,127.0.0.1,0.0.0.0references
This prevents false positives for rules about hardcoded URLs — development URLs are not violations.
Line Number Detection
When a violation is found, the engine attempts to identify the specific line number:
- Get the content from
toolInputortoolOutput - Split into lines
- Skip files with fewer than 5 lines (too short for meaningful line detection)
- Test each line against the matching condition
- Return the 1-based line number of the first match
Line number detection supports contains, equals, startsWith, endsWith, and regex operators.
Correction Detection
When a tool_call event modifies a file that has uncorrected violations:
- Query
user_rules_violationsfor uncorrected violations matching the file path - For each violation, look up the original rule's conditions
- Re-evaluate the conditions against the new event
- If the conditions no longer match, mark the violation as corrected
Event modifies /src/config.ts → Found uncorrected violation for "Hardcoded API Key" in /src/config.ts → Re-check: toolInput no longer contains "api_key = 'sk-..." → Violation marked corrected ✓
Correction detection works for both template and custom rules. The correction is recorded with:
corrected: truecorrectedAt: <timestamp>correctedByEventId: <event-id>
Evaluation Flow
For each event:
1. Is event type "tool_call"? If not, skip rule checking
2. Is template cache stale? If yes, refresh
3. Get user config (stack, disabled templates, plan)
4. Resolve matchable rules:
a. Template rules filtered by user's stack categories
b. Minus disabled templates
c. Plus always-active templates
d. Plus custom rules (Enterprise)
5. For each rule:
a. Check all conditions (AND logic)
b. If all match → create violation
c. Detect line number
6. Check for corrections on the same file
7. Mark event as ruleChecked
Example Rules
Security: Hardcoded API Key
{
"name": "Hardcoded API Key",
"category": "security",
"severity": "error",
"conditions": [
{
"field": "toolInput",
"operator": "regex",
"value": "(api[_-]?key|secret|token|password)\\s*[:=]\\s*['\"][a-zA-Z0-9_\\-]{20,}['\"]"
}
]
}
TypeScript: Any Type Usage
{
"name": "Avoid any Type",
"category": "typescript",
"severity": "warning",
"conditions": [
{
"field": "toolInput",
"operator": "regex",
"value": ":\\s*any\\b"
},
{
"field": "fileExtension",
"operator": "equals",
"value": "ts"
}
]
}
React: Missing Key Prop
{
"name": "Missing Key Prop in List",
"category": "react",
"severity": "warning",
"conditions": [
{
"field": "toolInput",
"operator": "regex",
"value": "\\.map\\([^)]*=>\\s*<(?!.*\\bkey\\b)"
}
]
}
See Also
- Rules & Templates — Template library and categories
- Rule Engine Overview — Processing pipeline
- Event Schema — Event fields available for matching