<!--
Sitemap:
- [Installation](/installation)
- [Upgrading](/upgrading): Version-specific steps for upgrading an existing Bento install.
- [Concepts](/concepts)
- [Build your first pipeline](/tutorials/pipeline-args)
- [Target a specific issue or PR from a URL](/tutorials/url-targeting)
- [Keep state across runs](/tutorials/pipeline-state)
- [Fire a pipeline on a schedule or on demand](/tutorials/schedule-and-fire)
- [Configuration](/configuration)
- [Knowledge Base](/knowledge-base/)
- [Method & delivery](/knowledge-base/modes)
- [Config](/knowledge-base/config)
- [MCP](/knowledge-base/mcp)
- [Pipeline configuration reference](/pipelines/config)
- [Filters](/pipelines/filters)
- [Triggers](/triggers/)
- [GitHub Trigger](/triggers/github)
- [Linear Trigger](/triggers/linear)
- [Webhook](/triggers/webhook)
- [Schedule Trigger](/triggers/schedule)
- [Manual Trigger](/triggers/manual)
- [Traces](/pipelines/traces)
- [Slack](/integrations/slack)
- [Public Access](/public-access)
- [Context Engineering](/context-engineering)
- [Best Practices](/best-practices)
- [Troubleshooting](/troubleshooting)
- [Architecture](/architecture/vision)
- [Workspaces](/workspaces)
- [Authentication](/authentication)
- [Identity](/identity)
- [Security](/security)
- [References](/references)
- [Changelog](/changelog): Bento release history.
- [CLI Reference](/cli/)
- [Setup](/cli/setup)
- [Lifecycle](/cli/lifecycle)
- [Sandbox Image](/cli/image)
- [Observability](/cli/observability)
- [Diagnostics](/cli/diagnostics)
- [Triggers](/cli/triggers)
- [Workbench](/cli/workbench)
- [Auth](/cli/auth)
- [Knowledge](/cli/knowledge)
- [Bento](/index)
- [Runtime Wrapper](/architecture/runtime-wrapper)
- [Skill Evolve](/architecture/skill-evolve)
-->

# GitHub Trigger

The daemon accepts GitHub webhooks at `/webhooks/github` (alias: `/events`). Requests are verified with HMAC-SHA256 against `webhooks.secret` in `daemon.yaml`; unverified requests are rejected.

:::note
Creating a GitHub webhook requires admin on the org or repo. To run a loop on your own machine without that access, skip the webhook: use a [schedule trigger](/triggers/schedule) and poll the GitHub API with a token listed in the pipeline's [`env:`](/pipelines/config#env) manifest.
:::

## Event string format

GitHub sends an `x-github-event` header (the event type) and a JSON payload. If the payload has an `action` field, the daemon combines them with a dot:

```
x-github-event: pull_request
payload.action: opened
→ event string: "pull_request.opened"

x-github-event: deployment_status
(no action field)
→ event string: "deployment_status"
```

## Prefix matching

A trigger pattern matches if it equals the event string **or** is a prefix of it (separated by `.`).

```yaml
trigger:
  github:
    - pull_request          # matches pull_request.opened, pull_request.synchronize, pull_request.closed, ...
    - pull_request.opened   # matches only pull_request.opened
```

## Common events

| Event pattern | When |
|---|---|
| `pull_request.opened` | New PR opened |
| `pull_request.synchronize` | New commits pushed to an open PR |
| `pull_request.closed` | PR closed (merged or not merged) |
| `pull_request_review.submitted` | A reviewer submits a review |
| `pull_request_review_comment.created` | An inline review comment is posted |
| `issue_comment.created` | A comment posted on a PR or issue (top-level, not inline). |
| `deployment_status` | A GitHub deployment status event (e.g. a state change from CI or a deploy tool). |
| `push` | Commits pushed to any branch |

## Loop-breaker guards

The daemon applies two automatic guards before matching pipelines — these reject events even if the trigger pattern would otherwise match:

1. **Self-authored comments** — if `sender.login` matches the daemon's configured GitHub login, issue and PR comments are rejected. This prevents a pipeline from triggering on its own output. Reviews and pushes are exempt from this guard.
2. **Merged or closed PR** — if a PR event arrives for a PR that is already merged or closed, the event is rejected.

## Examples

```yaml
# Fire on PR open and every push to the PR branch
trigger:
  github:
    - pull_request.opened
    - pull_request.synchronize

# Fire when a deployment succeeds on a specific repo
trigger:
  github:
    - deployment_status
  filter:
    repos: [acme/backend]
    when:
      deployment_status.state: success

# Observer mode: every inline review comment, except from the bot itself
trigger:
  github:
    - pull_request_review_comment.created
  filter:
    not:
      comment.user.login: my-bot
    mentioned: false
```

## Prompt variables (`{{event.*}}`)

### Pull request events

| Variable | Value |
|---|---|
| `event.pull_request.number` | PR number |
| `event.pull_request.title` | PR title |
| `event.pull_request.body` | PR description |
| `event.pull_request.user.login` | PR author's GitHub login |
| `event.pull_request.html_url` | URL to the PR |
| `event.pull_request.head.ref` | Head branch name |
| `event.pull_request.head.sha` | Head commit SHA |
| `event.pull_request.base.ref` | Base branch name |
| `event.pull_request.draft` | `true` if draft |
| `event.repository.full_name` | `owner/repo` |
| `event.repository.default_branch` | Default branch |

### Review events

| Variable | Value |
|---|---|
| `event.review.id` | Review ID |
| `event.review.state` | `approved`, `changes_requested`, `commented` |
| `event.review.body` | Review summary body |
| `event.review.user.login` | Reviewer's login |

### Comment events

| Variable | Value |
|---|---|
| `event.comment.body` | Comment text |
| `event.comment.user.login` | Commenter's login |
| `event.comment.path` | File path (inline comments only) |
| `event.comment.line` | Line number (inline comments only) |
| `event.comment.diff_hunk` | Diff context (inline comments only) |
| `event.issue.number` | PR/issue number (top-level comments) |
| `event.issue.title` | PR/issue title |

### Deployment events

| Variable | Value |
|---|---|
| `event.deployment.ref` | Branch or tag deployed |
| `event.deployment.environment` | Target environment |
| `event.deployment_status.state` | `success`, `failure`, `pending`, etc. |

## See also

* [Filters](/pipelines/filters) — narrow which events reach this pipeline
* [Public Access](/public-access) — expose the daemon to receive webhooks
