CHANGELOG.md
Rama main · réplica de lectura del repositorio original.
# Changelog
Notable changes to the scripts. Dates are the commit dates on `main`.
The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
## [Unreleased]
## [1.2.0] — 2026-10-15
### Added
- **`kiln pi`** (`./kiln.sh pi`) lists the local models in
[pi](https://pi.dev), the terminal coding agent. It adds a `kiln`
provider to pi's `models.json` and takes the same `--print`,
`--remove` and `--url` as `kiln opencode`. pi's built-in llama.cpp
provider needs llama-server's router mode, so it lists nothing for a
server `kiln start` runs. The key is read from `api_key.txt` by a
command rather than copied. `p` in `kiln tui` runs it.
- **`kiln cursor`** (`./kiln.sh cursor`) sets Cursor up in one step. It
points Cursor's OpenAI base URL at the tunnel `kiln start` opened,
turns on the API-key override and lists the downloaded models. After
that `kiln start` points Cursor at each new tunnel and `kiln stop`
turns the override off. Changes wait for Cursor to close, which would
otherwise write its own copy back. From WSL it sets up the Windows
Cursor. `--off` gives back Cursor's own settings. The key is pasted
once: Cursor encrypts it, so kiln puts it on the clipboard instead.
`C` in `kiln tui` runs it. `scripts/unix/cursor_tunnel.sh` now goes
through it too.
- **Gemma 4, opt-in.** `kiln get gemma-26b` and `kiln start gemma-26b`
serve Google's Gemma 4. There are four variants: `gemma-31b`,
`gemma-26b` (26B-A4B MoE), `gemma-12b` and `gemma-e4b`. Each one has
its own MTP draft head and vision projector, and the same arithmetic
as Qwen sizes the download and the context to your card. kiln never
picks Gemma on its own. `kiln hardware`, a bare `kiln get` and a bare
`kiln start` all stay on Qwen3.8, unless Gemma is the only thing
downloaded. If a Gemma model is too big for the card, kiln points you
at a smaller Gemma model. It never suggests E4B, which is weak at
tool calls. Gemma needs llama.cpp b11059 or newer, and `kiln start`
refuses an older build before it stops the running server.
`hardware.py --table gemma` prints the Gemma context table. The sizing
was checked by loading the 31B, 12B and E4B on a 5090. That showed
Gemma's attention scratch and its MTP head both cost VRAM per token.
Counting that keeps the 31B on a 32 GB card from running out of
memory. The benchmark measures and picks within the model line you
run, as it already did for abliterated builds, and it never picks
E4B while anything else was measured.
- **`kiln quality` on Windows**, which only `./kiln.sh` had.
- **`kiln key set` on macOS and Linux.** It used to print the old key
and change nothing. Only Windows had it.
### Changed
- **Each model family carries its own launch settings.** The registry in
`scripts/hardware.py` now holds each family's MTP head and projector,
sampling, draft length, reasoning flag and minimum llama.cpp build.
The start scripts read these instead of assuming Qwen's. Qwen launches
with exactly the flags it had before. The four Unix start scripts now
share one copy of this logic in `lib_select.sh`.
- **Bare `kiln` opens the TUI.** `kiln` with no arguments (`./kiln.sh`
on macOS and Linux) starts the full-screen app. `kiln status` still
prints the status board. If the TUI cannot start — no Python, or the
output is not a terminal — kiln says why and prints the board instead
of hanging. Unix setup links `kiln` to `~/.local/bin/kiln` without
sudo. That link resolves back to the checkout, so the command works
from any directory.
- **`kiln` on PATH on Windows too.** `kiln setup` writes a `kiln.cmd`
shim into `%USERPROFILE%\.local\bin` and adds that folder to the user
PATH, so `kiln` runs from any folder in a new terminal. No admin
rights are needed. The rest of the user PATH is kept as it was:
`%USERPROFILE%`-style entries stay unexpanded. `kiln path` does only
this step on every platform, and `kiln path --remove` undoes it. It
never replaces or deletes a `kiln` that some other tool put there.
On macOS and Linux, setup now says how to put `~/.local/bin` on PATH
when it is missing, which it always is on macOS.
### Fixed
- **kiln stops only its own llama-server.** `kiln stop`, `kiln start`,
the benchmark and the quality run stopped every llama-server on the
machine (`pkill -x llama-server`, `taskkill /IM llama-server.exe`), and
the status board counted any of them as kiln's. kiln's server is now
the one on kiln's port, the same rule as the tunnel, through
`scripts/unix/lib_server.sh` and `scripts/windows/kiln_server.ps1`.
Stopping waits for it to exit, because the next launch needs its
memory.
- **The macOS and Linux start scripts no longer quit on a slow tunnel.**
They read the tunnel's address once, after 12 seconds, and exited
when it was not there yet, before printing the API key, leaving the
server and tunnel running. They now wait up to a minute and carry on
either way. Ctrl+C while the model loads now stops the server too;
until the load finished, it kept the GPU.
- **MTP is no longer reported missing on macOS.** The check for it read
llama-server's help through `grep -q` under `pipefail`, which fails
whenever grep stops reading first, and macOS's small pipe buffer made
that likely.
- **Failing commands fail on Windows.** `kiln get VARIANT` and
`kiln start VARIANT` returned success whatever happened, so `kiln tui`
showed a failed download as done. Unknown commands return an error.
- **`kiln key set` on Windows keeps the key as typed.** It dropped or
mangled `! ^ ' % & >`, and still said "key set". Quote the key:
`kiln key set "YOUR-KEY"`.
- **The API key stays where it belongs.** The key is now sent to a
server only after it answers as llama-server; before, `kiln tui`,
`kiln opencode` and `kiln pi` sent it to whatever held port 8080, and
to the WSL gateway. It no longer lands in `kiln-benchmark.json` when a
setup fails, and the job logs `kiln tui` keeps are deleted when it
quits. Keys made on macOS and Linux are 24 bytes, as on Windows and as
documented, not 16. The file is created readable only by you, and
locked down again on every start.
- **A small card gets a plan for the model you name.** `kiln get base`
on a 16 GB card said nothing fits, and Windows then offered the
31.5 GB download first. It now offers the largest quant that loads,
says when that is a low-bit one, and defaults to the smallest when
nothing fits comfortably. Intel Macs are sized for the CPU, not as
Apple Silicon.
- **Windows paths and locales.** The free-space check reads the drive
kiln is on, not always `C:`, and works where the decimal mark is a
comma. A `'` in the folder path works. A `!`, `%`, `[` or `]` is
refused with a message rather than breaking in odd places. The status
board shows the tunnel URL again.
- **`kiln tui` copes.** A Python environment broken by an upgraded or
removed Python is rebuilt instead of failing on every run. Closing
the window cancels a download or setup still running, as quitting
does; a model that is serving keeps serving. A benchmark whose results
file cannot be written, say because OneDrive has it locked, keeps the
results and says so instead of closing the app.
- **Setup keeps a working llama.cpp.** Linux setup in a Windows
checkout used from WSL deleted the Windows build; it now stops and
says how to go on. A new build replaces the old one only once it is
in place, and a failing `nvidia-smi` is reported instead of ending
setup without a word.
- **Linux and WSL setup give an NVIDIA card the CUDA build.** Newer
`nvidia-smi` prints `CUDA UMD Version: 13.4` where it printed `CUDA
Version: 13.4`, so setup read no CUDA version and fell back to Vulkan
on every NVIDIA card. `./kiln.sh setup` on Ubuntu and WSL also asked
for Vulkan outright. Under WSL that build sees no GPU and runs the
model on the CPU, while CUDA passes straight through: on a 5090 the
WSL CUDA build matched the Windows one. Setup now takes the CUDA
build when there is an NVIDIA driver, and Vulkan, then CPU, otherwise.
An existing `llama-bin/` is kept, so move it aside and re-run setup
to switch.
- **Fedora setup no longer downloads a Vulkan build from `/releases/latest`.**
That URL is the empty v0.x line, so `./kiln.sh setup` on Fedora found
nothing. An NVIDIA card now gets the Ubuntu CUDA build whose toolkit
the driver can load (12.8 unless the driver reports 13.4 or newer),
plus the separate cudart tarball. Fedora does not ship those libraries,
and the server looks for them beside the binary. No NVIDIA card still
falls through to Vulkan, then CPU. The WSL/Linux installer keeps
Vulkan and uses the same bNNNN tag lookup.
- **Linux and WSL serve on port 8080 again.** `start_linux.sh` had
moved to 8081, while `kiln opencode`, the Cursor tunnel and the docs
all use 8080, so on Linux and WSL they pointed at nothing. The Slurm
job keeps 8081.
- **Config backups keep the file's permissions.** The `.kiln.bak` that
`kiln opencode` and `kiln pi` make, and the temporary file each write
goes through, start with the mode of the file they copy, so a config
readable only by you never sits in a readable copy.
- **`kiln stop` stops only kiln's tunnel.** It, the macOS and Fedora
start scripts and the Slurm job ran `pkill -x cloudflared`, and on
Windows `kiln stop` and `kiln start` ran `taskkill /IM cloudflared.exe`.
That stopped every cloudflared on the machine: a named tunnel, a
tunnel run as a Windows service, or T3 Code's remote access. kiln now
stops only the quick tunnel to its own port, matched by its command
line, through `scripts/unix/lib_tunnel.sh` and
`scripts/windows/kiln_tunnel.ps1`. `kiln tui` uses the same rule
before it shows a tunnel URL, so another program's tunnel no longer
makes an old URL look live.
- **`./kiln.sh get` on Fedora and Debian.** A plain `pip install` into
the system Python is refused there. The download uses `huggingface_hub`
when it is already installed, and otherwise installs it for the user.
- **`kiln update` and `kiln setup` on Windows.** llama.cpp moved its
Windows CUDA builds from 13.3 to 13.4 at b11000. Both scripts were
pinned to 13.3, so `kiln update` failed with a 404. `kiln setup` also
read `/releases/latest`, which has no Windows CUDA build at all. Both
now take the newest bNNNN release. From it they take the newest CUDA
build that has a cudart zip of the same version, and they download
that zip too. `kiln setup` also failed to parse, with
`... was unexpected at this time`, in two places. One was its download
progress line. The other was the cloudflared block, which breaks on
the `(x86)` in the install path even when cloudflared is already
installed.
- **The Windows status board shows the llama.cpp build again.** Newer
builds print `version: 0.6.0-dev (build 11624, ...)`, and the board
showed `build 0.6.0-dev`.
- **macOS setup downloads llama.cpp again.** `install_mac.sh` read
`/releases/latest`, which is now the v0.x line with no binaries, and
wanted a `.zip` where the Mac builds are now `.tar.gz`. It found
nothing and exited without a message. It now uses the same bNNNN
lookup as Linux and Fedora. Apple Silicon gets the Metal build, also
from a shell running under Rosetta. Intel gets the x64 build, which
llama.cpp compiles without Metal, so it runs on the CPU. Homebrew
installs cloudflared from homebrew-core, where Cloudflare's tap moved
it, and the direct download creates `/usr/local/bin` when it is
missing. The README now asks for macOS 13.3, the oldest release those
builds load on.
- **`kiln start` on macOS with the 9B or 4B.** macOS runs the start
script with its stock bash 3.2, which treats an empty array as unset
under `set -u`. A model with no MTP head and no projector left the
extra flags empty, and the launch died with `EXTRA[@]: unbound
variable`. The sampling flags now always fill that list, and
`start_mac.sh` expands both of its arrays in a form bash 3.2 accepts
when one is empty.
## [1.1.0] — 2026-10-01
### Added
- **`kiln tui`** (`./kiln.sh tui`) is the status board and the everyday
commands as a full-screen terminal app. You can start, switch and stop
models, download one, copy the URL and API key Cursor needs, set up
OpenCode, and update kiln, with each command's output shown as it
runs. It runs the same kiln commands rather than reimplementing them.
The first run offers to install Textual into `.kiln/`, a folder inside
the checkout. It needs Python 3.9+. A model started from it keeps
serving after you quit. It is also item 9 on the Windows menu.
- **A benchmark in `kiln tui`** (press `b`, or `scripts/bench.py`)
starts each downloaded model with and without the MTP head through
`kiln start`, with the tunnel off. It times prefill, generation, MTP
acceptance and, on a thorough run, generation 32K tokens deep. Then it
recommends the fastest setup that keeps 96K of context, and starts
the one you pick. Setups whose runs overlap are called a tie, and the
abliterated build is only measured and picked if it is the one you
run. `p` copies the results as a markdown table for a hardware report.
Unlike `kiln bench`, it measures what MTP is worth.
- **`KILN_NO_TUNNEL=1`** makes every start script skip the Cloudflare
tunnel. `l` in `kiln tui` sets it for the next start.
- **`./kiln.sh start --no-mtp`** trades the MTP draft head for a larger
context window on macOS and Linux, as `kiln start --no-mtp` already
did on Windows.
- **A warning when another program holds the server's port.** On
Windows a WSL or Docker container publishing 8080 takes
`127.0.0.1:8080` ahead of llama-server, so localhost and the tunnel
reach that program instead. `kiln tui` says so and finds the server by
the machine's name.
- **`.github/scripts/test_control.py`, `test_bench.py` and
`test_tui.py`** run in CI. They check that only the fixed command list
reaches a command line, that a benchmark never opens a tunnel and
always frees the GPU, and that the app's keys do what they say.
- **`kiln self-update`** (`./kiln.sh self-update`) updates kiln itself
from GitHub. By default it moves to the newest `vX.Y.Z` release.
`--main` follows every change on `main` instead and is remembered.
`--check` only reports. The update is a git fast-forward, so `models/`,
`llama-bin/` and `api_key.txt` are never touched. It refuses, changing
nothing, when there are local edits, local commits or another branch
checked out. It is also item 8 on the Windows menu.
- **A `kiln` row on the status board** shows the version you are on, and
the newest release when there is a newer one. It asks GitHub at most
once a day with `git ls-remote`. `KILN_NO_UPDATE_CHECK=1` turns that
off.
- **`.github/scripts/test_selfupdate.py`** runs in CI against throwaway
repositories and checks that every refusal leaves HEAD where it was.
- **`kiln opencode`** (`./kiln.sh opencode`) — lists the downloaded
Qwen builds in OpenCode as `kiln/<alias>`, each with the context window
`kiln start` would open for it. Works on Windows, WSL and Linux, and
works out the WSL-to-Windows address itself. Merges into an existing
config rather than replacing it, and references `api_key.txt` instead
of copying the key. `--remove` undoes it. Refuses, leaving the file
untouched, when the config cannot be parsed or the key file is missing.
- **A Python job in CI** that byte-compiles every script and runs
`.github/scripts/test_opencode.py`.
- **`kiln hardware`** — reads the GPU and prints the model, quant, MTP
head, vision projector and context window that fit it, which is exactly
what `kiln get` will download. Available as `kiln hardware` and
`./kiln.sh hardware`.
- **`scripts/hardware.py`** — the model registry and the sizing
arithmetic, shared by every script on both platforms. Holds the repos,
the quant ladders with exact byte counts, and the per-family KV-cache
model. Also generates the context tables in `README.md`, so the docs
cannot drift from the code.
- **Two smaller model families**, for cards a 27B has no business on:
`9b` and `4b`, Empero's Apache-2.0 distillations of Qwen3.8-2.4T-A95B.
Both are third-party rather than Qwen releases, and are labelled as such
everywhere they are offered. Both are text-only — no MTP head, no vision.
- **Six more 27B quants.** The ladder is now the eleven `UD-*` names
present in both the unsloth and huihui-ai repos, rather than five.
- **The q4_0 MTP head and the q8_0 vision projector.** 1.4 GB and 0.3 GB
smaller than the ones used before, and the reason a 24 GB card can now
keep speculative decoding.
### Changed
- **The default model and context window are chosen from your GPU, not
assumed.** `kiln get` used to default to `UD-Q5_K_XL` on every machine —
right on the 32 GB card this repo was tuned on, a guaranteed OOM on a
12 GB one. Downloads, launches and menus now default to what fits, and
say what they picked. An explicit `QUANT=` or `VARIANT=` still wins.
- **24 GB cards no longer have to choose between MTP and quant quality.**
`UD-IQ4_XS` with the q4_0 head reaches ~104K with speculative decoding
on. The README previously recommended giving up MTP for `UD-Q4_K_XL` at
72K; that advice predated the smaller head.
- **`kiln start` prefers the tier's quant among the files on disk** and
prints a one-line note when a better one exists, but never re-picks
weights behind your back.
- The three Unix start scripts and `slurm-llama.sh` now share
`lib_select.sh` instead of each carrying its own hardcoded quant, MTP
filename and context.
- **The root `kiln.bat` exits on the same line that calls the CLI.** An
update that rewrites the file can no longer leave cmd reading half a
line of the new version.
### Fixed
- The `kiln setup` and `kiln update` lines of the README quick start had
run together onto one line.
- **The documented 131K context on a 32 GB card was never what the code
produced.** The probe computes 114688 with `UD-Q5_K_XL` + the q8_0 head
+ f16 vision; 131072 is what loaded when tried by hand. The comment
claiming the 0.85 safety factor reproduced 131072 was wrong, and every
131K in the README has been corrected to the computed figure.
- **`start_mac.sh` and `start_fedora.sh` exited silently when the vision
projector was absent.** `[ -f "$MMPROJ" ] && EXTRA+=(...)` returns
non-zero under `set -euo pipefail`, killing the script before it printed
anything. Same bug in `slurm-llama.sh`.
- **The Unix scripts could not find Python on Windows shells.** `command
-v python3` resolves to the Microsoft Store alias stub, which exits 0
and prints nothing, so every lookup silently fell back. `lib_python.sh`
now verifies the interpreter answers, and strips the CR that Windows
Python puts on each line — a trailing `
` made `V_MTP` compare unequal
to `1` while still printing as `1`.
- **The status board's "shared files" row** reported "no MTP head" on
machines given the q4_0 head, because it matched the q8_0 filename only.
## [1.0.0] — 2026-09-03
First tagged release. The repo has been usable for months; this marks the
point where the Qwen3.8 path, the API key, and the `kiln` CLI are all in
place across every platform.
### Added
- **`kiln`, a single entry point on every platform.** Prints a status
board of what is installed, downloaded and running, names the one thing
to do next, and offers a menu. Verbs for every step: `status`, `setup`,
`update`, `get`, `start`, `stop`, `key`, `bench`, `clean`. `kiln.bat` on
Windows, `./kiln.sh` on macOS and Linux — the latter detects your
distribution and dispatches to the right platform script.
- **A `scripts/` layout.** The repo root was 36 loose files; it is now the
entry point plus documentation, with `scripts/windows/` and
`scripts/unix/` holding the rest.
- **Shared libraries** — `lib_variants`, `lib_api_key`, `lib_ui` — so the
Windows and shell script families no longer duplicate variant
definitions or key handling.
- **Abliterated build** alongside the stock one, selectable at launch with
`kiln start ablit` or `VARIANT=ablit`. Both builds share one copy of the
MTP head and vision projector, so the second download is weights-only.
- **`scripts/unix/slurm-llama.sh`**, to run the server as a Slurm batch job so the GPU
shows as allocated in `squeue`.
- **`kiln quality`**, scoring each quant against `Q8_0` by
KL-divergence rather than perplexity.
- **`kiln bench`** — quant speed, ubatch sweep, KV precision and
throughput vs. context depth.
- **`kiln clean`**, to reclaim space from superseded GGUFs. Requires
typing `DELETE`.
### Changed
- **Default model is now Qwen3.8-27B**, replacing Qwen3.6-35B-A3B. Better
coding scores, native MTP, and a hybrid-attention stack that makes long
context far cheaper.
- **MTP speculative decoding is wired up by default** via
`--spec-type draft-mtp`, which needs llama.cpp **b9180+**
([PR #22673](https://github.com/ggml-org/llama.cpp/pull/22673)).
- **Context is sized from your actual hardware.** `probe_hardware.ps1`
reads VRAM and the weight files on disk and computes the window that
fits; the shell scripts use llama.cpp's `--fit on`. No card is
hardcoded any more.
- **KV cache precision raised to `q8_0`** from the `q4_0` used in the
Qwen3.6 setup. In a 75%-linear-attention stack, low-bit KV error
accumulates along the sequence instead of being re-anchored each token.
- **`--parallel 1`** rather than llama.cpp's auto default, which splits
the KV cache across slots and hands a single-user Cursor session only
`ctx/N` of its own context window.
### Removed
- **Legacy Windows forwarders** `run.bat`, `start_windows.bat` and
`download_model.bat`. Use `kiln` instead.
- The `qwen` command is now `kiln`. It collided with Alibaba's official
Qwen Code CLI and tied the tool to a single model family.
### Security
- **All platforms now generate an API key** into `api_key.txt` and serve
with `--api-key-file`. The file is locked to the invoking account on
every launch (`chmod 600`; `icacls /inheritance:r` on Windows). See
[SECURITY.md](SECURITY.md).
### Fixed
- A batch of cmd.exe bugs that were latent in shipped scripts: unescaped
parentheses inside `( )` blocks aborting the launcher, `::` comments
inside blocks, `for /f` splitting `nvidia-smi` options on commas,
`timeout /t` spinning when stdin is redirected, and
`if COND set A & set B` running the second `set` unconditionally. All
are written up in [NOTES.md](NOTES.md).
- Line endings pinned in `.gitattributes` — a `.sh` checked out with CRLF
fails on Linux with `\r: command not found`.
## Earlier
- **2026-07-21** — Slurm launch path and a `cloudflared` helper.
- **2026-04-25** — Fedora support (thanks @EmeryJJ).
- **2026-04-24** — Initial local model setup, Windows start scripts, and
Cursor instructions.
[1.2.0]: https://github.com/Lampsdad/kiln-local-llm/releases/tag/v1.2.0
[1.1.0]: https://github.com/Lampsdad/kiln-local-llm/releases/tag/v1.1.0
[1.0.0]: https://github.com/Lampsdad/kiln-local-llm/releases/tag/v1.0.0