@expo/verify

中文文档
0.11.24发布于 2026/11/05MITTypeScriptES Module零依赖近 30 天下载 4989

Portable engine for the /verify agent pipeline — runs under GitHub Actions, EAS Workflows, or locally. See expo-sandbox-mcp LLP 0020.

原始使用文档
文档目录8 节
  1. Usage
  2. Commands
  3. Library use
  4. Duplicate pull requests
  5. Triage
  6. Adopting a repo
  7. Running on EAS Workflows
  8. Releases

@expo/verify

Portable engine for the /verify agent pipeline: an AI agent investigates a GitHub issue or pull request in an isolated sandbox, a second agent attacks the draft, and the revised findings post back to the thread. This package carries all the logic; the repos that use it hold only a thin workflow file and a .expo-agents/verify/ profile.

Design of record: LLP 0001 in this repository.

Usage

No install needed:

npx @expo/verify <command>

Commands

CommandWhat it does
verify run [--dry-run]Run the investigation here — on a CI runner, an EAS worker, or a laptop: context → investigate → critic → revise → publish. A comment body in env selects the comment path (gate, ack, announce, report). --dry-run investigates for real but posts nothing.
verify mint / verify revokeThe scoped-token steps a workflow runs around run: mint exchanges the parent EXPO_SANDBOX_MCP_TOKEN for a scoped token and writes the agent's mcp.json to VERIFY_MCP_CONFIG (0600); revoke releases it afterwards. The run step then holds only the scoped token — the parent is mapped into the mint/revoke steps on GHA and blanked on the run step on EAS. Without VERIFY_MCP_CONFIG, run mints in-process (the laptop path).
verify dispatch <target>Start a run remotely on the profile's runner (GitHub Actions or EAS Workflows) for an issue/PR number or URL, quietly. verify <target> is shorthand.
verify triage <owner/repo#N> [--dry-run]Classify an issue or PR (classify → critic → revise, no tools) and publish routing labels plus a triage comment as the profile's bot. --dry-run writes the proposed result locally without touching GitHub. Only expo/expo is supported for now; see Triage.
verify init --repo <owner/name>Scaffold .expo-agents/verify/ and the thin runner workflow. Repos set up before 0.9 keep .verify/: every command looks for the new name first and falls back to the old one.
verify verify-configCI guard: profile validation, credential-env lock, version-pin assertion.
verify doctorRead-only environment/profile/credential triage.
verify status / verify lsDashboard of in-flight and recent runs / in-flight only. On GitHub Actions this lists the dispatch and comment workflows, skipping gate-skipped runs, and reports each finished run by its jobs' outcome — the thin workflows use job-level continue-on-error, so the run itself always says success. EAS runs are titled from the job outputs the engine emits (target, mode, outcome), since EAS has no per-run name.

Comment commands (/verify, @expo-bot verify, @expo-bot check, @expo-bot triage, and work requests) receive an 👀 acknowledgment without a "started" comment by default. Pick the agent model with --model <name>, a shorthand flag (--fable, --opus, --sonnet, --haiku), or the phrase with <name> on verify, check, and triage commands, for example @expo-bot verify with fable. Work requests accept only the flag forms, since "with" is ordinary prose in a task. Add --announce on the first line to post one, for example @expo-bot verify --announce. --no-announce takes precedence if both flags are present. Findings and failure reports still post to the thread. Use verify status to find runs without a start comment.

Library use

The package also exports the sensitive-path classifier, so another engine can use the same rules as the publisher:

import { sensitivePaths } from "@expo/verify";

sensitivePaths([".github/workflows/ci.yml", "src/index.ts"]);
// [{ path: ".github/workflows/ci.yml", category: "ci", reason: "..." }]

