关于 mo-qa
mo-qa 是通过 Mo 托管沙盒运行浏览器 QA 的技能,面向执行软件测试的 Agent。它涵盖测试说明准备、会话启动与监控,以及在保持目标稳定的前提下报告发现。
主要功能
- 01准备范围明确的 QA 说明
- 02启动 Mo QA 会话
- 03监控会话状态与发现
- 04处理阻塞情况和用户输入
- 05附证据报告复现问题
适用场景
- 01在托管浏览器沙盒中测试 Web 应用
- 02验证 GitHub PR 中的行为变更
- 03针对本地或私有目标运行 QA
- 04跟踪发现并报告测试状态
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ momentic-ai/ skills --skill mo-qa安装后在 Claude Code 中输入/mo-qa确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
agents/openai.yamlreferences/authentication.mdbrowser-settings.mdinstallation.mdremediation-loop.mdreports.mdtunneling.md详细介绍
使用 Mo 运行 QA
Mo 在托管沙盒中运行浏览器 QA。它的文件和进程都位于远程。
Mo 运行期间的工作
在初始 QA 检查及其复现期间,保持受测版本稳定。Mo 使用目标时,不要更改目标提供或热重载的任何内容、重启应用、将应用部署到其 URL,或修改共享测试数据。代码审查等其他工作不受影响。对于较长运行期间的隔离 Bug 修复,请遵循修复循环。
通过 qa status "$session_id" --full 获取发现结果。kind: "bug" 条目表示问题已独立复现。kind: "flag" 条目表示静态的单帧错误(如拼写错误),记录时未进行复现。Agent 的判定结果包括 verified、issues_found 或 blocked。向用户报告发现结果时,请包含其名称、证据、状态和 web_url。
如果 Mo 遇到阻碍,且你能从需求说明、代码仓库或获准访问的环境数据中找到答案,就据此回答。否则,请用户提供缺失的访问权限、许可或决策,然后将答案发送给根 Mo。根 Mo 会将上下文转达给内部子 Agent。绝不要编造或泄露秘密。
准备需求说明
运行 qa version。如果缺少 Mo 或版本过旧,请阅读安装。遇到身份验证错误后,请阅读身份验证。
使用请求中指定的目标。对于本地或私有目标,请阅读隧道。
向 Mo 说明测试目标和操作边界。按需提供以下信息:
- 已知的目标 URL,包括相关路径和查询参数。
- 用户的目标、相关产品意图和已知要求。
- 登录方式、测试账户标签以及允许使用的测试数据。
- Mo 禁止执行的操作,以及不得更改的数据。
- 用户希望测试的内容和要求排除的内容。
- 任何非默认浏览器设置。必要时请阅读浏览器设置。
提供来自请求和代码仓库的事实背景,不要将其变成规定好的测试计划。只有当缺少范围、访问权限或许可会影响运行时才询问。
设置高层参数,默认让 Mo 规划
在符合用户请求的范围和预算内,让 Mo 自行选择流程和子 Agent 编排。说明用户希望测试的内容。保留用户指定的覆盖范围;否则不要规定检查清单、交互步骤或固定检查次数。提供实现细节作为背景信息。
目标设置、身份验证以及 Mo 无法远程执行的操作由你负责。开始前,移除未经请求的测试限制。保持正常并发;只有在用户明确要求或已证实目标存在限制时,才降低 --max-concurrency,并记录原因。
向 Mo 提供商定的时长或花费预算,并让它自行安排覆盖优先级。“轻量”不代表固定检查次数或串行执行。Mo 没有适用于整个会话的时间或测试数量选项。对于用户指定的硬性上限,请监控实际耗时或运行 qa cost <session-id>,达到上限时运行 qa stop <session-id> --subagents 停止,并报告未完成的覆盖范围。
启动会话
将需求说明作为一个参数传给 qa start。
对于要求进行快捷结账冒烟测试并检查标准结账回归的用户:
brief=$(cat <<'EOF'
Target: https://preview.example.com/checkout?variant=express
Goal: Keep the selected shipping method after returning from payment.
Sign in: Use the staging QA buyer account.
Test data: Create test carts and orders only.
Do not: Submit payment, send email, delete data, or change the shared catalog.
Coverage: Smoke the express-checkout happy path and standard checkout. Skip other flows and failure states.
Pass criteria:
- The shipping method stays selected.
- The total does not change.
- Standard checkout still works.
EOF
)
session_json=$(qa start "$brief")
session_id=$(jq -r .sessionId <<<"$session_json")
web_url=$(jq -r .webUrl <<<"$session_json")
created_at=$(jq -r '.createdAt // empty' <<<"$session_json")
启动命令会在 Mo 完成之前返回。保留以下值:后续每条命令都需要 session_id;用户可以通过 web_url 查看或加入会话;created_at 记录会话开始时间。若服务器运行的是较早版本的 API,createdAt 可能不存在。
例如,测试 Mo 无法构建或运行的未发布 CLI 时:
请让我使用此分支的未发布 QA CLI 启动会话。发送所需参数并等待会话 URL,然后在 Web 界面中验证该 URL。
对于 GitHub PR,请使用 PR 模式,而不是只在需求说明中填写 PR 引用。使用 --url 传入你创建或验证过的部署 URL;任何 HTTP 或 HTTPS 预览主机均可:
session_json=$(qa start "$brief" --pr https://github.com/acme/shop/pull/412 --url https://preview.example.com)
--pr 接受完整的 GitHub PR URL,包括评论固定链接和带查询参数的链接。Mo 会保留仓库和 PR 编号,并丢弃查询参数和片段。owner/repo#number 也适用。请明确指定 PR;不要根据当前分支或远程仓库推断。Mo 会获取远程 PR 修订版,并测试其中变更的应用行为和回归问题。若要使用此默认范围,请省略测试说明。没有可测试应用行为的变更会直接结束,不会启动测试 Agent。
对于 PR 会话,让 Mo 根据 PR 上下文识别变更行为和受影响的流程。计划约 10 分钟的累计交互时间,以及包括规划和复现过程在内约 20 分钟的总耗时。Mo 的 PR 指令会引导它进行有针对性的验证,并减少探索者数量。若用户明确指定了范围、时长和并发要求,请遵从这些要求,而非采用默认值。这些只是规划目标,并非强制限制;如果用户设定了硬性上限,请监控会话并及时停止。
环境会提供目标,无需预览 URL。否则,Mo 会在 Vercel、Cloudflare Pages 或 Netlify 的机器人帖子中查找与 PR 提交关联的预览。发现失败或结果不明确不会阻止启动:Mo 可以检查 PR,也可以询问目标。不要根据分支名称编造 URL。若所选部署是本地或私有的,也请使用 --tunnel。
不带 --pr 时,--url 和 --patch 会被忽略;请在常规会话的说明中填写目标 URL。
每个 PR 会话都会发布一条包含会话链接的 GitHub 评论,并在结果生成后更新该评论。新会话会将较早的 Mo 评论折叠为已过时;其中的会话链接和报告链接仍可访问。同一提交上的 Mo 检查会跟随最新请求。请以会话报告查看发现,不要将已被取代的评论视为当前结果。
对于本地变更,只要获得授权,启动前请先提交并推送到该 PR。如果不允许推送,请从 PR 检出目录使用 --patch FILE 传入经过筛选的 Git 补丁。CLI 使用本地 HEAD 作为基准;它必须与已发布的 PR head 一致,否则启动会被拒绝。请使用包含这些本地变更的目标;已知目标时使用 --url,必要时使用 --tunnel。
补丁会为 Mo 提供源代码上下文,但不会部署这些变更。
只选择测试变更所需的文件和代码块,包括相关的未跟踪文件。发送前请检查补丁。排除机密信息、凭据、日志、临时文件、大型二进制文件、不相关的变更或客户数据。不要收集整个工作树,也不要强制添加被忽略的文件。补丁必须是纯文本 Git 差异,且大小不超过 256 KiB。
若要在不更改实际 Git 索引的情况下包含已跟踪和未跟踪的文件,请使用临时索引和明确的文件列表。运行此示例前,请确认本地 HEAD 与指定的 PR head 一致,然后将示例中的路径替换为你已检查的文件:
patch_base=$(git rev-parse --verify HEAD)
patch_file=$(mktemp)
(
set -eu
patch_index=$(mktemp)
rm "$patch_index"
trap 'rm -f "$patch_index"' EXIT
export GIT_INDEX_FILE="$patch_index"
git read-tree "$patch_base"
git add -- src/checkout.ts src/discount.ts
git diff --cached --no-renames --no-ext-diff --no-textconv "$patch_base" -- src/checkout.ts src/discount.ts > "$patch_file"
)
git apply --stat "$patch_file"
启动 Mo 前,请使用文件读取工具读取 patch_file 中的每个代码块。移除所有应排除的内容,然后启动会话:
qa start "$brief" --pr https://github.com/acme/shop/pull/412 --url https://preview.example.com --patch "$patch_file"
rm -f "$patch_file"
请在初始启动请求中发送补丁。不要先启动会话再上传补丁:上传完成前,Mo 可能已经开始读取代码。Mo 会结合 PR 修订版和提供的补丁进行源代码调查。在测试和复现期间,请保持目标和补丁不变。使用干净补丁运行时,GitHub 检查会显示为中性状态,因为其源代码包含尚未发布的变更。
Momentic 环境会将一个 BASE_URL 与可复用的非机密变量组合在一起,并使用 staging 这样的名称。--environment NAME 会选择在 Momentic 控制面板的 Environments 下创建的环境,而不是 shell 或 momentic.config.yaml 中的环境。Mo 会在会话启动时将其中的变量复制到会话中。
使用可重复指定的 --env-file 或 --env-var NAME 选项传入本地值和密钥;它们会覆盖匹配的环境变量。--env-var 会转发 qa start 进程环境中已存在的变量;它不接受 NAME=value。切勿将密钥值写入命令或简报。使用 --tunnel 进行私有访问。并发限制在会话启动时固定。如果目标过载,需要降低限制,请运行 qa stop --subagents 并启动新会话。如果目标需要将浏览器交互放慢至人类节奏,请使用 --interaction-speed <default|human>。
跟进会话
使用此监视器打印新发现的错误名称、判定状态和显示状态变化。Mo 需要你提供输入或报告终止状态时,监视器会退出:
seen=""
while :; do
snapshot=$(qa status "$session_id" --full) ||
{ echo "status request failed"; sleep 30; continue; }
events=$(jq -r '"displayState \(.displayState // .state)",
(.findings.bugs[] | "\(.kind) \(.name)"),
(.findings.verdicts[] | "verdict \(.status)")' \
<<<"$snapshot" | sort)
comm -13 <(printf '%s\n' "$seen") <(printf '%s\n' "$events")
seen=$events
if [[ $(jq -r '.attentionPending // false' <<<"$snapshot") != true ]] || [[ $(jq -r '.displayState // .state' <<<"$snapshot") == needs_you ]]; then
case $(jq -r '.displayState // .state' <<<"$snapshot") in
needs_you | blocked | findings | incomplete | replied | ready | sleeping | cancelled | failed_start | failed | waitingOnUser | idle | stopped) break ;;
esac
fi
sleep 30
done
对于较旧的、仅包含生命周期信息的响应,idle 或 stopped 并不能证明子 Agent 已完成;请在 Web 会话中确认任务已完成。
工作时,请使用能报告监视器输出的主机工具;如果环境支持接收运行中 Agent 消息的执行器子 Agent,也可以使用它。 否则,请保留命令会话,并在各项任务之间检查其输出。
在没有执行器子 Agent 的 Codex 中,请在长时间运行的 exec_command 前台运行监视器,保留其返回的会话 ID,并使用 write_stdin 获取输出。不要追加 &、将其分离运行,或在其仍运行时结束本轮对话。
Shell 变量不会跨独立命令保留,因此请直接填入 Mo 会话 ID,或在设置该 ID 的同一个 Shell 中启动监视器。
你需要处理阻塞问题,并将用户的决定告知 Mo。
displayState 是会话在 UI 中显示的状态。status、read 和 report 都会报告其中相同的状态词:
| 状态 | 含义 |
|---|---|
running | Root Mo 正在工作。 |
waiting_on_agents | Root Mo 当前空闲;其内部子 Agent 正在工作。 |
needs_you | Mo 需要访问权限、决定或答复。阅读其回复,并使用 qa send 作答。 |
blocked | 请求遇到了工具、访问权限、配额或 Agent 故障。检查回复并解决阻塞问题。 |
findings | 没有 Agent 正在运行;需要审查错误或问题。 |
incomplete | 没有 Agent 正在运行;报告覆盖范围受阻或未经验证。 |
replied | 没有 Agent 正在运行;Mo 已回复,但未提供完整的 QA 报告。 |
checking | Mo 正在检查其最新回复。继续轮询结果。 |
ready | 没有 Agent 正在运行;已保存的报告完整且无问题。 |
sleeping | 没有 Agent 正在运行,也没有报告或最终回复。 |
cancelled | 工作已停止。 |
failed_start | 会话从未启动。请启动新会话。 |
failed | 会话失败。检查其记录。 |
sessionState 是生命周期状态(starting、working、 | |
waitingOnUser、waitingOnAgents、idle、stopped 或 failed),在三个命令中的值也完全相同。state 是旧版字段,在出现的地方都是 | |
sessionState 的别名。createdAt 是会话创建时间, | |
lastActivityAt 是最后一次持久化更新的时间。latestTurn 包含 | |
最近一次持久化的助手计时元数据:startedAt、completedAt 和 | |
durationMs。部分计时值使用 null。运行较早版本 API 的服务器可能会在 read 和 report 中省略 displayState;此时请使用 | |
qa status 获取显示用状态词。 |
对于 Mo 的提问和回复(而非发现),请使用此有界读取:
qa read "$session_id" --from start --timeout 45s --json
它会读取已持久化的对话消息,以及等待期间流式传输的面向用户的消息。
--from latest 也会漏掉在读取开始前完成的轮次。在
read 响应中,displayState 与 status 状态词一致,而 state 和 sessionState 表示生命周期状态。运行较早版本 API 的服务器会省略 displayState;此时请使用 qa status 获取显示用状态词。
timedOut: true 表示 Mo 仍在工作。
使用 --json 时,read 会向 stdout 写入一个 JSON 响应,不输出进度文本。
不使用 --json 时,若读取等待超过两秒,则会向 stderr 输出运行状态信息。返回的消息会写入 stdout,而超时或停止状态文本会写入 stderr。
qa wait "$session_id" --json 会在根 Agent Mo 的轮次结束、停止或需要输入时返回。退出代码 2 表示 Mo 需要输入;4 表示它已停止。
内部子 Agent 可能仍在运行。请确认 qa status 不再报告
running、waiting_on_agents 或 checking,然后检查结果。needs_you 和
blocked 需要处理;findings、incomplete 和 replied 是已结束的结果,但并不能证明 QA 已通过。所有工作结束后,可使用 qa report --require-idle 导出已保存的部分报告。
切勿发送消息询问进度。请使用 status、read 或 wait。
仅在回答阻碍问题,或有意引导或重新检查工作时发送消息:
qa send --session-id "$session_id" --wait 45s "Use the staging account."
在工作进行期间发送消息,会在工具调用之间引导根 Agent Mo,而正在执行的工作会继续进行。Mo 空闲时,消息会启动它的下一轮。若未使用 --wait,请通过 read 确认回复。
完成或修复
呈现最终结果前,请阅读报告。确认覆盖范围符合用户的要求。会话空闲或未发现错误,本身并不能证明 QA 已通过。
如果用户要求修复,请阅读 修复循环。否则,请勿更改应用代码。
选择停止方式:
qa stop <session-id>仅中断根 Agent Mo。子 Agent 会继续测试、提交发现并产生费用。根 Agent Mo 会保持停止状态,直到你下次运行qa send。使用此命令可在不丢失正在进行的测试的情况下重新引导 Mo。qa stop <session-id> --subagents还会停止所有正在运行的子 Agent。使用此命令可停止产生费用。仍可通过qa send恢复会话。qa archive <session-id>会取消所有工作、隐藏会话,并拒绝后续的qa send。只能通过 Web 取消归档。
qa upload 会返回一个沙盒路径。请将该路径发送给 Mo,因为本地路径在它的沙盒中不存在。如果 --output 指定的是目录,请在运行 qa download 前创建目标目录。运行 qa <command> --help 查看语法。
备选方案:无法访问代码仓库时提供源代码上下文
优先在 Mo 中配置 Git 访问,以获取代码仓库上下文。如果无法访问,请告知用户并建议配置访问权限。
无法配置 Git 访问时,请准备一个临时源代码快照,其中只包含 Mo 所需的文件。上传前请检查其中的内容;排除 .env 文件、凭据、私钥、令牌、node_modules、构建输出以及无关的客户数据。测试未提交的工作时,请包含相关的本地更改或经过审查的补丁。
启动会话后,使用 qa upload 上传快照,并使用 qa send 将返回的沙盒路径发送给 Mo。上传后请删除本地临时快照。告知 Mo 将其用作只读上下文、哪些路径具有权威性、它代表的是基线代码还是修改后的代码,以及哪些命令或依赖文件说明了如何使用它。本地路径在 Mo 的沙盒中无法使用。