Forking Policy¶
When Marin needs a modified version of an upstream package, we maintain a fork
under the marin-community GitHub organization rather than vendoring code into
the Marin monorepo. Each fork carries Marin's patches on top of an upstream base,
and an automated weekly process keeps it close to upstream. This page describes
how Marin pins a fork and how the refresh runs.
How Marin pins a fork¶
Every fork is pinned under config/external/. The pins feed
config/update-external.py, which regenerates
lib/marin/src/marin/external_dependencies.py; nothing else imports a fork
revision directly. There are three pin kinds:
- Isolated uv lock (
evalchemy,harbor,MarinSkyRL): the fork is a git dependency inconfig/external/<fork>/uv.lock.uv run config/update-external.py <fork>advances the lock and regenerates the pins. - Descriptor SHA (
vllmTPU source,tpu-inference): the exact pair lives inconfig/external/vllm/tpu.toml. Its vLLM commit comes from the same maintainedmainlineage as GPU releases. The stack runs from an isolateduvxenvironment, so itsjax/jaxlib/libtpu/torchcome from the forks' own dependencies and there is no workspace lock change. - Release wheel (
vllmGPU):config/external/vllm/gpu.tomlrecords a promoted, immutable wheel per architecture. See the GPU release pipeline below. - Pinned wheel URL (
xla): thegpuextra'sjax-cuda13-pjrtsource inlib/marin/pyproject.tomlpoints at a promoted wheel from the fork's release, anduv.lockrecords its hash. This fork sits outside the weekly refresh; see the XLA fork section below.
The weekly refresh¶
.github/workflows/ops-fork-ferry.yaml runs every Monday at 08:00 UTC. It has one
matrix leg per fork unit (tpu-vllm, vllm-gpu, evalchemy, harbor). Each leg
mints a GitHub OIDC token, exchanges it for a short-lived Loom token, and launches
one Weaver session for that unit. The fork-ferry Loom profile admits all four
scheduled units; a test keeps its concurrency limit at or above the matrix size.
There is no stored PAT.
MarinSkyRL is pinned and refreshable through the skill on demand, but is not yet
in the weekly rotation. A human runs the skill for a single fork the same way.
The session runs the refresh-fork skill
(.agents/skills/refresh-fork/SKILL.md), which owns the migration procedure:
select a new upstream base or existing main-line source, replay Marin's overlays
for overlay forks, stage rebases on main-next, re-pin Marin, run the fork's declared
end-to-end test, and on green open one draft Marin PR requesting the descriptor's
reviewer. On an unresolved external blocker it files a "can't migrate" issue
instead of a PR.
config/external/migration.toml is the per-fork descriptor. It records the
upstream repository, the pin kind, the fork branch the pin tracks, how to select a
new base, the validating e2e, the blocker assignee, and the nuances a refresh must
respect (a held torch revision or a CUDA/torch/stable-ABI boundary that turns a
bump into a migration).
Validation¶
Each descriptor names one required e2e that runs before the PR opens:
| Fork | End-to-end |
|---|---|
vllm TPU source, tpu-inference |
marin-community/vllm:.github/workflows/marin-gpu-release.yaml#tpu (Qwen3-0.6B TP8 on v6e-8) |
vllm (GPU) |
tests/cluster/vllm/test_snowball_backend_parity.py |
evalchemy |
experiments/evaluation/configs/evalchemy/gsm8k-smoke.yaml |
harbor |
experiments/evaluation/configs/harbor/aime-smoke.yaml |
MarinSkyRL |
experiments/post_training/iceball_micro.py |
When an e2e fails, the refresh reruns the same workload against Marin's current pins on the old fork stack. It fixes only failures that pass on the old stack and regress on the refreshed one. A workload already broken on the old stack is recorded as a baseline failure and left for its own fix.
The vLLM GPU release pipeline¶
The GPU pin resolves to a prebuilt wheel. The current marin-community/vllm
pipeline builds an immutable CUDA 13.2 x86_64 wheel for H100, validates the
exact wheel bytes on real GPUs, and publishes a GitHub release carrying
marin-vllm-gpu-manifest.json. The GPU overlay lives on the fork's main, which
the candidate build triggers on.
A refresh dispatches those workflows against the staged main-next branch, waits
for the promoted release, downloads the manifest, and re-pins with:
That command writes gpu.toml (release tag, source commit, version, torch
backend, and each arch's wheel URL and SHA-256) and regenerates the pins. Do not
hand-edit gpu.toml; the helper re-encodes the wheel URLs the way the pin
loader validates.
Promotion¶
The refresh never force-moves a fork's stable branch. A rebase stages on main-next
and leaves the protected stable branch at the old tip; the draft Marin PR names
the main-next to main hard swap an admin performs after review. Because
the staged tip and the eventual stable tip are the same commit, the pins need no
change after promotion.
The vLLM TPU selector is the exception: it reuses an exact commit already on
the fork's main lineage, so it has no vLLM staging branch or protected-branch
promotion. Its paired tpu-inference refresh still follows the normal
main-next promotion protocol.
Existing forks¶
| Fork | Repository | Tracks upstream | Pin |
|---|---|---|---|
| vLLM TPU source | marin-community/vllm |
vllm-project/vllm |
exact main-line SHA (tpu.toml) |
| vllm (GPU) | marin-community/vllm |
vllm-project/vllm |
release wheel from main (gpu.toml) |
| tpu-inference | marin-community/tpu-inference |
vllm-project/tpu-inference |
descriptor SHA (tpu.toml) |
| evalchemy | marin-community/evalchemy |
mlfoundations/evalchemy |
isolated uv lock |
| harbor | marin-community/harbor |
harbor-framework/harbor |
isolated uv lock |
| MarinSkyRL | marin-community/MarinSkyRL |
NovaSky-AI/SkyRL |
isolated uv lock |
| xla | marin-community/xla |
openxla/xla |
wheel URL in lib/marin/pyproject.toml (gpu extra) |
The XLA fork¶
The fork exists to carry two ragged all-to-all device-kernel patches on the GPU
PJRT plugin, which only that plugin binary embeds. It is not in
config/external/migration.toml and the weekly refresh never advances it,
because its base is not a refreshable choice: jax pins an exact XLA revision by
integrity hash, so the fork must sit on the XLA commit that the workspace's
pinned jax[cuda13] release names, and it moves only when that pin moves. Every
sibling package (jax, jaxlib, jax-cuda13-plugin) installs stock at the
pin, and the wheel's +marin.<sha> local version still satisfies the stock
jax-cuda13-pjrt== requirement.
A refresh happens only after a jax bump; the step-by-step rebuild-and-re-pin
procedure is the refresh-fork skill's .agents/skills/refresh-fork/docs/xla.md.
The pin gate is
policy: do not pin a wheel whose manifest's validation block is not
status: passed. A patch can compile in and still be inert, and an inert patch
passes ordinary correctness tests, including the e2e
(tests/cluster/grug/test_ragged_ep_check.py, cluster-marked), so the
promote job's validation proves the patched behaviors are live, and a patch
that adds another required behavior adds its own check there.
When to fork¶
Fork only when upstream has not accepted patches you need, the upstream release cadence is too slow for a fix you need now, or you need a custom build such as TPU-specific or GPU-specific wheels. Prefer upstreaming changes. A fork is ongoing maintenance overhead even with the weekly refresh, and every retained patch needs a reason and a drop condition so the overlay shrinks as upstream absorbs it.