tunekeep
Keep a fine-tuned model working after its provider retires the base model.
OpenAI shuts down fine-tuned gpt-4o, gpt-4o-mini, gpt-4.1 and gpt-4.1-mini models on
14 January 2027, and stops new fine-tuning jobs on 6 January 2027. The named replacement,
gpt-6-luna, cannot be fine-tuned. Once a model is gone, so is the only exact record of how it behaved.
tunekeep helps you get out in time:
| Step | Command |
|---|---|
| 1. See every fine-tune you own and its days left | tunekeep inventory |
| 2. Record how each model answers, as a golden eval set | tunekeep record |
| 3. Check whether gpt-6-luna (or any model) already matches it | tunekeep compare |
| 4. Retrain an open model with LoRA from your own data | tunekeep retrain |
| 5. One HTML report: quality, speed and tokens side by side | tunekeep report |
Do the recording first. Everything else can happen later; recording cannot happen after the shutdown.
Install
uv tool install tunekeep # or: pipx install tunekeep
Python 3.10+. No dependencies: tunekeep uses only the Python standard library. (The retraining kit it writes has its own pinned requirements, installed only where you run it.)
1. Inventory
export OPENAI_API_KEY=sk-... # a key for the org/project that owns the fine-tunes
tunekeep inventory
Fine-tuned models: 1 (plus 1 checkpoint)
New fine-tuning jobs stop on 2027-01-06 (60 days).
MODEL SHUTS DOWN DAYS LEFT SOURCE
ft:gpt-4o-mini-2024-07-18:acme::AbC123 2027-01-14 68 api
Files: 1 saved, 1 training/validation file the API would not return.
Keep your own copy of these; tunekeep retrains only from your original data:
- file-train-0 train.jsonl (job ftjob-000)
Next: record how each model behaves while it still answers, e.g.
tunekeep record --model ft:gpt-4o-mini-2024-07-18:acme::AbC123 --prompts prompts.jsonl
tunekeep-out/inventory.json holds the full detail: jobs, hyperparameters, checkpoints and their
metrics, and every file. Result files (training metrics) are downloaded. Files you uploaded for
training are not: OpenAI does not return them through the API, so keep your own copy.
2. Record
tunekeep record --model ft:gpt-4o-mini-2024-07-18:acme::AbC123 --prompts prompts.jsonl
prompts.jsonlcan be your training file as-is. The final assistant message on each line is removed before sending and kept as the reference answer. DPO lines (input.messages) work too.- Real production prompts make the best golden set. Use a few hundred, covering your real traffic.
- Answers are recorded at
temperature 0by default. Use--seedfor more repeatable runs. - Safe to stop and re-run: prompts already recorded are skipped, failed ones are retried.
--dry-runcounts prompts and estimated input tokens without sending anything.
3. Compare
tunekeep compare --golden tunekeep-out/golden-ft_gpt-4o-mini-2024-07-18_acme_AbC123.jsonl \
--candidate gpt-6-luna --examples train.jsonl --shots 5
Each recorded prompt goes to the candidate, optionally with a few examples from your own training file, and the answer is scored against the recorded one:
- Tool calls: matched by function name, arguments compared field by field.
- JSON answers: the share of leaf fields with the same value; invalid JSON scores 0.
- Text: 100% when equal after normalising case and spacing, otherwise word overlap (F1). Overlap is a rough signal for free text, so the report shows the biggest differences side by side.
GPT-6 Luna reasons by default, and in Chat Completions it accepts temperature and function tools
only with reasoning_effort: "none". tunekeep sends none by default (--reasoning-effort auto),
which is also closest to how a fine-tuned gpt-4o-mini answered. Try --reasoning-effort low to see
whether reasoning helps; tunekeep then drops temperature, and refuses before sending anything if your
prompts use tools.
Any OpenAI-compatible endpoint works as a candidate: --candidate-base-url http://127.0.0.1:8080/v1
for llama-server, vLLM or Ollama (no key needed on localhost; --candidate-key-env for others).
4. Retrain
tunekeep retrain --data train.jsonl # default base: Qwen/Qwen3-1.7B, pinned revision
cd tunekeep-out/retrain && modal run modal_app.py
retrain converts your OpenAI training file (chat format, tools, legacy functions, per-message
weight) and writes a small kit: your data, a config, a training script and a Modal
app. It uploads nothing itself. The kit:
- trains a LoRA adapter with loss only on assistant messages (
"weight": 0turns are skipped, as on OpenAI); - reuses your original job's epoch count when
tunekeep-out/inventory.jsonhas it; - pins every package by hash, the base model by revision, and llama.cpp by commit;
- stops after a time limit (default 2 hours), which caps the cost of a run;
- exports merged weights and a q8_0 GGUF for llama-server or Ollama.
Use --check to only validate and summarise the data. See the kit's own README for running it
elsewhere and serving the result. Not yet supported: DPO, images and audio in training data.
5. Report
tunekeep report # reads tunekeep-out/, writes tunekeep-out/report.html
One self-contained HTML file with deadlines, every candidate's scores, latency and token use, and the lowest-scoring answers side by side. It loads nothing from the network and runs no scripts, and every value from your data is escaped.
What tunekeep will not do
It never trains on recorded outputs. OpenAI's Services Agreement (section 3.3(e)) restricts using Output to develop competing models. Recorded answers are used only to evaluate a replacement. Retraining uses only your original training data. If that data was itself generated by an OpenAI model, it counts as Output too. Check with your own counsel; this is not legal advice.
Privacy
- tunekeep talks only to the API base URLs you give it. No telemetry, no other network calls.
- Outputs can contain production prompts, so the output folder is created
0700and files0600. - API keys are read from the environment and are never written to disk or printed. A candidate
endpoint never receives your OpenAI key unless you name that variable with
--candidate-key-env.
Other providers
--base-url/OPENAI_BASE_URLfor OpenAI-compatible gateways.--azure --base-url https://<resource>.openai.azure.com/openai/v1withAZURE_OPENAI_API_KEY(experimental). Azure retires fine-tuned gpt-4o and gpt-4o-mini deployments on 1 October 2027, and the gpt-4.1 family on 14 October 2027.
Development
python -m unittest discover -s tests -v
The tests run against a fake OpenAI server built from the public API reference: pagination, the
shutdown_date field, blocked training-file downloads, rate limits, tool calls and GPT-6 Luna's
parameter rules. The retraining kit is tested end to end on CPU with Qwen3-0.6B.
tools/lock-kit.sh regenerates the kit's hash-locked requirements.
Reports from real accounts are very welcome. Please open an issue with anything that behaves differently.
Sources
- OpenAI deprecations: https://developers.openai.com/api/docs/deprecations
- GPT-6 parameters: https://developers.openai.com/api/docs/guides/latest-model
- Azure retirement schedule: https://learn.microsoft.com/en-us/azure/foundry/openai/concepts/model-retirement-schedule
Licence
Apache-2.0. Built by Rush Labs, an applied AI lab.
Metadata
Release files for tunekeep 0.2.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| tunekeep-0.2.1.tar.gz | 99.4 kB | With provenance | Details for tunekeep-0.2.1.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| tunekeep-0.2.1-py3-none-any.whl | Python 3 | none | any | Details for tunekeep-0.2.1-py3-none-any.whl |
Total release size: 203.5 kB
Release files / tunekeep-0.2.1.tar.gz
| Download URL | tunekeep-0.2.1.tar.gz |
|---|---|
| Size | 99.4 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
60908075b23b13378055f626c2b325fef9ce321c48f41db0bf3a0714bd514f69
|
|
BLAKE2b-256 checksum How to use checksums |
1ad9a4ef4b4fd2a5746d1b61ed6cac201a23c9834966faaf71931b3e1ca166bc
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Nov 8, 2026.
Transparency logRelease files / tunekeep-0.2.1-py3-none-any.whl
| Download URL | tunekeep-0.2.1-py3-none-any.whl |
|---|---|
| Size | 104.1 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
44d59f7ccfdda6814efc0039c39ac15c8a75894d06a1847e78e06e8249edbb2d
|
|
BLAKE2b-256 checksum How to use checksums |
60c6785f7408448d97235faa004e6257fa8007ce13e268a4b423a9f9449221e4
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Nov 8, 2026.
Transparency logSecurity for tunekeep 0.2.1
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
Full provenance
Both files in this release have been uploaded with provenance metadata.
Attestation for tunekeep-0.2.1.tar.gz
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Nov 8, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.