notifbuddy

Templates

Expression syntax for channel names and creation conditions.

Channel names, channel topics, and creation conditions use GitHub Actions expression syntax, run against the incoming event.

${{ linear.issue.identifier }}          # channel name or topic
linear.issue.state.name == 'Done'       # condition

Event data

Reference fields off the event envelope:

  • event_typelinear
  • linear.* — the NotifBuddy-normalized Linear event (not Linear’s raw webhook)

How we transform Linear webhooks

Linear delivers PascalCase types and a generic data bag (type: "Comment", data: {…}). Before templates or sync see an event, NotifBuddy rewrites it:

  1. Lowercase typeIssueissue, Commentcomment, WorkflowStateworkflow_state
  2. Typed entity keys — former data moves to linear.issue, linear.comment, or linear.workflow_state (no linear.data)
  3. Comment → issue injection — on comment events we GraphQL-fetch the parent issue and set linear.issue, so naming/conditions can always use issue fields

Example comment envelope:

{
  "event_type": "linear",
  "linear": {
    "type": "comment",
    "action": "create",
    "actor": {},
    "comment": { "id": "…", "body": "@notifbuddy create a channel", "issueId": "…" },
    "issue": { "id": "…", "identifier": "NOT-54", "state": { "name": "Todo" } }
  }
}

Useful paths: linear.issue.identifier, linear.issue.state.name, linear.comment.body, linear.action.

The settings Test against an event panel uses the same transformed samples (including comment events with an injected issue).

Operators

== != < <= > >= · && || ! · ( ) · . [ ] · .* (object filter)

Literals: strings ('...'), numbers, true, false, null.

== compares strings case-insensitively: 'done' == 'Done' is true.

Functions

FunctionDoes
contains(a, b)Substring, or array membership
startsWith(str, prefix)Prefix check
endsWith(str, suffix)Suffix check
format(fmt, ...){0}, {1} placeholders
join(array, sep?)Join array (default ,)
toJSON(value)Serialize to JSON
fromJSON(str)Parse JSON

String functions are case-insensitive. Names are case-insensitive.

Extension functions (Handlebars-style)

Beyond the GitHub Actions dialect, we add Handlebars-style string helpers. More will be added over time.

FunctionDoes
lowercase(str)Lowercase a string

Not supported

CI-only functions error if used: hashFiles, success, always, cancelled, failure.

Examples

# only when moved to Done
linear.issue.state.name == 'Done'

# bugs only
contains(join(linear.issue.labels.*.name), 'bug')

# name by identifier (the default channel-name template)
tkt-${{ lowercase(linear.issue.identifier) }}

# backlink topic (the default channel-topic template)
${{ linear.issue.identifier }}: ${{ linear.issue.title }} • ${{ linear.issue.state.name }} • ${{ linear.issue.url }}