From 97bdbebd7f4b64d2fcacd6b6980f84e5cfd9c813 Mon Sep 17 00:00:00 2001 From: Mohamed Boudra Date: Fri, 21 Aug 2026 14:59:04 +0200 Subject: [PATCH] docs(hub): document semantic GitHub triggers (#3643) --- public-docs/hub/configuration/hub-yml.md | 33 ++++ public-docs/hub/self-hosting/github-app.md | 4 + public-docs/hub/triggers/github.md | 184 +++++++++++++++++++-- public-docs/hub/triggers/index.md | 51 +++--- 4 files changed, 233 insertions(+), 39 deletions(-) diff --git a/public-docs/hub/configuration/hub-yml.md b/public-docs/hub/configuration/hub-yml.md index a478dcf1e..ffc046ef2 100644 --- a/public-docs/hub/configuration/hub-yml.md +++ b/public-docs/hub/configuration/hub-yml.md @@ -137,6 +137,39 @@ steps: | `values` | no | Named expressions. | | `steps` | yes | One or more ordered inline steps. | +### GitHub events and filters + +Use one of these semantic event names for new GitHub workflows: + +| `on` | Matches | +| ------------------------------------- | ------------------------------------------------------------------------- | +| `github.issue_created` | An `issues` delivery whose action is `opened`. | +| `github.pull_request_created` | A `pull_request` delivery whose action is `opened`. | +| `github.issue_comment_created` | An `issue_comment` delivery whose action is `created`, on an issue. | +| `github.pull_request_comment_created` | An `issue_comment` delivery whose action is `created`, on a pull request. | +| `github.issue_label_added` | An `issues` delivery whose action is `labeled`. | +| `github.pull_request_label_added` | A `pull_request` delivery whose action is `labeled`. | + +Existing configurations may continue to use `github.issues`, `github.issue_comment`, `github.pull_request_review`, `github.pull_request_review_comment`, and `github.push`. These legacy events retain their existing behavior. + +`filters` supports these GitHub fields. `from_users` must be non-empty for every externally sourced workflow. All supplied filters compose with AND. + +| Field | Type | Applies to | Meaning | +| ------------ | ----------------------------------- | ------------------------------------------------------------- | ------------------------------------------------------------------------------- | +| `from_users` | non-empty list of strings | all GitHub events | GitHub logins allowed to start the workflow. | +| `repo` | non-empty string | all GitHub events | Repository in `owner/name` form. | +| `connection` | string | all GitHub events | GitHub connection slug. | +| `contains` | string | issue, pull-request, and comment events | Substring in the issue or pull-request title plus body, or in the comment body. | +| `pattern` | string | issue, pull-request, and comment events | Start of that same text. | +| `label` | non-empty string | `github.issue_label_added`, `github.pull_request_label_added` | The label added by the delivery. | +| `labels` | non-empty list of non-empty strings | issue, pull-request, and comment events | Every listed label must be currently present on the issue or pull request. | + +`label` and `labels` match GitHub labels case-insensitively. `label` checks the one changed label; `labels` checks the full current label set and requires every entry. For example, `labels: [bug, backend]` requires both `bug` and `backend`. + +Use `label` only with a label-added event. It has no match on other events. Use `labels` to require the item state, including when a comment starts the workflow. + +See [GitHub triggers](/docs/hub/triggers/github) for complete triage, pull-request review, and ready-for-agent workflows. + ### Inputs and values Inputs have `type: string | number | boolean`, plus optional `required`, `default`, and `choices`. `required` and `default` cannot be combined. Finite `choices` are required when an input can choose authority such as an environment or named agent. diff --git a/public-docs/hub/self-hosting/github-app.md b/public-docs/hub/self-hosting/github-app.md index 7810c60c8..740ce9da5 100644 --- a/public-docs/hub/self-hosting/github-app.md +++ b/public-docs/hub/self-hosting/github-app.md @@ -29,6 +29,10 @@ GitHub uses these Hub URLs: Keep GitHub's SSL verification enabled. +## Subscribe to GitHub events + +Under **Subscribe to events**, select **Issue comment**, **Issues**, **Pull requests**, **Pull request review**, **Pull request review comment**, and **Push**. **Pull requests** is required for `github.pull_request_created` and `github.pull_request_label_added`. + ## Connect repositories After Hub verifies the App, choose **Install on GitHub**. Select the account or organization and repositories the App may access. diff --git a/public-docs/hub/triggers/github.md b/public-docs/hub/triggers/github.md index 90dc9524b..92be54bfe 100644 --- a/public-docs/hub/triggers/github.md +++ b/public-docs/hub/triggers/github.md @@ -1,6 +1,6 @@ --- title: GitHub triggers -description: Configure GitHub events with explicit step-scoped GitHub authority. +description: Start Hub workflows from specific GitHub issues, pull requests, comments, and labels. nav: GitHub order: 67 category: Hub @@ -8,25 +8,150 @@ category: Hub # GitHub triggers -| `on` | Event | -| ------------------------------------ | ------------------------------------ | -| `github.issue_comment` | Comment on an issue or pull request. | -| `github.issues` | Issue event. | -| `github.pull_request_review` | Pull request review. | -| `github.pull_request_review_comment` | Diff comment. | +Use semantic GitHub events to start a workflow from one GitHub action. Add the workflow below to a repository whose `.paseo/hub.yml` defines the `dev` environment and `codex` agent, then activate the bundle. -GitHub sends every subscribed action. Each delivery that passes the filters starts a run. +## Triage new issues -`.paseo/workflows/github-change.yml`: +`.paseo/workflows/triage-issue.yml`: ```yaml -name: github-change -on: github.issue_comment +name: triage-issue +on: github.issue_created +max_runtime: 2h +filters: + repo: example/project + from_users: [maintainer] +steps: + - id: triage + environment: dev + max_runtime: 30m + idle_timeout: 5m + agent: codex + github: + connection: example-github + repositories: [example/project] + permissions: + issues: write + prompt: + - text: | + Triage the new issue. Add the appropriate labels and leave a short comment + explaining the result with gh. Use this event context: + ${{ paseo.context }} + Call hub.finish_execution when done. +``` + +`github.issue_created` fires only when someone opens an issue. `from_users` is required and matches the GitHub login that caused the event. + +## Review new pull requests + +`.paseo/workflows/review-pull-request.yml`: + +```yaml +name: review-pull-request +on: github.pull_request_created +max_runtime: 2h +filters: + repo: example/project + from_users: [maintainer] +steps: + - id: review + environment: dev + max_runtime: 90m + idle_timeout: 10m + agent: codex + github: + connection: example-github + repositories: [example/project] + permissions: + contents: read + pull_requests: write + prompt: + - text: | + Review the new pull request and submit your findings with gh. Use this event context: + ${{ paseo.context }} + Call hub.finish_execution when done. +``` + +`github.pull_request_created` fires only when someone opens a pull request. + +## Respond to new comments + +`.paseo/workflows/respond-to-issue-comment.yml`: + +```yaml +name: respond-to-issue-comment +on: github.issue_comment_created max_runtime: 2h filters: repo: example/project contains: "@paseo" from_users: [maintainer] +steps: + - id: respond + environment: dev + max_runtime: 30m + idle_timeout: 5m + agent: codex + github: + connection: example-github + repositories: [example/project] + permissions: + issues: write + prompt: + - text: | + Respond to the new issue comment with gh. Address this request: + ${{ paseo.prompt }} + Use this event context: + ${{ paseo.context }} + Call hub.finish_execution when done. +``` + +`.paseo/workflows/respond-to-pull-request-comment.yml`: + +```yaml +name: respond-to-pull-request-comment +on: github.pull_request_comment_created +max_runtime: 2h +filters: + repo: example/project + contains: "@paseo" + from_users: [maintainer] +steps: + - id: respond + environment: dev + max_runtime: 30m + idle_timeout: 5m + agent: codex + github: + connection: example-github + repositories: [example/project] + permissions: + pull_requests: write + prompt: + - text: | + Respond to the new pull-request conversation comment with gh. Address this request: + ${{ paseo.prompt }} + Use this event context: + ${{ paseo.context }} + Call hub.finish_execution when done. +``` + +Use `github.issue_comment_created` for an issue discussion and `github.pull_request_comment_created` for a pull-request conversation. A comment on a changed line is a diff comment, covered by the legacy `github.pull_request_review_comment` event. + +For `github.issue_comment_created`, `github.pull_request_comment_created`, `github.issue_comment`, and `github.pull_request_review_comment`, Hub reacts with 👀 when it accepts the delivery, 🚀 when the agent starts, 👍 on completion, and 👎 on failure. + +## Start work when an issue becomes ready + +`.paseo/workflows/implement-ready-issue.yml`: + +```yaml +name: implement-ready-issue +on: github.issue_label_added +max_runtime: 2h +filters: + repo: example/project + label: ready-for-agent + from_users: [maintainer] steps: - id: implement environment: dev @@ -38,16 +163,43 @@ steps: repositories: [example/project] permissions: contents: write + issues: write pull_requests: write prompt: - text: | - Implement the request and open a pull request with gh. + Implement the issue that was marked ready for an agent. Create a branch, + push it, and open a pull request with gh. Use this event context: + ${{ paseo.context }} Call hub.finish_execution when done. - ${{ paseo.prompt }} ``` -`from_users` matches the GitHub login. `contains` checks event text and `pattern` checks its start. Comment events use the comment body; issue events use title plus body. +`label` matches the label that this event added. The match is case-insensitive, so `ready-for-agent` also matches `Ready-For-Agent`. + +## Choose the event + +| `on` | Fires when | +| ------------------------------------- | ---------------------------------------------------- | +| `github.issue_created` | An issue is opened. | +| `github.pull_request_created` | A pull request is opened. | +| `github.issue_comment_created` | A comment is created on an issue. | +| `github.pull_request_comment_created` | A conversation comment is created on a pull request. | +| `github.issue_label_added` | A label is added to an issue. | +| `github.pull_request_label_added` | A label is added to a pull request. | + +Choose `github.issue_comment_created` for a comment on an issue and `github.pull_request_comment_created` for a conversation comment on a pull request. GitHub delivers both as issue comments; Hub separates them for you. A comment on a changed line is a diff comment, covered by the legacy `github.pull_request_review_comment` event. + +## Filter GitHub events + +Every externally sourced workflow needs a non-empty `from_users` allowlist. GitHub filters compose with AND: the repository, connection, sender, content, changed label, and required current labels must all match. + +`contains` and `pattern` inspect the title plus body for issue and pull-request events. For comment events, they inspect the comment body. `contains` is a substring match; `pattern` matches the start. + +Use `label` with `github.issue_label_added` or `github.pull_request_label_added` when the added label itself matters. Use `labels` when the item must currently have every listed label. Both compare labels case-insensitively. For example, `labels: [bug, backend]` requires both labels; it does not mean either one. + +The [configuration reference](/docs/hub/configuration/hub-yml#github-events-and-filters) lists every GitHub event and filter. + +## Legacy event compatibility + +Existing workflows keep their behavior with `github.issues`, `github.issue_comment`, `github.pull_request_review`, `github.pull_request_review_comment`, and `github.push`. Prefer the semantic events above for new workflows. A semantic workflow and a legacy workflow can both match the same delivery, so they start separate runs. A GitHub trigger grants no token. Authority is the `github` block on the step that needs it. GitHub has no `hub.reply` capability; the agent acts through `gh` within the declared connection, repositories, and permissions. - -On comment events, Hub reacts with 👀 when accepted, 🚀 when the agent starts, 👍 on completion, and 👎 on failure. `${{ paseo.prompt }}` contains normalized request text, not event identifiers. Use `${{ paseo.context }}` in prompt text when the step explicitly needs provider context. diff --git a/public-docs/hub/triggers/index.md b/public-docs/hub/triggers/index.md index 565f29aab..0ae72c1ee 100644 --- a/public-docs/hub/triggers/index.md +++ b/public-docs/hub/triggers/index.md @@ -10,14 +10,13 @@ category: Hub A trigger says which provider event can start a workflow. The [Hub workflows](/docs/hub/workflows) page covers the steps, inputs, routing, prompts, and deadlines that run after a match. -`.paseo/workflows/github-mention.yml`: +`.paseo/workflows/github-issue.yml`: ```yaml -name: mention -on: github.issue_comment +name: triage-issue +on: github.issue_created filters: repo: acme/api - contains: "@paseo" from_users: [alice] max_runtime: 2h steps: @@ -35,15 +34,19 @@ Field-by-field detail is in the [configuration reference](/docs/hub/configuratio ## Events -| `on` | Fires when | -| ------------------------------------ | ------------------------------------- | -| `github.issue_comment` | A comment on an issue or pull request | -| `github.issues` | An issue is opened or edited | -| `github.pull_request_review` | A review is submitted | -| `github.pull_request_review_comment` | A comment on a diff | -| `slack.mention` | The bot is mentioned in a channel | -| `discord.mention` | The bot is mentioned in a guild | -| `manual.run` | A run started from the API | +| `on` | Fires when | +| ------------------------------------- | ---------------------------------------------------- | +| `github.issue_created` | An issue is opened. | +| `github.pull_request_created` | A pull request is opened. | +| `github.issue_comment_created` | A comment is created on an issue. | +| `github.pull_request_comment_created` | A conversation comment is created on a pull request. | +| `github.issue_label_added` | A label is added to an issue. | +| `github.pull_request_label_added` | A label is added to a pull request. | +| `slack.mention` | The bot is mentioned in a channel. | +| `discord.mention` | The bot is mentioned in a guild. | +| `manual.run` | A run started from the API. | + +New GitHub workflows should use a semantic event. The five legacy events remain compatible: `github.issues`, `github.issue_comment`, `github.pull_request_review`, `github.pull_request_review_comment`, and `github.push`. See [GitHub triggers](/docs/hub/triggers/github) for complete workflows and when to use each event. Each provider page documents its events and the data they expose: @@ -59,16 +62,18 @@ The allowlist is what keeps a stranger's comment on a public issue from starting An allowlist is one layer of defense. It does not make a permitted account trustworthy after compromise or make prompt injection harmless. See [Hub security](/docs/hub/security) before choosing the daemon, working directory, provider policy, and outputs for an external trigger. -| Filter | Applies to | Matches | -| ------------ | -------------- | --------------------------------------------------------------- | -| `from_users` | all | GitHub: login. Slack and Discord: **user id**, not display name | -| `repo` | GitHub | `owner/name` | -| `workspace` | Slack | Team id, `T01234567` | -| `guild` | Discord | Guild id | -| `channels` | Slack, Discord | Channel ids | -| `contains` | all | GitHub substring; Slack and Discord invocation prefix | -| `pattern` | all | Invocation prefix | -| `connection` | all | A connection slug, when the organization has several | +| Filter | Applies to | Matches | +| ------------ | ------------------------- | -------------------------------------------------------------------- | +| `from_users` | all | GitHub: login. Slack and Discord: **user id**, not display name | +| `repo` | GitHub | `owner/name` | +| `workspace` | Slack | Team id, `T01234567` | +| `guild` | Discord | Guild id | +| `channels` | Slack, Discord | Channel ids | +| `contains` | all | GitHub substring; Slack and Discord invocation prefix | +| `pattern` | all | Invocation prefix | +| `connection` | all | A connection slug, when the organization has several | +| `label` | GitHub label-added events | The label added by this delivery, case-insensitively | +| `labels` | GitHub | Every listed current issue or pull-request label, case-insensitively | All conditions must pass. There is no `any` mode.