mirror of
https://github.com/BerriAI/litellm.git
synced 2026-09-23 00:41:40 +00:00
The daily compat-matrix runs from the dedicated GCP VM
`litellm-compatibility-matrix-populator` rather than from a GitHub
Actions runner. The VM has no docker daemon, has `gh` already
authenticated against an account with `pull-requests: write` on
`BerriAI/litellm-docs`, and runs a long-lived litellm checkout we can
reuse across runs. That makes Docker, the GitHub App auth flow, and the
GHA workflow itself dead code.
Removed
-------
* `.github/workflows/claude_code_compat_matrix.yml` — no longer
triggers anything; the systemd timer in this PR owns the daily fire.
* `docker_image_for_tag` + `DOCKER_IMAGE_BASE` constants and the two
unit tests that covered them.
* `_start_proxy(image, port)` / `_stop_proxy(container_id)` /
`docker run` flow, replaced by direct `uv run litellm` subprocess
management with a sigterm-the-process-group teardown.
* `--skip-proxy` CLI flag (was only useful when the GHA workflow
split docker-bringup from publish into separate jobs).
* `docs_token` parameter and `DOCS_REPO_TOKEN` env var; `gh` on
the VM is already authenticated, so we don't pass an explicit
token through the publisher.
Added
-----
* Persistent worktree flow in `publisher.py`. First run clones
`BerriAI/litellm` into `~/litellm-cron-worktree/`; subsequent runs
do `git fetch --tags && git checkout --force <stable-tag> &&
uv sync --frozen`. Disk footprint is bounded because uv sync
removes packages no longer pinned and `git clean -fdx -e .venv`
wipes per-run cruft while keeping the venv around.
* `tests/claude_code/cron_vm/` containing systemd units and a
setup README:
- `litellm-compat-matrix.service` (`Type=oneshot`, runs as the
`mateo` user, sources `/etc/litellm-compat-matrix.env` for
provider creds, hardened with `NoNewPrivileges` /
`ProtectSystem=strict` / `PrivateTmp`);
- `litellm-compat-matrix.timer` (`OnCalendar=*-*-* 06:00:00 UTC`,
`Persistent=true` so a missed run fires when the VM is back up,
`RandomizedDelaySec=10min`);
- `.env.example` documenting the provider-credential surface;
- `README.md` covering one-time install, daily operation,
`journalctl` debugging, and the gotchas (proxy port `4100` to
avoid colliding with a developer's `:4000`, `gh` token
rotation, what to do after a Claude Code CLI upgrade).
Operator notes
--------------
* The proxy now binds `:4100` by default so a developer SSH'd into
the VM with their own `:4000` proxy isn't preempted by the cron.
* The Claude Code CLI is exercised as-is from the system install;
the populator does NOT `npm install` it. Operators upgrade the
CLI by running `npm install -g @anthropic-ai/claude-code@latest`
out of band, typically after watching a `--skip-publish` run to
verify the matrix doesn't suddenly turn red.
* 20 publisher unit tests pass (`pytest
tests/claude_code/_publisher_unit_tests/`).
* End-to-end validation on the VM happens after this PR lands as
follow-up commits on the same branch — the systemd unit is
`Type=oneshot` so a manual `systemctl start` reproduces the cron.
|
||
|---|---|---|
| .. | ||
| litellm-compat-matrix.env.example | ||
| litellm-compat-matrix.service | ||
| litellm-compat-matrix.timer | ||
| README.md | ||
Cron VM setup for the Claude Code compatibility-matrix populator
The populator runs daily on a dedicated GCP VM
(litellm-compatibility-matrix-populator) rather than as a GitHub
Action. Trade-offs:
- ✅ Real VM means we can
gh auth loginagainst a human/bot account that's already a collaborator onBerriAI/litellm-docs, instead of provisioning a GitHub App withpull-requests: write. - ✅ Persistent state (a single
~/litellm-cron-worktree/and its.venv) is reused across runs, so each daily run does a fastgit checkout+ incrementaluv syncrather than a fresh clone + cold sync. - ✅ No Docker dependency — proxy is run directly via
uv run litellm. - ⚠️ The VM has to actually be on. systemd's
Persistent=truerecovers from short outages, but a multi-day outage means the matrix goes stale until the VM is back. - ⚠️ Provider credentials live on the VM filesystem
(
/etc/litellm-compat-matrix.env) instead of GitHub secrets. Treat the VM as an environment with comparable blast radius to a CI runner.
What the populator does, end to end
tests/claude_code/publisher.py (python -m tests.claude_code.publisher):
- Resolves the latest
v*-stabletag ofBerriAI/litellmvia the GitHub Releases API (tests/claude_code/resolver.py). - Reads the locally installed Claude Code CLI version
(
claude --version). - Updates the persistent worktree at
~/litellm-cron-worktree/to that tag, anduv sync --frozens its.venv.git clean -fdx -e .venvwipes any cruft from previous runs while keeping the venv around. - Boots the LiteLLM proxy as a subprocess on port
4100(override withPROXY_PORT), usingtests/claude_code/test_config.yamlfrom the checked-out tag. - Runs
pytest tests/claude_code/withANTHROPIC_BASE_URLpointed at the proxy andCOMPAT_RESULTS_PATHset so the conftest hook writes the per-test results artifact. - Builds
compatibility-matrix.jsonfrom the artifact viatests.claude_code.matrix_builder.build_from_paths. - Clones the docs repo (
gh repo clone BerriAI/litellm-docs) into a temp dir, checks out a deterministic head branch (compat-matrix/<litellm-version>-<claude-code-version>-<UTC-date>), commits the JSON, force-with-lease pushes, and opens a PR withgh pr create.
Re-running on the same day with the same versions is idempotent: the
branch name collides, the force-with-lease updates the existing branch,
and gh pr create no-ops because the PR already exists.
One-time VM setup
Run as mateo on the cron VM:
# 1. Toolchain
sudo apt-get update
sudo apt-get install -y git nodejs npm
curl -LsSf https://astral.sh/uv/install.sh | sh
sudo apt-get install -y gh # or follow https://cli.github.com/
# 2. Claude Code CLI (the cron does NOT auto-upgrade this; rerun this
# line out-of-band when you want a fresh CLI to be tested)
sudo npm install -g @anthropic-ai/claude-code@latest
# 3. Litellm dev checkout. Used as the launcher for the publisher
# module; the populator mutates a separate worktree under
# ~/litellm-cron-worktree/.
mkdir -p ~/litellm
git clone https://github.com/BerriAI/litellm.git ~/litellm/litellm
cd ~/litellm/litellm && uv sync --frozen
# 4. gh auth — must be a collaborator on BerriAI/litellm-docs.
gh auth login # follow prompts; pick HTTPS + token paste flow
# 5. Provider credentials.
sudo cp tests/claude_code/cron_vm/litellm-compat-matrix.env.example \
/etc/litellm-compat-matrix.env
sudoedit /etc/litellm-compat-matrix.env # fill in real values
sudo chmod 0600 /etc/litellm-compat-matrix.env
# 6. systemd units.
sudo cp tests/claude_code/cron_vm/litellm-compat-matrix.service /etc/systemd/system/
sudo cp tests/claude_code/cron_vm/litellm-compat-matrix.timer /etc/systemd/system/
sudo systemctl daemon-reload
sudo systemctl enable --now litellm-compat-matrix.timer
Operating it
# When does it run next?
systemctl list-timers litellm-compat-matrix.timer
# Trigger a run right now (still PRs to litellm-docs).
sudo systemctl start litellm-compat-matrix.service
# Trigger a run that does NOT open a PR (good for first-time validation).
cd ~/litellm/litellm
uv run python -m tests.claude_code.publisher --skip-publish
# Watch the most recent run.
journalctl -u litellm-compat-matrix.service -f
# Read older runs.
journalctl -u litellm-compat-matrix.service --since '2 days ago'
# Disable until further notice (e.g. while debugging).
sudo systemctl disable --now litellm-compat-matrix.timer
Gotchas
- The proxy port is
4100, not4000. This is so a developer SSH'd into the same VM with their own:4000proxy doesn't collide with a cron run. Override withPROXY_PORT=...in/etc/litellm-compat-matrix.envif you need to. uv sync --frozenrequires the resolved tag to be tagged on GitHub. If the latest stable release was made but not pushed as a git tag, the run willgit checkoutfail. Push the tag, then rerun.gh authtoken rotation is your problem. The cron does not refresh the token; if the bot account's PAT expires the run will fail atgh repo clonewith a 401. Re-rungh auth login.- First run after upgrading the Claude Code CLI is the riskiest one.
If the new CLI changes its wire format the matrix run can produce
systematic failures. Always run
--skip-publishafter a CLI upgrade to inspect the JSON before the next scheduled fire.