项目介绍
Agent 配套工具 · 2026-11-09 更新 · 本站尚未实测
SVRF(Silicon Valley Rocket Fuel)自称是“面向编码代理群体的合并队列”。它面向这样的仓库:编码代理提交拉取请求的速度快于人工逐个审查、测试和合并的速度。它可作为 GitHub Actions 工作流、CLI 或容器运行,监视一个 GitHub 仓库,把彼此兼容的待合并 PR 折叠到同一棵树上,只运行一次你配置的门禁(gate)命令,再对变红的批次做二分定位,找出破坏批次的 PR,其余用普通合并提交落地,并在每次合并后检查基分支的树与通过门禁的树完全一致。
该项目是单个仓库范围、较新的项目。README 说明它仍年轻且只支持单仓库;发布标签 v0.3.0 与 main 分支内容存在差异,README 建议可复现安装时固定到已审查的提交或发布标签。
核心能力
点击能力名称查看输入、输出和原文依据。
- 成批门禁:只保留两两不冲突的 PR 集合,按
family_size切分批次,批次在专用 worktree 中并行运行门禁命令。 - 冲突感知分组:基于 git 自身的两两合并结果判断冲突;仅在某类联合合并文件(如变更日志)上冲突不计入。
- 失败二分:红色批次被拆分后重新规划并再次门禁;若门禁失败行只指向唯一成员改动的路径,则直接定位该成员。
- 落地树校验:每个 PR 落地前核对合并结果等于计划树,合并后拉取合并提交再与门禁树比较。
- 代理可读状态:通过
svrf why、svrf status --json和基于 stdio 的 MCP 接口,代理可获知排队与挂起原因并自行修复分支。 - PR 表面反馈:在候选头上写
svrf提交状态,并在每个 PR 上维护一条就地编辑的评论,展示批次时间线与挂起原因。 - 仪表盘:
svrf dashboard可从轮次回执生成单文件静态站点。 - 自适应批次大小:
family_size = "adaptive"时依据自身回执选择每轮批次规模。
README 中给出的性能数字(如每小时合并数提升、每 PR 墙钟时间、门禁次数)来自其自述的特定部署与基准,细节与限制见其 docs/BENCHMARK.md,未在本站复现验证。
实际应用场景
适用场景
适合由多个编码代理频繁提交 PR、人工逐个审查测试成为瓶颈的 GitHub 仓库,且团队愿意自托管门禁机器或使用自托管 runner。若你的 CI 相对 PR 到达速度已经很快,或已使用含合并队列的 GitHub 套餐,README 也坦言 GitHub 自带合并队列可能是更简单的选择;若希望使用托管队列而不自运维,README 另列了 Mergify、Graphite、Aviator 等服务作为权衡。
安装与接入
README 给出三种方式:
- GitHub Action:无需本地安装,也不需要
svrf.toml,首次运行会自动探测项目与门禁命令。示例中通过uses: nybarius/SVRF@v0.3.0并传入github-token: ${{ secrets.SVRF_TOKEN }},以每 5 分钟 cron 和ready_for_review事件触发。 - CLI:需要 Python 3.11+、git 与
ghCLI,可pipx install git+https://github.com/nybarius/SVRF(或pip install git+https://github.com/nybarius/SVRF)。安装后svrf init通过探测生成svrf.toml,svrf doctor只读检查令牌权限、分支保护与门禁命令。运行svrf run --once执行一轮,或用svrf watch持续轮询。 - 容器:README 给出
docker build与docker run命令,挂载svrf.toml与状态卷,并通过GH_TOKEN传入令牌。
另可选安装 systemd 定时器(bash systemd/install.sh --enable)。完整的 Action 输入、零配置行为见 docs/ACTION.md,MCP 与代理用法见 docs/AGENTS.md。
使用条件与限制
- 是否需要部署
- 需自行准备运行环境,具体要求见正文
- 是否需要注册
- 账号和认证要求见正文;未明确说明的项目仍待核验
- 是否需要 API Key
- 待核验
- 费用与额度
- 费用边界见正文,项目许可不代表模型或托管服务免费
- 所需权限
- 待核验
- 许可证与服务条款
- 待核验
权限费用与限制
- 令牌权限:
GH_TOKEN或secrets.SVRF_TOKEN需要推送分支和合并 PR 的权限,具体范围按docs/GITHUB_SETUP.md核查;README 未在本页罗列完整权限清单。 - 速率限制:每轮先读 GitHub 速率预算,剩余低于
train.rate_floor(默认 200)时暂停;一次快照最多列出 1000 个打开 PR。 - 单仓库:每仓库一个 train,通过文件锁保证单一所有者,第二个所有者会以退出码 3 结束。
- 门禁与机器资源:门禁命令在自托管环境运行,README 提供内存守卫等配置项;超时按重试处理而非判为红色。
- 证明边界:Lean 定理针对抽象合并步骤模型成立,不构成对 Git、Python 程序或整个系统的形式化验证;运行时另以实际落地树与门禁树比较作为检查。
- 费用:README 提到商业与企业条款、支持服务可发邮件咨询,未公开价格,费用需向官方核验。README 未声明完全免费或免费额度。
- 平台:示例使用
ubuntu-latest,容器方式可自托管;其他操作系统是否受支持资料未说明,需核验。
国内使用情况
网友核验 用户经验分享
与站长实测独立,不代表官方认证或本站已实测。
最近核验:暂无有效核验。参与人数按当前项目有效身份去重;不同核验项分别统计,不合并成用户总结果。仅统计审核通过且未过期的记录。
分项统计、有效期与样本量
| 核验项目 | 有效人数 | 成功 / 部分 / 失败 / 无法判断 | 成功率 | 最近核验 / 有效期 |
|---|---|---|---|---|
| 官方网站访问 | 0 | 0 / 0 / 0 / 0 | 样本不足 | 暂无 / 7 天 |
| GitHub 仓库访问 | 0 | 0 / 0 / 0 / 0 | 样本不足 | 暂无 / 7 天 |
| 安装与运行 | 0 | 0 / 0 / 0 / 0 | 样本不足 | 暂无 / 30 天 |
| 官方服务国内连接 / MCP 连接 | 0 | 0 / 0 / 0 / 0 | 样本不足 | 暂无 / 30 天 |
| 国内网络情况 | 0 | 0 / 0 / 0 / 0 | 样本不足 | 暂无 / 7 天 |
| 国内模型兼容性 | 0 | 0 / 0 / 0 / 0 | 样本不足 | 暂无 / 30 天 |
| 自定义 API | 0 | 0 / 0 / 0 / 0 | 样本不足 | 暂无 / 30 天 |
| 海外服务依赖 | 0 | 0 / 0 / 0 / 0 | 样本不足 | 暂无 / 30 天 |
| 海外账号要求 | 0 | 0 / 0 / 0 / 0 | 样本不足 | 暂无 / 30 天 |
| 中文界面 | 0 | 0 / 0 / 0 / 0 | 样本不足 | 暂无 / 30 天 |
| 客户端兼容性 | 0 | 0 / 0 / 0 / 0 | 样本不足 | 暂无 / 30 天 |
| 账号及费用信息 | 0 | 0 / 0 / 0 / 0 | 样本不足 | 暂无 / 30 天 |
成功率 = 成功 ÷(成功 + 部分成功 + 失败);无法判断不计入分母。至少 5 份可判断结果才显示成功率。账号、费用、海外依赖与语言等事实项,成功表示核查结论与资料吻合,具体观察另行统计;不表示免费或没有海外依赖。不同网络、客户端和版本的结果不能直接等同。
最近有效核验
暂无审核通过且未过期的网友核验。欢迎提交真实使用记录。
查看全部有效核验 →国内实测状态:国内可用性待核验。协议兼容和官方资料说明不等于国内网络可用。
- 官方网站访问
- 尚未实测 待核验
- GitHub 仓库访问
- 尚未实测 待核验
- 官方服务国内连接
- 尚未实测 待核验
- 国内网络情况
- 尚未实测 待核验
- 国内模型兼容性
- 尚未实测 待核验
- 自定义 API
- 尚未实测 待核验
- 海外服务依赖
- 尚未实测 待核验
- 海外账号要求
- 尚未实测 待核验
- 中文界面
- 尚未实测 待核验
- 国内最后核验时间
- 尚未实测
许可与国内使用
仓库代码采用 PolyForm Shield 1.0.0 许可(见 LICENSE),允许使用、修改与再分发,包括在公司内部用于自有仓库,但不得用于与 SVRF 竞争的产品;商业与企业条款、竞争或嵌入产品、支持与担保可另行获取(见 COMMERCIAL.md)。README 说明截至 v0.1.0 的发布版本曾以 Apache-2.0 发布并继续按该许可提供。公开仓库不等于所有功能与服务免费,托管 Action 所依赖的 GitHub 服务、容器镜像等费用与条款需分别核验。
国内使用方面:资料未说明对国内网络、GitHub 访问、镜像源或本地化支持情况,相关部署可行性、延迟与合规需自行核验;README 未提供中文文档。
项目资料与来源
字段依据与待核验事项
access:来源确认 · pipx install git+https://github.com/nybarius/SVRF # or: pip install git+https://github.com/nybarius/SVRF
project_type:来源确认 · SVRF is a self-hosted merge train for repositories where coding agents open pull requests faster than they can be reviewed, tested, and merged one by one.
原始 README(折叠技术参考)
<p align="center">
<img src="docs/img/hero.svg" alt="SVRF: the merge queue built for agent swarms. Batches, bisects, and proves every landing." width="100%">
</p>
# Silicon Valley Rocket Fuel (SVRF)
**The merge train for coding-agent swarms. Batch compatible PRs, isolate failures, verify landed trees.**
[](https://github.com/nybarius/SVRF/actions/workflows/ci.yml)
[](LICENSE)
[](proofs/README.md)


SVRF is a self-hosted merge train for repositories where coding agents open pull
requests faster than they can be reviewed, tested, and merged one by one. It runs as a GitHub Actions workflow, a CLI, or a container; watches a GitHub
repository; folds compatible ready pull requests together; runs **your** gate command once
on the folded tree; bisects a red batch down to the pull request that broke it; and lands
the rest with ordinary merge commits, checking after every merge that the base branch holds
exactly the tree that was gated. Agents can read queue and hold reasons through `svrf why`, `svrf status`, or the
stdio MCP interface, then repair their own branches. SVRF retries a held head when
its consequential inputs change. Its scheduling technique is a *braided train*: pull requests that do not conflict are
braided into families that gate in parallel; the ones that do conflict wait for a later
round.
<p align="center">
<img src="docs/img/benchmark.svg" alt="Benchmark: 5.8 to 16.3 merges per hour, about 3 minutes to about 47 seconds of wall time per PR, 0.79 gate runs per merged PR; best batch 13 PRs in 2 gate runs in 4:46" width="100%">
</p>
On a 17,000-declaration Lean monorepo fed by coding agents it went from 5.8 to 16.3 merges
per hour on the same machine, about 47 s of wall time per merged PR, 0.79 gate runs per
merged PR with bisection included, and 0 landed-tree mismatches. One day, one repository,
and the "after" window was arrival-bound: details and caveats in
[docs/BENCHMARK.md](docs/BENCHMARK.md).
> **Release and source:** The latest tagged release is `v0.3.0`. The `main`
> branch includes subsequent admission, cancellation, retry, and PR-surface
> changes that are not in that tag. The Action example below pins the tagged
> release; installing the CLI from the Git URL reads `main`. For reproducible
> installations, pin a reviewed commit or release tag. See [CHANGELOG.md](CHANGELOG.md).
## Quickstart
**0. Watch it work first (optional, no GitHub needed).** A fake agent swarm opens eight
pull requests against a local bare repository (two conflicting, one failing its own
test, one committed out of order, one stacked on another), and the real train code
lands them:
```sh
python3 demo/run_demo.py
```
**1. Install.** Either add the published GitHub Action. It needs no local install and no
`svrf.toml`: on its first run it detects your project and gate command.
```yaml
# .github/workflows/svrf.yml
name: svrf
on:
schedule:
- cron: "*/5 * * * *"
pull_request:
types: [ready_for_review]
jobs:
round:
runs-on: ubuntu-latest
concurrency: { group: svrf-round, cancel-in-progress: false }
steps:
- uses: actions/checkout@v4
- uses: nybarius/SVRF@v0.3.0
with:
github-token: ${{ secrets.SVRF_TOKEN }} # see docs/GITHUB_SETUP.md for scopes
```
Or install the CLI, to run it on your own machine, in a container or on a self-hosted
runner (Python 3.11+, git and the `gh` CLI):
```sh
pipx install git+https://github.com/nybarius/SVRF # or: pip install git+https://github.com/nybarius/SVRF
```
Either way the token (`GH_TOKEN` or `secrets.SVRF_TOKEN`) needs permission to push
branches and merge pull requests ([docs/GITHUB_SETUP.md](docs/GITHUB_SETUP.md)).
**2. Configure.** The Action needs nothing further. With the CLI, `svrf init` writes
`svrf.toml` by detection (project type, gate command, base branch, repository), asking at
most three questions with sensible defaults; `svrf doctor` then checks the token's
scopes, branch protection, and that the gate command actually runs.
```sh
svrf init # --yes accepts every default; --repo/--base/--gate override one
svrf doctor
```
`svrf init` never overwrites an existing `svrf.toml` or workflow file unless you pass
`--force`. Presets for Lean, Python and Node are in [presets/](presets/).
**3. Run.**
```sh
svrf run --once # one round; or `svrf watch` to keep going
```
or install the systemd timer (`bash systemd/install.sh --enable`), or run it in Docker:
```sh
docker build -t svrf .
docker run -d --name svrf -e GH_TOKEN -v "$PWD/svrf.toml:/config/svrf.toml:ro" -v svrf-state:/var/lib/svrf svrf
docker logs -f svrf
```
See [docs/ACTION.md](docs/ACTION.md) for the Action's inputs and zero-config behaviour,
and [docs/AGENTS.md](docs/AGENTS.md) for `svrf why`, `svrf status --json` and `svrf mcp`:
a coding agent whose pull request gets held can find out why and fix it itself.
## What you'll see
The demo, as it runs ([docs/demo.cast](docs/demo.cast) is the asciinema recording;
`asciinema play docs/demo.cast`):
<p align="center"><img src="docs/img/demo.svg" alt="Animated terminal: the demo opens eight pull requests, runs the train tick by tick, and prints what merged and what was held" width="100%"></p>
On every pull request it merges, a comment naming the batch it was gated in, the gated
tree, and the receipt:
<p align="center"><img src="docs/img/pr-comment.svg" alt="The comment SVRF leaves on a merged pull request" width="720"></p>
And `svrf dashboard` builds a static site from the round receipts: live queue, throughput,
gates and wall time per PR, a batch timeline, the bisection tree of every red batch, holds,
and the landed-tree = gated-tree tally. One self-contained `index.html`: open it from disk
or publish it to GitHub Pages ([docs/DASHBOARD.md](docs/DASHBOARD.md)). Shown here on
anonymized receipts from a real day of runs (`make dashboard-sample`); SVRF's own
[live dashboard](https://nybarius.github.io/SVRF/dashboard/) runs the same way against its
own production train (see [docs/CASE_STUDY.md](docs/CASE_STUDY.md)):
<p align="center"><img src="docs/img/dashboard.png" alt="The SVRF dashboard: totals, live queue, landed-tree tally, throughput, gates per PR and wall time per PR" width="100%"></p>
<p align="center"><img src="docs/img/dashboard-bisection-dark.png" alt="Dashboard, dark theme: batch timeline and the bisection tree of a red batch" width="100%"></p>
## Commands
| Command | What it does |
| --- | --- |
| `svrf init` | detect the project and write `svrf.toml` (and a scheduled workflow); needs no config |
| `svrf doctor` | read-only checks: token scopes, branch protection, gate command, rate budget |
| `svrf run --once` | one round: discover, admit, gate, land (what the timer runs) |
| `svrf watch` | a round every `train.interval_seconds` |
| `svrf plan --dry-run` | one round that gates and reports but pushes, merges and remembers nothing |
| `svrf land --prs 12,15` | one batched run over the named pull requests |
| `svrf status [--json]` | held pull requests and the last round, from local state only |
| `svrf why 12` | why one pull request is held or queued, and what to do next ([docs/AGENTS.md](docs/AGENTS.md)) |
| `svrf mcp` | an MCP server over stdio for coding agents: queue status, why held, requeue ([docs/AGENTS.md](docs/AGENTS.md)) |
| `svrf forget 12,15` | drop pull requests from the held memory |
| `svrf dashboard --receipts DIR --out DIR` | a static site from the round receipts ([docs/DASHBOARD.md](docs/DASHBOARD.md)); needs no config or token |
## How a round works
<p align="center"><img src="docs/img/architecture.svg" alt="Architecture: PR swarm, admission, batch planner, gate slots with bisection of red batches, landing with a tree check, main" width="100%"></p>
1. **One list.** Read GitHub's rate budget, then one pull-request list. An idle round
costs exactly that.
2. **Admission.** Skip drafts, forks, pull requests with the hold label and ones based
on another branch. A stacked pull request waits for its parent and is retargeted to
the base once the parent merges; if the train re-landed the parent, the child's own commits
are restacked onto the ordered branch, but only when the result is git's merge of the two heads. Each remaining head gets the admission check: does it
merge onto the base, and (optionally) is its history ordered and does your extra
admission command pass. Up to `admission.slots` heads are read at once, each in its own
worktree. Completed heads reach the train while other admissions continue; all
results available together stay in one batch. Admission and gating share the memory
limit, so a gate still waits when the host has no capacity. Uneven completion can
produce smaller batches and more gate runs, in exchange for earlier progress.
3. **Families.** Read which pairs of heads conflict (git's own merge of each pair). Keep
the largest set that pairwise does not conflict; conflicts only on union-merge files
(changelogs, requirement lists, import indexes) do not count. Fold the kept heads onto
the base and cut them into families of `family_size` (a fixed count, or the adaptive
size below). Family k is gated on top of
families 1..k, so families gate in parallel and every gated tree is a tree the base
will actually hold.
4. **Gate.** Run your commands once per family in a dedicated worktree slot.
5. **Land.** For each pull request in a green family: recompute the merge of the current
base into the branch, check it equals the planned tree, push it to the branch, and
merge the pull request with a merge commit pinned to that sha. Then fetch the merge
commit and compare its tree with the gated tree.
6. **Red.** A red family is split and each part is replanned on the current base and gated
again. When the gate's failing lines name a path that exactly one member changed, the parts
are that member and the rest; otherwise they are halves. A red single pull request is held
with its failing lines.
7. **Memory.** A held pull request is not read again until its head changes or the base
changes a file its hold depended on.
## Adaptive family size
With `family_size = "adaptive"` the train chooses each round's family size from its own
retained receipts. A family of `k` pull requests costs one gate run when every member is
green. When any member is red it is halved and each half is gated again. With a per-PR red
probability `p`, the expected gate runs for a family of `k` are
E(1) = 1, E(k) = 1 + (1 - (1-p)^k) * (E(floor(k/2)) + E(ceil(k/2)))
The size chosen minimises `E(k)/k` for `k` in `1..family_cap`. `p` is the maximum-likelihood
estimate from each round's first family, counted once per exact set of (pull request, head)
pairs: a held red head re-gated in later rounds is the same verdict, not a new red arrival.
With no receipts yet, the cap is used. Each receipt records the choice and its evidence under
`batching`.
On one busy deployment, counting every re-gate of the same red heads gave `p = 0.36` and
`k = 1`. Counting each (pull request, head) once gave `p = 0.17` and `k = 6`, which is 0.64
gate runs per pull request. The first round at `k = 6` landed 20 pull requests.
A check that can refuse a head cheaply belongs in `admission.command`. A refusal found only
at the gate costs a gate run, plus every speculative family stacked behind it in that round.
## How it stays safe
| Invariant | Enforced by | Stated in `proofs/` as |
| --- | --- | --- |
| The base only ever lands trees that were gated: the tree after each family is compared with the gated tree | `Train.land_family` | `landed_eq_gated`, `checkLanding_iff` |
| A commit landing on the base from outside mid-family stops the family; the rest is regated | `Train.land_family` | `checkLanding_refuses_moved` |
| Bisected segments each land their own gated tree | `Train.settle_red` | `segments_land_last_gated` |
| Trees between two merges of one family are not claimed as gated; a family stopped midway is recorded `PREFIX_LANDED_UNGATED` | receipts | `prefix_is_fold`, `all_gated_iff_each_prefix` |
| A read that fails (rate limit, network, a gate machine falling over) is retried later, never turned into a hold | `admission_decision`, `Train` | `read_failure_never_holds` |
| A held pull request is retried exactly when what it depended on changed | `retry_due` | `retry_iff`, `held_verdict_stands` |
| Non-conflicting pull requests can share a family: disjoint merges commute, in any interleaving | `choose_families` | `strands_comm`, `interleaved_landing` |
| An out-of-order history is re-landed with the identical final tree, or held | `RealGit.reland` | `reland_tree` |
| One train per repository: a file lock; a second owner exits 3 without reading anything | `owner_lock` | |
| Every git call names its clone (`git -C`) and every `gh` call names its repository | `gh_argv`, a test over the source | |
| Branches are updated by refspec push, never forced, never checked out | `RealGit` | |
| A configured tree provider's tree is used only when it is git's own merge tree for that step; anything else keeps git's tree | `Train.merge_step` | |
The Lean theorems establish invariants of an abstract merge-step model, not a formal
verification of Git, the Python program, or the complete system. Runtime checks
compare each observed landed tree with the tree that was gated.
The theorems are about a model of the merge step, not about git. The code never relies
on the model being right: it reads every landed tree and compares it with the gated one,
which is exactly the theorems' hypothesis.
Every round writes a JSON receipt (`<state_dir>/receipts/`): the pull-request snapshot,
the pairwise conflicts, each family with its planned tree, every gate with its output,
every merge with its gated and observed tree, holds, alerts, rate waits and API call
counts. `svrf dashboard` renders them ([docs/DASHBOARD.md](docs/DASHBOARD.md)). `<state_dir>/held.json` lists every held pull request with its reason.
## On the pull request
The train's decision is also visible without leaving GitHub: a `svrf` commit status on
each candidate head (`queued (position 3, batch F2)` → `gating batch F2 with #12 #15` →
`landed in batch F2 (gate 1m32s)` or `held: <reason>`), and one living comment per pull
request, created once and edited in place, with a mini timeline, the batch it gated with,
and, on hold, the failing lines and what to do next. See
[docs/PR_SURFACE.md](docs/PR_SURFACE.md) for a rendered example. Controlled by
`ui.pr_comments` and `ui.status_checks` (both default on); every write is rate-limit aware
(an unchanged comment is never re-edited) and counted in the receipt's `surface` field.
## Configuration
`svrf.toml` ([full example](svrf.example.toml), presets in [presets/](presets/)).
Unknown keys are refused.
| Key | Default | Meaning |
| --- | --- | --- |
| `repo` | required | `owner/name` |
| `base` | `"main"` | branch pull requests land on |
| `demand_driver` | `""` | optional trusted Python `module:factory` selecting rounds under the existing owner lock |
| `clone`, `state_dir` | under `~/.local/share/svrf` | the train's clone; its state, receipts, slots, logs, lock |
| `gate.commands` | required | shell commands run in the folded tree; green iff all exit 0 |
| `gate.setup` | `[]` | run first, under one lock shared by all slots (dependency caches) |
| `gate.timeout_minutes` | `60` | a timeout is retried later, never red |
| `gate.memory_gb`, `gate.memory_reserve_gb` | `0`, `2` | admit another parallel gate only while memory allows; 0 turns this off |
| `gate.infra_patterns` | `[]` | extra regexes meaning the gate could not run |
| `gate.failing_pattern` | `error\|FAIL\|Traceback` | which output lines to report for a red gate |
| `gate.env` | `{}` | extra environment for gate commands |
| `train.family_size` | `8` | pull requests per gated family, or `"adaptive"`: chosen each round from the train's own receipts (see [Adaptive family size](#adaptive-family-size)) |
| `train.family_cap` | `8` | the largest family an adaptive size may choose |
| `train.jobs` | `2` | families gated in parallel, each in its own worktree slot |
| `train.max_rounds` | `3` | replanning rounds per tick |
| `train.rate_floor` | `200` | pause while GitHub's remaining budget is below this |
| `train.comment` | `true` | comment on merged pull requests |
| `train.snapshot_limit` | `1000` | the most open pull requests one snapshot lists; more is refused as `SNAPSHOT_LIMIT_EXCEEDED` |
| `train.interval_seconds` | `300` | sleep between rounds in `watch` |
| `train.tick_seconds` | unset | end a tick after this long; admission reads still running carry into the next tick of the same process (`watch`). Unset: a tick waits for all its reads |
| `labels.hold` | `"train:hold"` | label that keeps a pull request out |
| `repair.enabled` | `true` | push mechanical fixes (union merges, stale base) to pull-request branches |
| `repair.union_merge` | `[]` | globs of files merged by git's union merge (`merge=union`) instead of conflicting |
| `history.order` | `"off"` | `"tests-first"` refuses code committed before its tests |
| `history.reland` | `true` | re-land refused histories in order instead of holding them |
| `history.tests`, `history.docs` | common globs | how paths are classified for the history check |
| `admission.command` | `""` | extra admission check; exit 0 admits, 126/127 means "could not run" |
| `admission.watch` | `[]` | paths every hold depends on (requirements, toolchain pins); a base change there rereads every hold |
| `admission.slots` | `train.jobs` | concurrent admission reads, with separate worktrees and the same memory guard as gates |
| `admission.capacity_command` | unset | optional dynamic cap on admission concurrency; unavailable capacity defers admissions rather than guessing |
| `admission.round_reads` | unset | maximum new admission reads per round; keeps discovery responsive under heavy backlog |
| `admission.priority_command` | unset | optional priority list, including exact `PR@HEAD` identities (see below); never bypasses admission or gating |
| `ui.pr_comments` | `true` | one living comment per pull request (see [docs/PR_SURFACE.md](docs/PR_SURFACE.md)) |
| `ui.status_checks` | `true` | a `svrf` commit status on each candidate head |
| `ui.dashboard_url` | `""` | optional: linked from the status as `target_url` |
| `merge.tree_command` | `""` | optional alternative merge engine for the family merges, cross-checked against git's own merge tree on every step ([docs/TREE_PROVIDER.md](docs/TREE_PROVIDER.md)) |
| `merge.tree_timeout_seconds` | `120` | per merge step; a timeout keeps git's tree |
Gate commands see `SVRF_BASE`, `SVRF_COMMIT`, `SVRF_LABEL` and `SVRF_CHANGED_FILES` (a
file listing the changed paths), so a gate can build only what changed.
Admission commands can write dependency evidence to the per-invocation file
`SVRF_ADMISSION_READS`. The optional JSON document has `schema:
"svrf.admission-reads/1"`, `head` and `base` matching `SVRF_HEAD` and `SVRF_BASE`,
and a `consumed` array of `{ "kind": "PATH", "id": "src/helper.py" }` rows.
`CODE` also names a repository-relative file; `DIR` uses `dir:fixtures` for a
directory dependency. `COMMIT` rows are retained as ancestry. File paths may name
currently absent files. A hold watches these dependencies together with its
changed paths and `admission.watch`; unrelated base changes leave it quiet.
Malformed or mismatched evidence causes a retry instead of a retained hold.
Commands that do not write the file keep their existing behavior. Each invocation
gets its own temporary file, including concurrent admission checks.
An explicit demand driver changes `run --once` into a drain of externally retained
work. The factory receives `Config` and returns an object with `drain(owner)`.
The driver runs inside the same owner lock as the default round; it can call
`owner._tick(requested={12, 15}, changed={12: {"parent"}})` to limit candidates while
preserving the full ancestry snapshot, admission, parallelism, holds and landing
checks. `changed` accepts `base` and `parent` to invalidate ancestry memory. Exact
round inputs are exposed in `owner.round_inputs`, including rows, parent reads,
ancestry results and the watch digest measured before admission starts.
The driver owns durable work retention, acknowledgement and wake integration. An
empty drain should perform no discovery reads. An optional `released(owner, numbers)`
hook is called after `forget` saves its state, under the same lock. Dry runs neither
notify that hook nor authorize a driver to acknowledge work. Driver import or
construction failures refuse startup; they never fall back to polling. This is a
trusted local extension point, not a module name accepted from event payloads.
Disable any ordinary timer or `watch` process when configuring an external wake
source. With no driver configured, existing CLI behavior is unchanged.
## Compared with other merge queues
Summarised from each project's public documentation, not from using all of them in
production; corrections welcome (open an issue).
| | SVRF | GitHub merge queue | bors-ng | Mergify | Graphite | Aviator | Zuul |
| --- | --- | --- | --- | --- | --- | --- | --- |
| Where it runs | your machine or container | GitHub | self-hosted | hosted service | hosted service | hosted service | self-hosted |
| Availability | any GitHub plan, any repo | private-repo availability depends on your GitHub plan (Team or Enterprise); free for public repos | archived: development has stopped upstream | paid hosted plan | paid hosted plan | paid hosted plan | self-hosted, no plan required |
| Where checks run | its own gate command, on the same machine | your CI, on queue branches | your CI | your CI | your CI | your CI | its own job runners |
| Groups pull requests into one tested batch | yes, conflict-aware | yes | yes | yes | yes | yes | yes, via speculative gating: each change is tested as if the ones ahead of it in the pipeline had already merged |
| Chooses batches by pairwise conflicts | yes | no | no | no | no | no | no |
| Union-merges configured files instead of conflicting | yes | no | no | no | no | no | no |
| Compares each landed tree with the gated tree | yes | not documented | not documented | not documented | not documented | not documented | not documented |
| Re-lands out-of-order histories | yes (optional) | no | no | no | no | no | no |
| Needs hosted CI minutes | optional; none when self-hosted | generally yes, depending on configured CI | depends on CI | depends on CI | depends on CI | depends on CI | no hosted CI required |
SVRF is young and single-repository. If your CI is fast relative to your pull-request
rate, or you're already paying for a GitHub plan that includes it, GitHub's merge queue
is the simpler choice. If you want a managed, hosted queue with no infrastructure of your
own to run, Mergify, Graphite, or Aviator are that trade-off.
## Roadmap
* **Receipted incremental checks** (planned, optional): reuse a previous gate result when
the exact inputs of a check are unchanged, instead of re-running it. Still experimental:
it ships only after it matches a full check on historical commits with zero
disagreements, as something you opt into, never a change in what a green gate means.
* A GitHub App mode that mints its own installation tokens.
## Development
```sh
make check # everything CI runs: Python tests (denylist scan + demo), Lean proofs, docker build
make demo
make wheel # sdist/wheel, smoke tested by installing into a fresh venv
make images # regenerate docs/img/*.svg from docs/BENCHMARK.md and docs/demo.cast
```
The project has no Python dependencies beyond the standard library. The proofs need
[elan](https://github.com/leanprover/elan); the toolchain is pinned in
`proofs/lean-toolchain`. `make check` also builds the container image, so it needs
Docker. See [CONTRIBUTING.md](CONTRIBUTING.md) before opening a pull request, and
[SECURITY.md](SECURITY.md) to report a vulnerability. Releasing a new version is covered
in [docs/RELEASING.md](docs/RELEASING.md).
## Support & deployment
Help getting SVRF running on your repositories, or questions about commercial use:
inquiries to **nybarius@gmail.com**.
## Exact-head admission priority
An optional `[admission] priority_command` emits one priority per nonempty line,
in preferred order. A decimal PR number retains the legacy, explicitly PR-scoped
meaning. `NUMBER@HEAD` binds priority to one positive PR number and one exact
40-character lowercase hexadecimal head. For example,
`41@aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa` prioritizes only that head of PR 41.
Head-bound entries are compared with the head in the existing pull-request list
snapshot; they cause no additional GitHub reads. A pushed or missing head receives
the normal queue ranking. The original typed entries remain in the receipt while
a smaller refill recomputes their eligible numbers from its updated snapshot.
Malformed output or a failed command is recorded as unobserved and keeps the
normal ranking. Priority never skips admission, gating, or merge checks.
The command owner must omit expired declarations. Deploy a head-aware reader
before enabling typed output. Older readers reject typed lines and keep normal
ranking; they must not be fed a stripped PR-only projection of exact-head authority.
## License
[PolyForm Shield 1.0.0](LICENSE): free to use, modify and redistribute, including inside a
company for its own repositories, as long as you don't use it to compete with SVRF. Commercial
and enterprise terms (competing or embedded products, support, warranty) are available; see
[COMMERCIAL.md](COMMERCIAL.md). Releases up to and including v0.1.0 were published under
Apache-2.0 and remain available under that license.
历史前置条件说明(补充参考)
Python 3.11+(CLI 方式)、git、gh CLI;GitHub 令牌需具备推送分支和合并 PR 权限(完整范围见 docs/GITHUB_SETUP.md,待核验);容器方式需 Docker;需要可运行门禁命令的机器或 runner;商业与企业条款费用待向官方核验;国内网络与 GitHub 访问可用性待核验。
项目来源与清单版权许可
https://github.com/nybarius/SVRF
整理来源:https://github.com/slavakurilyak/awesome-ai-agents
清单版权与许可:
MIT License
Copyright (c) 2024 Slava Kurilyak
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.