---
title: Hub workflow
description: 用提示词、路由、输出和 Provider 权限构建有序的 Hub workflow。
nav: Workflow
---
# Hub workflow {#hub-workflows}
一个 workflow 文件包含一个触发器,以及它启动的有序 step。文件从 `.paseo/workflows/*.yml` 中发现。
## 你的第一个 workflow {#your-first-workflow}
假设 `.paseo/hub.yml` 定义了一个名为 `dev` 的环境和一个名为 `codex` 的 Agent。添加 `.paseo/workflows/slack-help.yml`:
```yaml
name: slack-help
on: slack.mention
max_runtime: 1h
filters:
workspace: T01234567
channels: [C01234567]
from_users: [U01234567]
steps:
- id: answer
environment: dev
max_runtime: 30m
idle_timeout: 5m
agent: codex
prompt:
- text: |
Answer the request. Call hub.reply once, then call hub.finish_execution.
${{ paseo.prompt }}
allow_outputs:
- { type: slack.reply, max: 1, required: true }
```
Hub 会先去掉提及和已声明的输入头部,再把剩余文本作为 `${{ paseo.prompt }}` 提供。回复能力在 Slack 触发器旁边显式声明。Discord 使用 `discord.reply`;GitHub 使用 step 级的 [`github` 块](/docs/hub/github),而不是 `hub.reply`。
## 选择 step 在哪里运行 {#choose-where-a-step-runs}
字面值选择一个命名环境:
```yaml
environment: dev
```
有限取值的输入可以在多个完整的命名环境中选择:
```yaml
name: route-repository
on: manual.run
max_runtime: 1h
filters:
from_users: [automation]
inputs:
repo:
type: string
required: true
choices: [paseo, hub]
steps:
- id: work
environment: ${{ paseo.inputs.repo }}
max_runtime: 30m
idle_timeout: 5m
agent: codex
prompt:
- text: ${{ paseo.prompt }}
```
激活时会检查每一个 `choices` 结果。环境对象永远不会被 workflow 合并或覆盖。
## 选择 Agent {#choose-an-agent}
step 可以选择一个命名 Agent:
```yaml
agent: codex-safe
```
也可以提供一份完整的静态内联配置:
```yaml
agent:
provider: claude
mode: full-access
```
对于动态路由,用一个有限取值的表达式在多个完整的命名 Agent 中选择:
```yaml
name: route-agent
on: manual.run
max_runtime: 1h
filters:
from_users: [automation]
inputs:
agent:
type: string
required: true
choices: [codex-safe, claude]
steps:
- id: work
environment: paseo
max_runtime: 30m
idle_timeout: 5m
agent: ${{ paseo.inputs.agent }}
prompt:
- text: ${{ paseo.prompt }}
```
如果 `codex-safe` 在 `hub.yml` 中包含结构化的沙箱选项,选择它时会原样带上这些选项。像 `provider: ${{ paseo.inputs.agent }}` 这样的动态内联对象会被拒绝。
## 由分类器路由 {#route-from-a-classifier}
前面的 step 可以返回有限取值的结构化输出。之后的权限必须由该输出 schema 中的 `enum` 或 `const` 加以限定。
```yaml
name: classify-request
on: discord.mention
max_runtime: 2h
filters:
guild: "123456789012345678"
from_users: ["345678901234567890"]
values:
selected_environment: ${{ steps.classify.outputs.environment }}
selected_agent: ${{ steps.classify.outputs.agent }}
steps:
- id: classify
environment: hub
max_runtime: 5m
idle_timeout: 1m
agent: claude
prompt:
- include: partials/classify.md
- text: ${{ paseo.prompt }}
output:
schema:
type: object
required: [environment, agent]
properties:
environment: { enum: [paseo, hub] }
agent: { enum: [codex-safe, claude] }
additionalProperties: false
- id: work
environment: ${{ values.selected_environment }}
max_runtime: 1h
idle_timeout: 10m
agent: ${{ values.selected_agent }}
prompt:
- text: |
Complete the request. Call hub.reply once, then call hub.finish_execution.
- text: ${{ paseo.prompt }}
allow_outputs:
- { type: discord.reply, max: 1, required: true }
```
`.paseo/workflows/partials/classify.md`:
```text
Choose one configured repository environment and one complete named agent configuration.
```
这个 workflow 保留了一个分类器分支和一个执行者分支,不需要为每个环境/Provider 组合重复编写执行者 step。
## 提示词与上下文 {#prompt-and-context}
提示词块保持有序。include 的内容是文件的字面内容;Hub 不会递归扫描片段文本。
```yaml
prompt:
- include: partials/instructions.md
- text: |
Provider evidence:
${{ paseo.context }}
${{ paseo.prompt }}
```
- `${{ paseo.prompt }}` 是规范化后的请求文本。它始终在编写的提示词中显式出现。
- `${{ paseo.context }}` 让该 step 选择加入 Provider 上下文的物化,并插入 JSON。没有这个表达式时,Hub 不会获取或注入环境上下文。
把不受信任的请求文本放在界限清晰的块中。片段是指令文本,而不是隐藏的权限。
## 条件与有序输出 {#conditions-and-ordered-output}
step 按文件顺序运行。`if` 可以读取输入、值和之前 step 的输出:
```yaml
name: conditional-review
on: manual.run
max_runtime: 1h
filters:
from_users: [automation]
steps:
- id: inspect
environment: paseo
max_runtime: 10m
idle_timeout: 2m
agent: codex-safe
prompt:
- text: ${{ paseo.prompt }}
output:
schema:
type: object
required: [needs_review]
properties:
needs_review: { type: boolean }
additionalProperties: false
- id: review
if: ${{ steps.inspect.outputs.needs_review == true }}
environment: paseo
max_runtime: 30m
idle_timeout: 5m
agent: claude
prompt:
- text: Review the prior result and call hub.finish_execution.
```
step 不能读取之后的 step。step ID 在 workflow 内唯一。
## 告诉 Agent 调用哪个工具 {#tell-the-agent-which-tool-to-call}
`allow_outputs` 授予一项能力;它不会改写提示词。请写明需要执行的操作:
```yaml
prompt:
- text: |
Send the final answer with hub.reply.
Then call hub.finish_execution.
allow_outputs:
- type: slack.reply
max: 1
required: true
```
`max` 默认为 `1`。`required: true` 会阻止成功完成,直到该能力被使用过。请把 Slack 和 Discord 的回复类型分别放在各自 Provider 的 workflow 文件中。
## 时限 {#deadlines}
workflow 的 `max_runtime` 限制整次运行。每个 step 都有自己的 `max_runtime` 和 `idle_timeout`;workflow 的剩余时间同时为两者封顶。超时会让运行失败,并停止之后的 step。
[配置参考](/docs/hub/configuration/hub-yml)列出了所有字段。Provider 过滤器和调用文本见[触发器](/docs/hub/triggers)。