Each hit has one category:

  • ci: files CI runs, such as .github/, .eas/, fastlane/, .changeset/config.json, and the root bin/, tools/, and scripts/.
  • agent-instructions: files agents read, such as AGENTS.md, CLAUDE.md, GEMINI.md, .claude/, .agents/, .cursor/, and .mcp.json.
  • supply-chain: lockfiles (including npm-shrinkwrap.json), patches/, binding.gyp, registry config including bunfig.toml, and dependency files such as Gemfile and Podfile.
  • vcs-hooks: git hooks, hook-manager config such as lint-staged and lefthook files, and git config such as .gitmodules and .gitattributes.
  • secrets: keys, certificates, .env files, and secrets/.
  • package-manifest: a package.json whose scripts, packageManager, devEngines, git hook config (lint-staged, simple-git-hooks, husky), trustedDependencies, or dependency overrides change. Pass { manifests } with the before and after text; without it, every package.json is a hit.

Matching ignores case, because a macOS checkout does. The publisher refuses every hit, and also refuses any staged symlink or submodule change, which no path rule can see. The package also exports deniedPaths (the publisher denylist), unsafePath, and hasControlCharacters.

Duplicate pull requests

In pr fix mode the publisher checks the fix against every open pull request before opening one. File overlap only shortlists: an open PR that touches every non-changelog file the fix touches is a candidate, capped at five. For each candidate a tool-less, schema-bound model call reads the shared-file patches on both sides and answers whether the candidate already makes the same change (templates/duplicate.md is the policy). A confident duplicate keeps the pushed branch and opens no PR; anything else opens the PR and lists the candidates, with the judge's one-line reason, for the reviewer. Without a judgment (no model, a failed call, a malformed reply) the fallback is a symmetric file-set match. Everything the decision saw is written to .verify-out/duplicate-judge.json.

Profile field, all keys optional: "duplicateJudge": { "enabled": true, "model": "claude-haiku-4-5-20251001", "threshold": 0.7 }. The judge runs on the run's model credential with the same isolation as triage.

Triage

From this source checkout, with gh authenticated and a Claude Code version supporting --safe-mode and --json-schema:

bun src/cli.ts triage expo/expo#49760 --dry-run --out-dir /tmp/verify-triage

Triage supports Expo issues and PRs. It collects context and runs classify → critic → revise with Opus, without tools or sandbox access. --dry-run renders proposed results without writing to GitHub.

Maintainers can comment @expo-bot triage on an issue or PR to classify it and publish routing labels plus a preliminary triage comment. Commands receive an 👀 acknowledgment; the start reply is opt-in with --announce. The first verify run also attempts triage before investigation. Later verify runs skip targets with a completed triage comment authored by the configured bot; an explicit triage command always reruns it. Triage failure never blocks verify.

For local publishing, omit --dry-run and use the target repository's trusted profile (--config-dir PATH if needed), authenticated as its configured bot. Publishing only adds existing routing labels and updates the bot's triage comment; it never closes targets or removes labels. Platforms become iOS, Android, or Platform: web. A PR gets no SDK label; its author decides whether to add one. Bug issues may receive severity: critical, severity: high, severity: medium, severity: low, or severity: trivial. Any existing severity label is preserved, including on explicit reruns. Reports spell out the code, name, and meaning (for example, S3 - Low). Comments use short impact and scope bullets rather than a narrative summary. The verdict still records workaround status, which informs severity, but the comment leaves it out. An uncertain completed verdict receives no labels but still counts as triaged. In expo/expo, every newly opened issue and PR, external contributors' included, is triaged automatically with verify triage <target> --if-untriaged, which skips a target the bot has already triaged. The policy is templates/triage.md; configurable label maps remain deferred.

Each target gets a unique output directory containing context, phase responses, draft.json, review.json, result.json, and any proposed-comment.md. The result includes proposed/skipped labels, input provenance, elapsed time, and model-reported USD cost (an estimate, not a subscription invoice). Failures retain error.json and any completed phase artifacts.

Options: --model (default claude-opus-5-5), --timeout-seconds (default 120 per phase, maximum 300), and --max-budget-usd (default 0.50 per phase, maximum 5). Each run has three phases and no automatic retries. Inputs sent to the model are capped at 60,000 characters, with truncation explicitly recorded. The classifier has no tools or MCP servers; it receives an allowlisted environment and runs with customizations disabled in an empty temporary working directory. Only the fixed collector uses GitHub credentials.

