Skip to main content

Create Your First Dynamic Content

Harness AI SRE supports two expression languages for creating dynamic content: CEL (Common Expression Language) for logic and conditions, and Mustache for simple variable substitution.

CEL versus Mustache

Choose the right expression language based on your needs:

FeatureCEL (${{expression}})Mustache ({{variable}})
PurposeLogic and computationSimple variable substitution
Use casesConditions, transformations, calculationsDisplay values, basic templating
CapabilitiesBoolean logic, regex, math, functionsVariable interpolation only
Syntax${{incident.severity == "0"}}{{incident.severity}}
Return typesAny type (string, number, boolean, array, object)String only
MixingCannot mix with Mustache in same fieldCannot mix with CEL in same field

When to Use Each

Use CEL When You Need:

  • Conditional logic: Filter or route based on conditions
  • Regex matching: Pattern matching on service names or messages
  • Calculations: Math operations, thresholds, percentages
  • Transformations: String manipulation, datetime formatting
  • Complex logic: Multi-field boolean expressions

Use Mustache When You Need:

  • Simple display: Show field values in messages
  • Basic templating: Insert variables into text
  • Field mapping: Map source fields to destination fields
  • Static substitution: Replace placeholders with values

Where to Use CEL

CEL is available in these contexts:

1. Alert Rule Conditions

Filter incoming alerts before creating incidents.

Example:

alert.severity == "critical" && alert.source.matches("prod-.*")

Go to Use CEL in Alert Rules to learn more.

2. Runbook Trigger Conditions

Control when runbooks automatically execute.

Example:

incident.severity == "0" && incident.environment == "production"

Go to Use CEL in Runbook Triggers to learn more.

3. Webhook Advanced Mapping Conditions

Filter webhook payloads before creating alerts.

Example:

webhook.priority == "P1" && webhook.region.matches("us-.*")

Go to Use CEL in Webhooks to learn more.

4. Runbook Action Fields (Inline)

Embed CEL expressions in text fields for dynamic content.

Example:

Incident ${{incident.title}} has severity ${{incident.severity == "0" ? "CRITICAL" : "Normal"}}

Go to Use CEL in Runbook Actions to learn more.


Where to Use Mustache

Mustache is available in these contexts:

1. Runbook Action Fields

Insert field values into messages, tickets, and notifications.

Example:

Incident {{incident.title}} detected in {{incident.environment}}

Go to Use Mustache in Runbook Actions to learn more.

2. Webhook Field Mapping

Map webhook payload fields to alert properties.

Example:

{{webhook.alert.name}}

Go to Use Mustache in Webhooks to learn more.


Harness-Specific Information

Feature Flag

CEL expressions require the feature flag IR_CEL_CONDITIONS. Contact your Harness account team to enable this feature.

Expression Limits

  • Max CEL expression length: 4,096 characters
  • No mixing: Cannot use both CEL and Mustache in the same field
  • No preview: Expressions cannot be tested before execution

Harness-Specific Data

Severity values are strings, not numbers:

// ✅ Correct
incident.severity == "0"

// ❌ Wrong - comparing string to number
incident.severity == 0

Timestamps are milliseconds since Unix epoch:

incident.created_at > 1704067200000

Common Patterns

Severity Checks

Single severity:

incident.severity == "0" // SEV0 (Critical)

Multiple severities:

incident.severity in ["0", "1", "2"]

String Operations

Contains check:

incident.title.contains("database")

Regex matching:

incident.service.matches("^payment-.*")

Regex extraction:

regex.extract(Webhook.parsed_body, r"\"AlarmName\"\:\"(.*)\"")

Case conversion:

incident.environment.upperAscii()

String trimming:

incident.title.trim()

Replace text:

regex.replace(incident.description, r"\n", ", ")

Null Safety and Default Values

Always check for null:

// ✅ Safe
incident.owner != null && incident.owner.contains("@example.com")

// ❌ May fail if owner is null
incident.owner.contains("@example.com")

Provide default values with orValue():

// Returns "Unknown" if field is null or empty
regex.extract(Webhook.parsed_body, r"\"AlarmName\"\:\"(.*)\"").orValue("")

// Chain multiple operations with safe defaults
incident.owner.orValue("Unassigned").trim()

Mustache Nested Fields

Access nested data:

{{webhook.metadata.environment}}
{{alert.resource.name}}

Collection Operations

CEL provides powerful collection operations for working with arrays and lists.

Get collection size:

size(incident.affected_services) > 3

Check if any item matches:

incident.tags.exists(t, t == "customer-impact")

Extract Harness service IDs from impacted services:

Activity.impacted_services.map(s, s.id)
// Returns: ["9280f15c-8c59-4c32-834b-3b36c06d269b", "a1b2c3d4-..."]

Get first service ID:

Activity.impacted_services[0].id

Filter services by name pattern:

Activity.impacted_services.filter(s, s.name.contains("api"))

Count services matching a condition:

size(Activity.impacted_services.filter(s, s.name.contains("api")))

Combine operations:

// Get IDs of all API services
Activity.impacted_services
.filter(s, s.name.contains("api"))
.map(s, s.id)
Activity Namespace

Activity.* provides access to incident and activity data in runbook action fields. Use Activity.impacted_services to get the list of Harness services affected by an incident, not just service names.


Examples

CEL: Dynamic Slack Message

${{incident.severity == "0" ? "[CRITICAL]" : "[ALERT]"}}
**Service**: ${{incident.service}}
**Environment**: ${{incident.environment}}
**Status**: ${{incident.status}}

${{incident.severity in ["0", "1"] ?
"**IMMEDIATE ACTION REQUIRED**" :
"Monitor and triage as needed"}}

View: ${{incident.url}}

Mustache: Simple Jira Ticket

**Incident**: {{incident.short_id}}
**Title**: {{incident.title}}
**Service**: {{incident.service}}
**Environment**: {{incident.environment}}
**Severity**: SEV{{incident.severity}}

Link: {{incident.url}}

Learn More

CEL Language Reference

Harness AI SRE Guides