第 2 课

Issue 分诊工作流:触发器、safe outputs 与 staged 预览

按官方图库示例写一个新开 Issue 就自动运行的分诊工作流,用 add-labels 白名单和 add-comment 次数限定 AI 的写操作,故意改成 issues: write 看严格模式如何拒绝,从 lock 文件里确认代理拿到的工具,再用 staged: true 只预览不落地。

图文20 分钟

课程目录第 2 / 3 课

学习位置仅保存在当前浏览器,有效期 180 天。

01 / 图文教材

图文教材

本课对照的官方页面:AI Issue Triage、Safe Outputs、Triggers、Staged Mode、Threat Detection。命令与输出在 Linux(gh-aw v1.0.1)上实测,输出为节选。

上一课的周报按日程运行。这一课写一个由事件触发的工作流:每当有人新开或重开 Issue,AI 读一遍内容,从允许的标签里挑 1~2 个加上,再留一条说明评论。示例按官方图库里的 Issue 分诊工作流精简而来,重点是看清 gh-aw 怎么限制代理「能写什么」。

第 1 步:写触发器、权限与允许的输出

在上一课的仓库里新建 .github/workflows/issue-triage.md,先写 frontmatter:

---
on:
  issues:
    types: [opened, reopened]
  reaction: eyes
permissions:
  contents: read
  issues: read
safe-outputs:
  add-labels:
    allowed: [bug, feature, question, needs-info]
    max: 2
  add-comment:
    max: 1
timeout-minutes: 10
---
  • on.issues.types 和普通 GitHub Actions 的写法一样。reaction: eyes 是 gh-aw 的扩展:工作流一启动,就在这个 Issue 上点一个 👀,让提问的人知道已经在处理。
  • add-labels.allowed 是标签白名单,代理只能从这 4 个里选。max: 2 限制最多调用 2 次。
  • add-comment.max: 1 表示最多评论 1 条。
  • 官方文档提醒:仓库里还不存在的标签会被拒绝并报错。可以先在仓库里建好,或者在 add-labels 下加 create-if-missing: true。

建标签可以用 gh 自带的命令,bug、question 等一般已经是默认标签:

gh label create needs-info --color FBCA04
gh label create feature --color A2EEEF

第 2 步:写给代理的指令

frontmatter 下面接着写正文:

# Issue 分诊助手

分析 Issue #${{ github.event.issue.number }}。

1. 读标题和正文,判断它属于 bug、feature 还是 question。
2. 信息不足以复现时,加 needs-info 标签。
3. 用 add-labels 加 1~2 个标签,只能从允许列表里选。
4. 用 add-comment 留一条简短中文评论:说明分类理由;
   如果缺信息,列出需要补充的内容。

${{ github.event.issue.number }} 是 GitHub Actions 的上下文表达式,运行时会替换成当前 Issue 的编号。代理会通过内置的 GitHub MCP 工具自己去读这个 Issue 的标题和正文,所以不用把正文塞进提示词里。

第 3 步:编译,并故意写错一次

先正常编译:

gh aw compile issue-triage

对照结果(省略 info 提示):

✓ .github/workflows/issue-triage.md (140.5 KB)
✓ Compiled 1 workflow: 1 succeeded, 0 warnings

再试一个常见的错误想法:既然要加标签,那就把 issues: read 改成 issues: write,再编译一次:

✗ Compiled 1 workflow: 0 succeeded, 1 failed, 1 error, 0 warnings
✗ issue-triage.md (1 error(s)):
  • 1. .github/workflows/issue-triage.md:1:1: error: strict mode:
    write permission 'issues: write' is not allowed for security
    reasons. Use 'safe-outputs.create-issue',
    'safe-outputs.create-pull-request', 'safe-outputs.add-comment',
    or 'safe-outputs.update-issue' to perform write operations
    safely.
✗ compilation failed

(为了不横向溢出,长行做了折行,原文是一整行。)编译器默认启用严格模式,直接拒绝给代理写权限,并指向 safe-outputs。改回 issues: read 后重新编译即可。

第 4 步:看清代理拿到了哪些工具

lock 文件第二行的 gh-aw-manifest 注释记录了这个工作流用到的 secrets、action、容器和 MCP 工具。把 safe outputs 工具单独取出来:

grep '^# gh-aw-manifest' .github/workflows/issue-triage.lock.yml \
  | grep -o '"name":"safeoutputs","tools":\[[^]]*\]'
grep -nE '^  [a-z_]+:$' .github/workflows/issue-triage.lock.yml

对照结果:

"name":"safeoutputs","tools":["add_comment","add_labels","noop",
"report_incomplete","report_missing_data","report_missing_tool"]
76:  activation:
446:  agent:
1285:  conclusion:
1637:  detection:
1988:  pre_activation:
2027:  safe_outputs:

(第一行同样做了折行。)可以看到:

  • 代理能调用的写类工具只有 add_comment 和 add_labels,正好对应 frontmatter 里的声明。noop、report_* 是内置的「没事可做 / 报告缺失」工具。
  • 和周报相比多了一个 pre_activation 作业。Issue 事件谁都能触发,这个作业先检查触发者在仓库里的角色(默认只放行 admin、maintainer、write),不符合就不启动代理。👀 反应则由 activation 作业里的「Add eyes reaction for immediate feedback」步骤点上。
  • 代理运行完之后,detection 作业先扫描它想写出的内容,检查提示词注入、密钥泄露和恶意代码改动,通过后 safe_outputs 作业才用自己的令牌真正加标签、发评论。

第 5 步:用 staged 模式先预览、不落地

第一次在真实仓库上跑,可以先开 staged 模式:代理照常分析,但不真正加标签、发评论,只在 Actions 运行摘要里列出「本来会做什么」。在 safe-outputs: 下加一行:

safe-outputs:
  staged: true
  add-labels:
    allowed: [bug, feature, question, needs-info]
    max: 2
  add-comment:
    max: 1

重新编译并确认开关已经写进 lock 文件:

gh aw compile issue-triage
grep -n 'GH_AW_SAFE_OUTPUTS_STAGED' \
  .github/workflows/issue-triage.lock.yml

对照结果:

✓ Compiled 1 workflow: 1 succeeded, 0 warnings
1033:          GH_AW_SAFE_OUTPUTS_STAGED: true
2051:      GH_AW_SAFE_OUTPUTS_STAGED: "true"
2127:          GH_AW_SAFE_OUTPUTS_STAGED: "true"

也可以只给某一种输出单独设 staged: true,比如只预览评论、标签照常加。看过几次预览、确认结果靠谱后,删掉 staged: true 再编译,就会真正写入。官方提醒:staged 只管内置的 safe outputs,自定义脚本、外部 MCP 服务等不在它的控制范围内。

小结

  • 事件触发写在 on: 里,reaction 可以立刻给提问者反馈。
  • 代理权限只能是只读,严格模式会拒绝 issues: write 这类写法。
  • add-labels.allowed、max 等字段把代理的写操作限定在白名单和次数以内,代理之外还有威胁检测作业把关。
  • 不确定效果时先开 staged: true 预览。
  • 下一课把这两个工作流推到 GitHub,配置 AI 认证,真正跑起来,并设好成本上限。