Adopting a repo

  1. In the repo's checkout: verify init --repo owner/name [--runner gha|eas] [--fix pr|gist|inline|comment|none] Fix modes: pr opens a pull request from the bot fork; gist/inline post a separate patch comment; comment folds the guarded patch into the findings comment itself (a <details> block with a concise explanation and a fenced diff — for repos that should never receive a second comment or a PR); none verifies only.
  2. Fill in .expo-agents/verify/build.md (the repo's sandbox build recipe) and .expo-agents/verify/policy.md (repo-specific agent policy).
  3. Add the secrets the generated workflow names, then run verify verify-config.
  4. Dispatch: verify <issue-number> (or verify <n> --runner eas).

Running on EAS Workflows

verify <n> --runner eas from a repo's checkout uploads that checkout's verify files — .expo-agents/verify/, .eas/workflows/verify.yml, app.json, eas.json — and runs the investigation on EAS. The upload is a few KB (.easignore trims the rest; the run clones the target repo itself in a sandbox), uncommitted files are included, and there is no GitHub link or repo-ownership requirement. verify init --runner eas --eas-project <id> writes all of those files and resolves the project's owner/slug into app.json. On the worker the engine clones the target's default branch itself (shallow — the same trusted base a GitHub Actions checkout gives), so fix mode and the publisher work on EAS exactly as on GHA.

This is also how a repo you do not own gets verified: the same files, kept as local uncommitted changes, customized freely in .expo-agents/verify/; commit them only if and when you want to land verify upstream.

The profile is enforcement, not documentation: its capability fields drive the agent tool allowlist, the scoped-token mint, and which publish steps run.

Releases

Push a tag: git tag v<semver> && git push origin v<semver>. release.yml stamps the version from the tag and publishes via npm trusted publishing (OIDC). The repository is private; the published package contains only build/ and templates/.

版本与发布记录

@expo/verify 共发布 53 个版本,首次发布于 2026/08/26;过去 12 个月发布了 53 个版本。

版本发布日期距今
0.11.24latest2026/11/058 天前
0.11.232026/10/2916 天前
0.11.222026/10/2816 天前
0.11.212026/10/2817 天前
0.11.202026/10/2817 天前
0.11.192026/10/2223 天前

关于 @expo/verify 的常见问题

@expo/verify 是什么?

Portable engine for the /verify agent pipeline — runs under GitHub Actions, EAS Workflows, or locally. See expo-sandbox-mcp LLP 0020.

如何安装 @expo/verify?

在项目目录运行 npm install @expo/verify,或使用 pnpm add / yarn add / bun add。它还提供命令行工具 verify,可以用 npx verify 直接运行。

@expo/verify 支持 TypeScript 吗?

支持。包内自带 TypeScript 类型声明(package.json 声明了 types 入口),安装后即可获得类型提示,无需再安装 @types 包。

@expo/verify 支持 ESM 还是 CommonJS?

以 ES Module 形式发布,推荐使用 import 引入。在 CommonJS 项目中,Node.js 20.19+ / 22.12+ 可以直接 require() 不含顶层 await 的 ES Module,更早的版本需要改用动态 import()。

@expo/verify 需要什么版本的 Node.js?

package.json 的 engines 字段要求 Node.js >=20。版本不符时 npm 默认只给出警告,开启 engine-strict 后会拒绝安装。

@expo/verify 可以商用吗?

@expo/verify 使用 MIT 许可。宽松许可:允许商业使用、修改和再分发,通常只需在分发时保留原版权与许可声明。以上为概括,不构成法律意见,请以许可原文为准。

@expo/verify 的下载量有多少?

根据 npm 官方下载统计,@expo/verify 在 2026/10/14 – 2026/11/12 这 30 天内被下载 4,989 次,日均约 166 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@expo/verify 还在维护吗?

最新版本 0.11.24 发布于 2026/11/05(8 天前);至今共发布 53 个版本,其中过去 12 个月发布了 53 个;首次发布于 2026/08/26。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。