Skip to content

Commit 19303d0

Browse files
committed
Automate llama.cpp version-bump target selection and chunking
Add a diff-size-driven bump workflow so a version upgrade never lands an unreviewably large diff in one step. - .github/scripts/llama-next-version.sh: read-only helper that computes the next reviewable step. Reads the current pin from llama/CMakeLists.txt and the target from an explicit b<nnnn> arg or the GitHub releases atom feed, against a cached blobless mirror clone. If git diff cur..target is under the threshold (LLAMA_BUMP_MAX_DIFF_KB, default 100 KiB) it bumps straight to the target; otherwise it binary-searches the intermediate tags for the largest one still under the threshold and prints that chunk plus its compare/.patch URLs. LLAMA_BUMP_EXCLUDE_WEBUI sizes the diff excluding the auto-followed tools/ui WebUI. - docs/upgrade/llama-cpp-version-bump.md: the runbook (documentation root) for target selection, byte-size chunking, the helper, and the edit/verify/commit loop. - CLAUDE.md: link the runbook from the Upgrading/Downgrading section. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HL7d4uQ3cKR5HwYFPvZvv7
1 parent c6ac704 commit 19303d0

3 files changed

Lines changed: 262 additions & 0 deletions

File tree

Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
#!/usr/bin/env bash
2+
# SPDX-FileCopyrightText: 2026 Bernard Ladenthin <bernard.ladenthin@gmail.com>
3+
#
4+
# SPDX-License-Identifier: MIT
5+
#
6+
# Pick the NEXT llama.cpp tag to bump the pin to, one reviewable chunk at a time.
7+
#
8+
# The runbook this supports is docs/upgrade/llama-cpp-version-bump.md. Strategy:
9+
# * TARGET = the topmost RELEASE on the GitHub releases page (read from the release atom feed),
10+
# or an explicit "b<nnnn>" passed as $1.
11+
# * CURRENT = the pinned tag in llama/CMakeLists.txt (GIT_TAG b<nnnn>).
12+
# * If `git diff CURRENT..TARGET` is smaller than the threshold (default 100 KiB), bump straight
13+
# to TARGET. Otherwise CHUNK: pick the largest intermediate b<nnnn> tag whose diff from CURRENT
14+
# is still under the threshold, so each bump stays a small, reviewable patch. Re-run after each
15+
# bump to walk the remaining chunks up to TARGET.
16+
#
17+
# This tool only READS (a cached mirror clone + the pin file); it never edits the repo. Apply the
18+
# bump by hand per the runbook. It prints the compare/.patch URLs for the chosen step.
19+
#
20+
# Env:
21+
# LLAMA_BUMP_MAX_DIFF_KB per-step diff-size threshold in KiB (default 100)
22+
# LLAMA_BUMP_EXCLUDE_WEBUI if "1", size the diff EXCLUDING tools/ui (the auto-followed WebUI, which
23+
# does not need per-bump review); default 0 = the full diff you paste/review
24+
# LLAMA_BUMP_CACHE mirror-clone location (default ~/.cache/jllama-llamacpp-mirror)
25+
#
26+
# Network: needs read access to github.com (git clone/fetch + the release atom feed). No token.
27+
28+
set -euo pipefail
29+
30+
THRESHOLD_KB="${LLAMA_BUMP_MAX_DIFF_KB:-100}"
31+
THRESHOLD=$((THRESHOLD_KB * 1024))
32+
EXCLUDE_WEBUI="${LLAMA_BUMP_EXCLUDE_WEBUI:-0}"
33+
REPO="ggml-org/llama.cpp"
34+
GIT_URL="https://github.com/${REPO}.git"
35+
CACHE="${LLAMA_BUMP_CACHE:-$HOME/.cache/jllama-llamacpp-mirror}"
36+
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
37+
CMAKELISTS="$ROOT/llama/CMakeLists.txt"
38+
39+
# --- current pinned tag number, e.g. "GIT_TAG b9866" -> 9866 -----------------------------------
40+
cur="$(grep -oE 'GIT_TAG[[:space:]]+b[0-9]+' "$CMAKELISTS" | grep -oE '[0-9]+' | head -1 || true)"
41+
[ -n "$cur" ] || { echo "ERROR: could not read 'GIT_TAG b<nnnn>' from $CMAKELISTS" >&2; exit 1; }
42+
43+
# --- cached blobless mirror of llama.cpp (clone once, then fetch tags) --------------------------
44+
if [ -d "$CACHE/.git" ]; then
45+
git -C "$CACHE" fetch --quiet --tags --prune origin || true
46+
else
47+
echo "cloning ${REPO} (blobless) into $CACHE (one-time) ..." >&2
48+
git clone --filter=blob:none --no-checkout --quiet "$GIT_URL" "$CACHE"
49+
fi
50+
51+
# --- target: explicit "$1" (b<nnnn>) or the latest RELEASE from the atom feed -------------------
52+
if [ "${1:-}" != "" ]; then
53+
target="$(printf '%s' "$1" | grep -oE '[0-9]+' | head -1)"
54+
[ -n "$target" ] || { echo "ERROR: '$1' is not a b<nnnn> tag" >&2; exit 1; }
55+
else
56+
feed="$(curl -sSL --fail --retry 4 --retry-delay 2 "https://github.com/${REPO}/releases.atom" 2>/dev/null || true)"
57+
[ -n "$feed" ] || { echo "ERROR: cannot fetch the releases feed (network/rate limit). Read the topmost release at https://github.com/${REPO}/releases and pass it: $0 b<nnnn>" >&2; exit 2; }
58+
target="$(printf '%s' "$feed" | grep -oE 'releases/tag/b[0-9]+' | grep -oE '[0-9]+' | sort -un | tail -1)"
59+
[ -n "$target" ] || { echo "ERROR: parsed no release tags from the feed." >&2; exit 3; }
60+
fi
61+
62+
git -C "$CACHE" rev-parse -q --verify "b${cur}^{commit}" >/dev/null 2>&1 || { echo "ERROR: b$cur is not a tag in the mirror" >&2; exit 3; }
63+
git -C "$CACHE" rev-parse -q --verify "b${target}^{commit}" >/dev/null 2>&1 || { echo "ERROR: b$target is not a tag in the mirror" >&2; exit 3; }
64+
65+
# diff byte size between two tag numbers, honoring the WebUI-exclusion toggle
66+
diffsize() {
67+
if [ "$EXCLUDE_WEBUI" = "1" ]; then
68+
git -C "$CACHE" diff "b$1" "b$2" -- . ':(exclude)tools/ui' 2>/dev/null | wc -c
69+
else
70+
git -C "$CACHE" diff "b$1" "b$2" 2>/dev/null | wc -c
71+
fi
72+
}
73+
74+
scope="full diff"
75+
[ "$EXCLUDE_WEBUI" = "1" ] && scope="diff excluding tools/ui"
76+
echo "current pin : b$cur"
77+
echo "latest release : b$target"
78+
echo "threshold : ${THRESHOLD_KB} KiB per step (${scope})"
79+
80+
if [ "$cur" -ge "$target" ]; then
81+
echo "=> up to date — no bump needed."
82+
exit 0
83+
fi
84+
85+
# --- choose next step: TARGET if it fits, else the largest intermediate tag under the threshold -
86+
if [ "$(diffsize "$cur" "$target")" -lt "$THRESHOLD" ]; then
87+
next="$target"
88+
else
89+
# existing b-tags strictly after cur, up to and including target, ascending
90+
# shellcheck disable=SC2207
91+
cands=($(git -C "$CACHE" tag -l 'b*' | grep -oE 'b[0-9]+' | grep -oE '[0-9]+' | sort -un \
92+
| awk -v c="$cur" -v t="$target" '$1 > c && $1 <= t'))
93+
# binary search for the largest candidate whose diff from cur is under the threshold
94+
# (diff size grows monotonically enough with the tag number for this to be a safe heuristic)
95+
lo=0; hi=$(( ${#cands[@]} - 1 )); best=""
96+
while [ "$lo" -le "$hi" ]; do
97+
mid=$(( (lo + hi) / 2 )); T="${cands[$mid]}"
98+
if [ "$(diffsize "$cur" "$T")" -lt "$THRESHOLD" ]; then best="$T"; lo=$(( mid + 1 )); else hi=$(( mid - 1 )); fi
99+
done
100+
if [ -n "$best" ]; then
101+
next="$best"
102+
else
103+
next="${cands[0]}"
104+
echo "NOTE: even b$cur..b$next exceeds ${THRESHOLD_KB} KiB — a single-commit step this large is unavoidable." >&2
105+
fi
106+
fi
107+
108+
full=$(git -C "$CACHE" diff "b$cur" "b$next" | wc -c)
109+
noui=$(git -C "$CACHE" diff "b$cur" "b$next" -- . ':(exclude)tools/ui' | wc -c)
110+
commits=$(git -C "$CACHE" rev-list --count "b$cur".."b$next")
111+
echo
112+
echo "next step : b$cur -> b$next"
113+
echo " diff size : $((full / 1024)) KiB full / $((noui / 1024)) KiB excluding tools/ui (auto-followed WebUI)"
114+
echo " commits : $commits"
115+
if [ "$next" -eq "$target" ]; then
116+
echo " progress : reaches the latest release — final chunk"
117+
else
118+
echo " progress : intermediate chunk — re-run this script after the bump for the next one"
119+
fi
120+
echo " review diff : https://github.com/${REPO}/compare/b$cur...b$next"
121+
echo " raw .patch : https://github.com/${REPO}/compare/b$cur...b$next.patch"
122+
echo
123+
echo "Apply this bump per docs/upgrade/llama-cpp-version-bump.md (b$cur -> b$next)."

CLAUDE.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -536,6 +536,13 @@ re-verify the generator the same way you re-verify `patches/`.
536536

537537
## Upgrading/Downgrading llama.cpp Version
538538

539+
**Runbook (documentation root):** [`docs/upgrade/llama-cpp-version-bump.md`](docs/upgrade/llama-cpp-version-bump.md)
540+
covers the full bump process end-to-end — picking the target (topmost GitHub release, via the atom
541+
feed), **chunking by `git diff` byte-size** (bump straight to the target when the diff is < 100 KiB,
542+
else step through the largest intermediate tag still under the threshold), the
543+
`.github/scripts/llama-next-version.sh` helper that computes the next reviewable step, and the
544+
edit/verify/commit loop below. Use it for any non-trivial bump; the steps here are the mechanical core.
545+
539546
To change the llama.cpp version, update the following **three** files (and re-verify `patches/`):
540547

541548
1. **llama/CMakeLists.txt** — the `GIT_TAG` line for llama.cpp: `GIT_TAG b8831`
Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
# llama.cpp version-bump runbook
2+
3+
This is the **documentation root** for bumping the pinned llama.cpp version. It links the
4+
mechanical edit steps in [`../../CLAUDE.md`](../../CLAUDE.md#upgradingdowngrading-llamacpp-version)
5+
together with a repeatable **target-selection + chunking** strategy so a bump never lands an
6+
unreviewably large diff in one step.
7+
8+
The current pin lives in `llama/CMakeLists.txt` as `GIT_TAG b<nnnn>`. llama.cpp tags **every**
9+
master commit as `b<nnnn>`, but only a subset get GitHub *Releases*.
10+
11+
---
12+
13+
## TL;DR
14+
15+
```bash
16+
# From the repo root. Prints the next reviewable step (b<cur> -> b<next>) and its compare/.patch URLs.
17+
.github/scripts/llama-next-version.sh # target = latest RELEASE (atom feed)
18+
.github/scripts/llama-next-version.sh b9900 # target = an explicit tag
19+
```
20+
21+
Then apply the printed `b<cur> -> b<next>` step per [§ Applying a bump](#applying-a-bump) and re-run
22+
the script to walk the next chunk, until it prints **"reaches the latest release — final chunk"**.
23+
24+
---
25+
26+
## 1. Pick the target (topmost release)
27+
28+
The **target candidate is the topmost release** on
29+
<https://github.com/ggml-org/llama.cpp/releases>. Read it from the release **atom feed**, which is
30+
reachable from restricted sandboxes where the ggml-org REST API is blocked:
31+
32+
```
33+
https://github.com/ggml-org/llama.cpp/releases.atom
34+
```
35+
36+
The first `<entry>`'s `releases/tag/b<nnnn>` is the latest release. `llama-next-version.sh` does this
37+
for you; if the feed is rate-limited (repeated unauthenticated fetches can return empty), open the
38+
releases page in a browser and pass the tag explicitly: `llama-next-version.sh b<nnnn>`.
39+
40+
> **Why releases, not just the newest `b<nnnn>` tag:** releases are the versions upstream deems
41+
> shippable; an arbitrary master commit tag may be mid-refactor. Intermediate **chunk** steps
42+
> (below) are allowed to land on non-release tags — they are transient waypoints, not the target.
43+
44+
## 2. Chunk by diff **byte-size**, not commit count
45+
46+
The step size is governed by the **size of `git diff` between the pinned tag and the target**, not by
47+
how many commits separate them:
48+
49+
- If `git diff b<cur> b<target>` is **< 100 KiB**, bump straight to the target in one step.
50+
- If it is **≥ 100 KiB**, pick an **intermediate** `b<nnnn>` tag whose diff from the current pin is the
51+
largest still **under** the threshold, bump to that first, then repeat. Each step stays a small,
52+
reviewable patch.
53+
54+
The threshold is a knob (`LLAMA_BUMP_MAX_DIFF_KB`, default `100`). This is a heuristic: diff size grows
55+
monotonically enough with the tag number that the helper binary-searches the intermediate tags safely.
56+
57+
> **`tools/ui` (the WebUI) dominates the full diff** and is *auto-followed* — CI rebuilds the matching
58+
> Svelte UI from the pinned `GIT_TAG`, so it needs no per-bump source review. To size the diff on the
59+
> code you actually review, set `LLAMA_BUMP_EXCLUDE_WEBUI=1` (the helper prints both figures regardless).
60+
61+
### The helper: `.github/scripts/llama-next-version.sh`
62+
63+
It only **reads** — a cached blobless mirror clone of llama.cpp plus `llama/CMakeLists.txt`; it never
64+
edits the repo. It prints the chosen `b<cur> -> b<next>` step, its full and WebUI-excluded diff size,
65+
the commit count, and the `compare` / `.patch` URLs. Environment:
66+
67+
| Var | Default | Meaning |
68+
|---|---|---|
69+
| `LLAMA_BUMP_MAX_DIFF_KB` | `100` | Per-step diff-size threshold, in KiB. |
70+
| `LLAMA_BUMP_EXCLUDE_WEBUI` | `0` | `1` = size the diff **excluding** `tools/ui`. |
71+
| `LLAMA_BUMP_CACHE` | `~/.cache/jllama-llamacpp-mirror` | Mirror-clone location (cloned once, then fetched). |
72+
73+
Worked example — pin `b9859`, latest release `b9866` (full diff 133 KiB ≥ 100 KiB, so it chunks):
74+
75+
```
76+
$ .github/scripts/llama-next-version.sh b9866
77+
current pin : b9859
78+
latest release : b9866
79+
threshold : 100 KiB per step (full diff)
80+
81+
next step : b9859 -> b9862
82+
diff size : 45 KiB full / ... KiB excluding tools/ui (auto-followed WebUI)
83+
commits : 3
84+
progress : intermediate chunk — re-run this script after the bump for the next one
85+
review diff : https://github.com/ggml-org/llama.cpp/compare/b9859...b9862
86+
raw .patch : https://github.com/ggml-org/llama.cpp/compare/b9859...b9862.patch
87+
```
88+
89+
## 3. Review the chunk's diff
90+
91+
Fetch the printed `compare/...patch` URL (or open the `compare` page). Walk it against the
92+
**priority-ordered API-compatibility review list** in
93+
[`../../CLAUDE.md`](../../CLAUDE.md#files-to-check-for-api-compatibility) — the 8 header rows that have
94+
historically caused breaks (`common.h`, `chat.h`, `speculative.h`, `mtmd.h`, `llama-cpp.h`, `arg.h`,
95+
`llama.h`, `download.h`), plus the project `CMakeLists.txt` for renamed link targets. Note any new
96+
API surface worth wiring through the Java layer (e.g. a new completion param or model-metadata getter).
97+
98+
---
99+
100+
## Applying a bump
101+
102+
Once you have the `b<cur> -> b<next>` step, apply it exactly as
103+
[`CLAUDE.md § Upgrading/Downgrading`](../../CLAUDE.md#upgradingdowngrading-llamacpp-version) describes.
104+
Concretely:
105+
106+
1. **Edit the pin — three files:**
107+
- `llama/CMakeLists.txt` — the `GIT_TAG b<cur>` line **and** the `-DLLAMA_TAG=b<cur>` used by the
108+
WebUI/TTS extraction (both must move together).
109+
- `README.md` — the llama.cpp badge and link (version appears twice).
110+
- `CLAUDE.md` — the "Current llama.cpp pinned version" line (and any build-example `b<nnnn>`).
111+
2. **Re-verify `patches/`** — a clean configure re-runs the fail-loud `PATCH_COMMAND`, so every patch
112+
`0001``0006` must still apply. Use a **fresh** build dir (a stale one re-applies over an
113+
already-patched tree and reports a false "does not apply"):
114+
```bash
115+
cd llama && mvn -q compile # generates the OSInfo class CMake's OS-detection needs
116+
rm -rf build && cmake -B build # fail-loud: aborts here if any patch no longer applies
117+
```
118+
If a patch no longer applies, refresh its diff against the new source and recommit it.
119+
3. **Append the history rows** — add a pair of rows to
120+
[`../history/llama-cpp-breaking-changes.md`](../history/llama-cpp-breaking-changes.md) covering the
121+
`b<cur> -> b<next>` range (what broke / what was new; "no source change" is a valid row).
122+
4. **Commit + push** on the working branch (do not open a new PR if one already tracks the branch):
123+
```bash
124+
git add llama/CMakeLists.txt README.md CLAUDE.md docs/history/llama-cpp-breaking-changes.md
125+
git commit -m "Upgrade llama.cpp from b<cur> to b<next>"
126+
git push -u origin <your-branch>
127+
```
128+
5. **Re-run the helper** for the next chunk. Repeat until it reports the **final chunk** (target
129+
reached).
130+
131+
CI builds every native classifier from the new pin; the full model-backed Java + C++ suites gate the
132+
result. A build failure at the configure step almost always means a patch needs refreshing (step 2).

0 commit comments

Comments
 (0)