docs(hub): document durable workflow routing (#2943)
* docs(hub): document durable workflow routing * docs(hub): make workflow guide progressive
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
---
|
||||
title: Discord triggers
|
||||
description: Discord mentions as Hub triggers, snowflake filters, thread context, and the full paseo.event.discord data reference.
|
||||
description: Configure Discord mentions as Hub triggers and route them into durable workflows.
|
||||
nav: Discord
|
||||
order: 67
|
||||
category: Hub
|
||||
@@ -10,15 +10,13 @@ category: Hub
|
||||
|
||||
## Events
|
||||
|
||||
| `on` | Fires when |
|
||||
| ----------------- | ------------------------------------------------- |
|
||||
| `discord.mention` | The bot is mentioned in a guild channel or thread |
|
||||
|
||||
Mentioning a role the bot holds counts as mentioning the bot.
|
||||
| `on` | Fires when |
|
||||
| ----------------- | ------------------------------------------------------------------------------ |
|
||||
| `discord.mention` | The bot or one of its managed roles is mentioned in a guild channel or thread. |
|
||||
|
||||
## Filters
|
||||
|
||||
Discord filters take snowflake IDs. Turn on **Developer Mode** in Discord's advanced settings, then right-click a channel or user to copy its ID.
|
||||
Discord filters use quoted snowflake IDs:
|
||||
|
||||
```yaml
|
||||
filters:
|
||||
@@ -27,92 +25,28 @@ filters:
|
||||
from_users: ["345678901234567890"]
|
||||
```
|
||||
|
||||
Quote them. Unquoted snowflakes parse as numbers and lose precision.
|
||||
Turn on Developer Mode to copy IDs. `from_users` matches the author's user id, `guild` matches the connected guild, and `channels` matches the channel or thread parent. `pattern` matches the start of the text after the mention. All filters must pass.
|
||||
|
||||
- `from_users` matches the author's user id.
|
||||
- `guild` is resolved to the connection on activation.
|
||||
- `channels` matches the channel the message was posted in; in a thread, the thread's parent channel counts.
|
||||
- `pattern` matches the start of the text after the mention.
|
||||
## Invocation
|
||||
|
||||
## Replying
|
||||
Put leading inputs directly after the mention:
|
||||
|
||||
```text
|
||||
@Paseo repo=project investigate the failed sync
|
||||
```
|
||||
|
||||
Hub consumes only declared consecutive headers and passes `investigate the failed sync` as `${{ paseo.prompt }}`. See [Hub workflows](/docs/hub/workflows) for the provider-neutral input contract.
|
||||
|
||||
## Replies and repository access
|
||||
|
||||
Put the reply capability on a step:
|
||||
|
||||
```yaml
|
||||
allow_outputs:
|
||||
- type: discord.reply
|
||||
max: 5
|
||||
```
|
||||
|
||||
One plain-text reply per execution, in the triggering thread or channel.
|
||||
The reply is posted in the triggering thread or channel. A Discord trigger has no implicit GitHub credential. If a step needs another connection, configure that connection through the supported step environment for your deployment; Hub does not guess between GitHub installations.
|
||||
|
||||
## Repository access
|
||||
|
||||
A Discord trigger has no implicit GitHub credential. Name the connection you want:
|
||||
|
||||
```yaml
|
||||
env:
|
||||
GH_TOKEN: ${{ paseo.connections.acme-github.token }}
|
||||
```
|
||||
|
||||
Hub will not guess between several GitHub installations.
|
||||
|
||||
## Data reference
|
||||
|
||||
The triggering message is `paseo.event.discord.trigger_message`:
|
||||
|
||||
| Path | Value |
|
||||
| -------------------- | ----------------------------------------------------- |
|
||||
| `id` | Message snowflake |
|
||||
| `content` | Raw text, including the mention |
|
||||
| `body` | Text with the mention stripped, usually what you want |
|
||||
| `url` | Canonical message link |
|
||||
| `author` | Author identity, including the user id |
|
||||
| `channel` | Channel identity |
|
||||
| `thread` | Thread identity, or `null` outside a thread |
|
||||
| `created_at` | Message creation time |
|
||||
| `attachments` | Typed list, see below |
|
||||
| `referenced_message` | Identity of a replied-to message, or `null` |
|
||||
|
||||
Each attachment has `id`, `filename`, `url`, `content_type`, and `size`. A `referenced_message` carries `id`, `channel_id`, and `guild_id`, without the message content.
|
||||
|
||||
Also available: `paseo.event.discord.event_type` and `paseo.event.discord.guild.id`.
|
||||
|
||||
### Thread context
|
||||
|
||||
In a thread, `paseo.event.discord.trigger_thread_context.messages` holds the preceding messages, **oldest first**, never including the triggering message. Each entry exposes the same identity, content, author, channel, creation time, attachment, and reference fields as `trigger_message`.
|
||||
|
||||
This is how you give an agent the conversation rather than one line:
|
||||
|
||||
```yaml
|
||||
prompt: |
|
||||
Thread so far:
|
||||
${{ paseo.event.discord.trigger_thread_context.messages }}
|
||||
|
||||
Latest request:
|
||||
${{ paseo.event.discord.trigger_message.body }}
|
||||
```
|
||||
|
||||
Outside a thread the list is empty.
|
||||
|
||||
## Example
|
||||
|
||||
```yaml
|
||||
triggers:
|
||||
- name: discord-fix
|
||||
on: discord.mention
|
||||
environment: dev
|
||||
filters:
|
||||
guild: "123456789012345678"
|
||||
channels: ["234567890123456789"]
|
||||
from_users: ["345678901234567890"]
|
||||
agent:
|
||||
provider: codex
|
||||
mode: full-access
|
||||
env:
|
||||
GH_TOKEN: ${{ paseo.connections.acme-github.token }}
|
||||
allow_outputs:
|
||||
- type: discord.reply
|
||||
prompt: |
|
||||
${{ paseo.event.discord.trigger_message.body }}
|
||||
|
||||
Context: ${{ paseo.event.discord.trigger_message.url }}
|
||||
Reply in the thread when you're done.
|
||||
```
|
||||
See the [workflow examples](/docs/hub/configuration/examples) for complete step configurations.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
---
|
||||
title: GitHub triggers
|
||||
description: GitHub events Hub can trigger on, how filters match them, and the full paseo.event.github data reference.
|
||||
description: Configure GitHub events as Hub triggers and route them into durable workflows.
|
||||
nav: GitHub
|
||||
order: 65
|
||||
category: Hub
|
||||
@@ -10,104 +10,44 @@ category: Hub
|
||||
|
||||
## 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 |
|
||||
| `on` | Fires when |
|
||||
| ------------------------------------ | ------------------------------------------------- |
|
||||
| `github.issue_comment` | A comment on an issue or pull request is created. |
|
||||
| `github.issues` | An issue is opened or edited. |
|
||||
| `github.pull_request_review` | A review is submitted. |
|
||||
| `github.pull_request_review_comment` | A comment is added to a diff. |
|
||||
|
||||
Which repositories produce events is set on the GitHub connection's installation, not in Paseo.
|
||||
Which repositories produce events is set on the GitHub App installation. `filters.repo` narrows a trigger to one `owner/name` repository.
|
||||
|
||||
## Filters
|
||||
|
||||
```yaml
|
||||
filters:
|
||||
repo: acme/api
|
||||
repo: example/project
|
||||
contains: "@paseo"
|
||||
from_users: [alice, bob]
|
||||
from_users: [maintainer]
|
||||
```
|
||||
|
||||
- `from_users` matches the GitHub **login** of the event's sender.
|
||||
- `repo` is `owner/name`, resolved to the repository's immutable id on activation.
|
||||
- `contains` is a substring test; `pattern` must match at the start.
|
||||
`from_users` matches the sender's GitHub login. `contains` checks the event text; `pattern` checks its start. The text is the comment body for comments and reviews, and the issue title plus body for issues. All filters must pass.
|
||||
|
||||
The text those two search depends on the event:
|
||||
## Invocation
|
||||
|
||||
| Event | Text searched |
|
||||
| ------------------------------------ | -------------------- |
|
||||
| `github.issue_comment` | The comment body |
|
||||
| `github.issues` | Issue title and body |
|
||||
| `github.pull_request_review` | The review body |
|
||||
| `github.pull_request_review_comment` | The comment body |
|
||||
Put the configured marker in the message, then put leading inputs in the text parsed after that marker:
|
||||
|
||||
## Tokens
|
||||
```text
|
||||
@paseo repo=project agent=claude investigate the failed sync
|
||||
```
|
||||
|
||||
A GitHub-triggered execution automatically receives a `GH_TOKEN` scoped to the triggering repository, with `contents`, `issues`, and `pull_requests` write access. It is minted per execution and revoked when the execution ends. You do not map it in `env`.
|
||||
Hub consumes only declared consecutive headers and passes `investigate the failed sync` as `${{ paseo.prompt }}`. See [Hub workflows](/docs/hub/workflows) for input types, defaults, choices, and rejected Activity records.
|
||||
|
||||
For a token from a _different_ connection, or from a non-GitHub trigger, name it explicitly:
|
||||
## Credentials and replies
|
||||
|
||||
GitHub-triggered steps receive a scoped `GH_TOKEN` for the triggering repository. The agent can use `gh` to comment, push, and open a pull request. A step may also declare:
|
||||
|
||||
```yaml
|
||||
env:
|
||||
GH_TOKEN: ${{ paseo.connections.acme-github.token }}
|
||||
allow_outputs:
|
||||
- type: github.reply
|
||||
max: 5
|
||||
```
|
||||
|
||||
## Data reference
|
||||
|
||||
GitHub's webhook payload is available directly under `paseo.event.github`, unflattened. Anything GitHub sends, you can read:
|
||||
|
||||
```yaml
|
||||
prompt: |
|
||||
${{ paseo.event.github.issue.title }}
|
||||
by ${{ paseo.event.github.sender.login }}
|
||||
on ${{ paseo.event.github.repository.full_name }}
|
||||
```
|
||||
|
||||
Common paths by event:
|
||||
|
||||
| Event | Useful paths |
|
||||
| ------------------------------------ | ------------------------------------------------------------------------------- |
|
||||
| `github.issue_comment` | `comment.body`, `comment.html_url`, `issue.number`, `issue.title`, `issue.body` |
|
||||
| `github.issues` | `issue.number`, `issue.title`, `issue.body`, `action` |
|
||||
| `github.pull_request_review` | `review.body`, `review.state`, `pull_request.number` |
|
||||
| `github.pull_request_review_comment` | `comment.body`, `comment.path`, `comment.diff_hunk`, `pull_request.number` |
|
||||
|
||||
All events also carry `sender.login`, `repository.full_name`, and `repository.default_branch`.
|
||||
|
||||
Hub adds an envelope alongside GitHub's fields:
|
||||
|
||||
| Path | Value |
|
||||
| ---------------------- | ---------------------------------------------- |
|
||||
| `delivery_id` | GitHub's webhook delivery id |
|
||||
| `event_name` | `issue_comment`, `issues`, … |
|
||||
| `repository_full_name` | `owner/name` |
|
||||
| `installation_id` | The installation that delivered the event |
|
||||
| `received_at` | When Hub accepted it |
|
||||
| `trigger_url` | Canonical URL of the comment, issue, or review |
|
||||
|
||||
`trigger_url` is only present when the event has one. It is the field you usually want in a prompt.
|
||||
|
||||
## Example
|
||||
|
||||
```yaml
|
||||
triggers:
|
||||
- name: review-fix
|
||||
on: github.pull_request_review_comment
|
||||
environment: dev
|
||||
filters:
|
||||
repo: acme/api
|
||||
contains: "@paseo"
|
||||
from_users: [alice]
|
||||
agent:
|
||||
provider: codex
|
||||
mode: full-access
|
||||
prompt: |
|
||||
${{ paseo.event.github.sender.login }} left this on PR
|
||||
#${{ paseo.event.github.pull_request.number }},
|
||||
in ${{ paseo.event.github.comment.path }}:
|
||||
|
||||
${{ paseo.event.github.comment.body }}
|
||||
|
||||
Fix it and push. Reply on the thread with gh when you're done.
|
||||
${{ paseo.event.github.trigger_url }}
|
||||
```
|
||||
See the [workflow examples](/docs/hub/configuration/examples) for review and PR workflows.
|
||||
|
||||
@@ -2,27 +2,31 @@
|
||||
title: Hub triggers
|
||||
description: How Hub matches an inbound event to a trigger: events, filters, and the allowlist that gates every execution.
|
||||
nav: Triggers
|
||||
order: 64
|
||||
order: 65
|
||||
category: Hub
|
||||
---
|
||||
|
||||
# Triggers
|
||||
|
||||
A trigger says: when this event arrives, from this source, from these people, run this agent with this prompt.
|
||||
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.
|
||||
|
||||
```yaml
|
||||
triggers:
|
||||
- name: mention
|
||||
on: github.issue_comment
|
||||
environment: dev
|
||||
filters:
|
||||
repo: acme/api
|
||||
contains: "@paseo"
|
||||
from_users: [alice]
|
||||
agent:
|
||||
provider: codex
|
||||
mode: full-access
|
||||
prompt: ${{ paseo.event.github.comment.body }}
|
||||
max_runtime: 2h
|
||||
steps:
|
||||
- id: work
|
||||
environment: dev
|
||||
max_runtime: 90m
|
||||
idle_timeout: 10m
|
||||
agent: { provider: codex, mode: full-access }
|
||||
prompt:
|
||||
- text: ${{ paseo.prompt }}
|
||||
```
|
||||
|
||||
Field-by-field detail is in the [`hub.yml` reference](/docs/hub/configuration/hub-yml). This page covers matching.
|
||||
@@ -84,11 +88,4 @@ Both run. Triggers are not ordered and do not shadow each other, in one configur
|
||||
|
||||
## Replying
|
||||
|
||||
`allow_outputs` gives the agent a single-use `reply` tool for the conversation that triggered it:
|
||||
|
||||
```yaml
|
||||
allow_outputs:
|
||||
- type: slack.reply
|
||||
```
|
||||
|
||||
Only `slack.reply` and `discord.reply` exist. GitHub-triggered agents reply with the scoped `GH_TOKEN` they already have, so `gh issue comment` works.
|
||||
Put `allow_outputs` on the step that should reply. The available provider reply types are `slack.reply`, `discord.reply`, and `github.reply`; set `max` when a step needs more than one update. GitHub-triggered agents also receive a scoped GitHub credential for `gh`.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
---
|
||||
title: Slack triggers
|
||||
description: Slack mentions as Hub triggers, ID-based filters, replies, and the full paseo.event.slack data reference.
|
||||
description: Configure Slack mentions as Hub triggers and route them into durable workflows.
|
||||
nav: Slack
|
||||
order: 66
|
||||
category: Hub
|
||||
@@ -10,89 +10,44 @@ category: Hub
|
||||
|
||||
## Events
|
||||
|
||||
| `on` | Fires when |
|
||||
| --------------- | -------------------------------------------------------- |
|
||||
| `slack.mention` | The bot is mentioned in a channel it has been invited to |
|
||||
| `on` | Fires when |
|
||||
| --------------- | --------------------------------------------------------- |
|
||||
| `slack.mention` | The bot is mentioned in a channel it has been invited to. |
|
||||
|
||||
The bot must be in the channel. `/invite @Paseo` first, or nothing arrives.
|
||||
The mention is required. Direct messages, slash commands, and interactive components do not produce this trigger.
|
||||
|
||||
## Filters
|
||||
|
||||
Slack filters take IDs, never display names. Copy a channel ID from the channel's details; copy a user ID from a member's profile menu.
|
||||
Slack filters use IDs, not display names:
|
||||
|
||||
```yaml
|
||||
filters:
|
||||
workspace: T01234567
|
||||
channels: [C01234567]
|
||||
from_users: [U01234567]
|
||||
pattern: "repo="
|
||||
```
|
||||
|
||||
- `from_users` matches the Slack user id of the author.
|
||||
- `workspace` is the team id, resolved to the connection on activation.
|
||||
- `channels` matches the channel id the message was posted in.
|
||||
- `pattern` matches the start of the text **after** the mention, and must end on a word boundary. `contains` is treated the same as `pattern` here.
|
||||
`from_users` matches the author's Slack user id. `workspace` is the team id. `channels` matches the channel id. `pattern` (or `contains`) matches the start of the text after the mention. All filters must pass.
|
||||
|
||||
The mention itself is always required. A message that does not mention the bot never produces an event.
|
||||
## Invocation
|
||||
|
||||
## Replying
|
||||
Put leading inputs directly after the mention:
|
||||
|
||||
```text
|
||||
@Paseo repo=project agent=claude investigate the failed sync
|
||||
```
|
||||
|
||||
Hub consumes only declared consecutive headers and passes `investigate the failed sync` as `${{ paseo.prompt }}`. See [Hub workflows](/docs/hub/workflows) for input types, defaults, choices, and rejection behavior.
|
||||
|
||||
## Replies and workflow shape
|
||||
|
||||
Put the reply capability on a step:
|
||||
|
||||
```yaml
|
||||
allow_outputs:
|
||||
- type: slack.reply
|
||||
max: 5
|
||||
```
|
||||
|
||||
That gives the agent one plain-text reply, posted in the thread. A root message gets a new thread; a threaded message gets a reply in the same thread.
|
||||
|
||||
## Data reference
|
||||
|
||||
Everything lives under `paseo.event.slack`.
|
||||
|
||||
| Path | Value |
|
||||
| ------------ | --------------------------------- |
|
||||
| `event_type` | `mention` |
|
||||
| `event_id` | Slack's Events API event id |
|
||||
| `event_ts` | Event timestamp from the envelope |
|
||||
| `event_time` | Envelope delivery time |
|
||||
| `team` | Workspace identity |
|
||||
| `app` | The installed app identity |
|
||||
|
||||
The message itself is `paseo.event.slack.trigger_message`:
|
||||
|
||||
| Path | Value |
|
||||
| ------------ | ----------------------------------------------------- |
|
||||
| `ts` | Native message timestamp, Slack's message id |
|
||||
| `content` | Raw text, including the `<@BOT>` mention |
|
||||
| `body` | Text with the mention stripped, usually what you want |
|
||||
| `author` | Author identity, including the user id |
|
||||
| `channel` | Channel identity |
|
||||
| `thread` | Thread identity, or `null` for a root message |
|
||||
| `created_at` | Derived from the message `ts` |
|
||||
|
||||
Use `body`, not `content`, unless you specifically need the mention text.
|
||||
|
||||
## Example
|
||||
|
||||
```yaml
|
||||
triggers:
|
||||
- name: slack-mention
|
||||
on: slack.mention
|
||||
environment: dev
|
||||
filters:
|
||||
workspace: T01234567
|
||||
channels: [C01234567]
|
||||
from_users: [U01234567]
|
||||
agent:
|
||||
provider: codex
|
||||
mode: full-access
|
||||
idle_timeout: 10m
|
||||
allow_outputs:
|
||||
- type: slack.reply
|
||||
prompt: |
|
||||
${{ paseo.event.slack.trigger_message.body }}
|
||||
|
||||
Reply in the thread when you're done.
|
||||
```
|
||||
|
||||
## Limits
|
||||
|
||||
Direct messages, slash commands, and interactive components do not produce triggers. Enterprise Grid org-wide installs are not supported.
|
||||
The reply is posted in the triggering thread. A root message gets a new thread; a threaded message stays in that thread. Use the shared [workflow examples](/docs/hub/configuration/examples) for complete configurations.
|
||||
|
||||
Reference in New Issue
Block a user