# Trigger Conditions > Filter GitHub events with dot-notation field matching, operators, and contributor whitelisting. Trigger conditions let you control exactly which GitHub events fire a workflow. Every condition is evaluated against the raw webhook payload using dot-notation field paths and comparison operators. When a trigger has multiple conditions, all must match (AND logic) for the trigger to fire. ## Anatomy of a Condition A condition has three parts: | Part | Description | Example | |------|-------------|---------| | **field** | Dot-notation path into the webhook payload | `sender.login` | | **operator** | Comparison to perform | `eq`, `in`, `not_empty` | | **value** | Expected value (omitted for unary operators) | `alice` | ## Operators | Operator | Description | Value | Example | |----------|-------------|-------|---------| | `eq` | Equals (exact match) | Required | `sender.type eq User` | | `neq` | Not equals | Required | `action neq closed` | | `in` | Value is in a comma-separated list | Required | `sender.login in alice,bob` | | `not_in` | Value is not in a list | Required | `sender.login not_in dependabot[bot]` | | `contains` | Field value contains substring | Required | `comment.body contains /syn` | | `not_empty` | Field exists and is truthy | None | `check_run.pull_requests not_empty` | | `is_empty` | Field is missing or resolves to a falsy value | None | `pull_request.body is_empty` | `is_empty` uses Python truthiness: `None`, `""`, `0`, `false`, and `[]` all match. If you need to check specifically for `null` or missing fields, use `is_empty` and be aware that other falsy values will also pass. Boolean coercion is automatic -- when a condition value is supplied as a string (e.g. `"false"` from a CLI flag or API request), it is converted to a native boolean before comparison. This means `pull_request.draft eq false` works whether the condition value was provided as a boolean or a string. Payload values are compared as-is and are not coerced. ## Dot-Notation Field Paths Fields use dot notation to traverse nested objects in the GitHub webhook payload. Array indexing is also supported: ``` sender.login → payload["sender"]["login"] review.user.login → payload["review"]["user"]["login"] pull_request.head.ref → payload["pull_request"]["head"]["ref"] check_run.pull_requests[0].number → first PR's number ``` If any segment in the path is missing, the resolved value is `None` (no exception is raised) and operators then evaluate that `None` value according to their normal semantics. For example, `is_empty` passes for `None` while `eq` does not. ## Common Webhook Payload Fields GitHub webhook payloads vary by event type. Here are the most commonly used fields for conditions: ### Sender (available on all events) | Field | Description | Example values | |-------|-------------|----------------| | `sender.login` | GitHub username of the actor | `alice`, `dependabot[bot]` | | `sender.type` | Account type | `User`, `Bot`, `Organization` | ### Pull Request events | Field | Description | |-------|-------------| | `action` | `opened`, `synchronize`, `closed`, `reopened` | | `pull_request.draft` | `true` / `false` | | `pull_request.head.ref` | Source branch name | | `pull_request.base.ref` | Target branch name | | `pull_request.number` | PR number | | `pull_request.user.login` | PR author | ### Pull Request Review events | Field | Description | |-------|-------------| | `action` | `submitted`, `edited`, `dismissed` | | `review.state` | `approved`, `changes_requested`, `commented` | | `review.user.login` | Reviewer username | | `review.body` | Review comment text | ### Check Run events | Field | Description | |-------|-------------| | `action` | `created`, `completed`, `rerequested` | | `check_run.conclusion` | `success`, `failure`, `cancelled`, `timed_out` | | `check_run.name` | Check name (e.g. `CI / test`) | | `check_run.pull_requests` | Array of associated PRs | ### Issue Comment events | Field | Description | |-------|-------------| | `action` | `created`, `edited`, `deleted` | | `comment.body` | Comment text | | `comment.user.login` | Comment author | | `issue.pull_request` | Present (truthy) if the comment is on a PR | ## CLI Usage Conditions are passed with the `--condition` / `-c` flag when registering a trigger. The basic syntax is `field=value` which uses the `eq` operator. The `-c` flag only supports `field=value` syntax (always the `eq` operator). For advanced operators like `in`, `contains`, `not_empty`, etc., use the API directly or built-in presets. ```bash syn triggers register \ --repo owner/my-repo \ --event check_run.completed \ --workflow self-heal-pr \ -c "check_run.conclusion=failure" ``` Multiple `-c` flags combine with AND logic -- all must match: ```bash syn triggers register \ --repo owner/my-repo \ --event pull_request_review.submitted \ --workflow self-heal-pr \ -c "review.state=changes_requested" \ -c "pull_request.draft=false" ``` ## Security: Contributor Whitelisting Conditions are the primary mechanism for restricting which users can trigger workflows. This is important because trigger rules fire automatically from external events -- without filtering, any GitHub user who opens a PR or leaves a comment could trigger an expensive agent execution. ### Whitelist Specific Contributors Only fire for known, trusted contributors: ```bash syn triggers register \ --repo owner/my-repo \ --event pull_request.opened \ --workflow pr-review-v1 \ -c "sender.login=alice" ``` To allow multiple users, use the API directly with the `in` operator: ```json { "conditions": [ { "field": "sender.login", "operator": "in", "value": ["alice", "bob", "charlie"] } ] } ``` ### Exclude Bots Prevent bot accounts from triggering workflows: ```bash syn triggers register \ --repo owner/my-repo \ --event pull_request.opened \ --workflow pr-review-v1 \ -c "sender.type=User" ``` This filters out `dependabot[bot]`, `renovate[bot]`, GitHub Actions, and any other non-human sender. ### Filter by Branch Only trigger on PRs targeting a specific branch: ```bash syn triggers register \ --repo owner/my-repo \ --event pull_request.opened \ --workflow pr-review-v1 \ -c "pull_request.base.ref=main" ``` ### Skip Draft PRs Avoid wasting agent time on work-in-progress: ```bash syn triggers register \ --repo owner/my-repo \ --event pull_request.opened \ --workflow pr-review-v1 \ -c "pull_request.draft=false" ``` ## Built-in Presets Syntropic137 ships with preset trigger configurations for common patterns. These include conditions by default: ### Self-Healing Automatically fixes CI failures on pull requests. - **Event:** `check_run.completed` - **Conditions:** `check_run.conclusion eq failure` AND `check_run.pull_requests not_empty` ```bash syn triggers enable self-healing --repo owner/my-repo ``` ### Review Fix Responds to review comments requesting changes on PRs. - **Event:** `pull_request_review.submitted` - **Conditions:** `review.state in changes_requested,commented` AND `pull_request.draft eq false` ```bash syn triggers enable review-fix --repo owner/my-repo ``` ### Comment Command Dispatches a workflow when `/syn` appears in a PR comment. - **Event:** `issue_comment.created` - **Conditions:** `issue.pull_request not_empty` (only PR comments) AND `comment.body contains /syn` ```bash syn triggers enable comment-command --repo owner/my-repo ``` ## How Conditions Combine All conditions on a trigger are evaluated with **AND** logic. Every condition must pass for the trigger to fire. There is no OR support within a single trigger -- if you need OR behavior, create separate triggers for each case. ``` Condition 1: sender.type eq User ← must match Condition 2: pull_request.draft eq false ← must match Condition 3: pull_request.base.ref eq main ← must match ───────────── All three must pass ``` ## Combining with Safety Limits Conditions work alongside the trigger safety limits (daily limit, cooldown, budget). The evaluation order is: 1. **Event type match** -- does the webhook event match the trigger's event? 2. **Condition evaluation** -- do all conditions pass against the payload? 3. **Safety limits** -- has the trigger exceeded its daily limit, cooldown, or budget? Only if all three gates pass does the trigger fire a workflow execution.