Skip to main content

Writing rules

The current rules UI edits rule expressions as raw JSON. This is an important constraint: operators must provide the backend AST shape directly.

What a rule does

A rule is a conditional statement:

If this condition is true, return this outcome.

In practice, rules help you express policies such as:

  • observe suspicious activity without blocking it yet
  • challenge medium-risk traffic
  • block high-confidence bad behavior

Rule definition fields

Every rule definition in the current model includes:

  • rule_id
  • tenant_id
  • name
  • description
  • enabled
  • priority
  • expression
  • outcome

Supported outcomes:

  • Allow
  • Observe
  • Challenge
  • Block

What each rule field means

FieldPlain-English meaningWhy you care
rule_idThe system-generated identifier for the ruleUseful when editing, auditing, or debugging a specific rule
tenant_idThe workspace this rule belongs toKeeps rules scoped to one tenant
nameShort human-friendly rule titleShould make sense in a list view
descriptionWhat the rule is trying to catchHelps others understand intent without reading JSON
enabledWhether the backend should evaluate the ruleThe current UI always submits true
priorityRelative ordering weightHelps decide which rules should run first or get attention first
expressionThe actual condition written as JSONThis is the core logic
outcomeWhat Esper returns when the condition matchesDetermines the practical effect of the rule

Choosing an outcome

OutcomeBest useRisk level
ObserveEarly rollout, learning mode, analyticsLowest
AllowExplicitly permit a known-safe patternLow
ChallengeAsk for stronger verification on suspicious trafficMedium
BlockStop a pattern you trust is harmfulHighest

Supported expression nodes

The current RuleExpression union supports these node types:

  • And
  • Or
  • Not
  • FieldCmp
  • StateCmp
  • WindowCmp
  • FieldExists

Comparison operators:

  • Eq
  • Ne
  • Lt
  • Le
  • Gt
  • Ge

State scopes:

  • Entity
  • Session

Current window counter support:

  • EventCount

How to read the expression types

Expression typePlain-English meaning
FieldCmpCompare a value in the current event
StateCmpCompare a saved state value from the entity or session
WindowCmpCompare a count inside a recent time window
FieldExistsCheck whether a field is present
AndAll child conditions must be true
OrAt least one child condition must be true
NotReverse the meaning of a child condition

Example: exact JSON shape

This is the same shape used as the default example in the frontend:

{
"FieldCmp": {
"field_name": "email",
"operator": "Eq",
"value": "flag@example.com"
}
}

More examples

Block when an entity-scoped event count exceeds a threshold:

{
"WindowCmp": {
"scope": "Entity",
"counter": "EventCount",
"window_seconds": 300,
"operator": "Gt",
"value": "5"
}
}

Challenge when a required field exists and a state value mismatches:

{
"And": {
"expressions": [
{
"FieldExists": {
"field_name": "email"
}
},
{
"StateCmp": {
"scope": "Session",
"field_name": "risk_bucket",
"operator": "Ne",
"value": "low"
}
}
]
}
}

Frontend API contract

GET /tenants/{tenant_id}/rules
POST /tenants/{tenant_id}/rules
PATCH /tenants/{tenant_id}/rules/{rule_id}
DELETE /tenants/{tenant_id}/rules/{rule_id}

Current operational note

The current UI always submits enabled: true when creating or updating a rule. There is no exposed enabled/disabled toggle in the form yet.

Writing rules well

  • Start with Observe, not Block.
  • Give each rule a description that explains business intent, not just the data shape.
  • Keep field names stable between encoding and rules.
  • Prefer one clear rule over one oversized rule with many unrelated conditions.