Last Orders (working name)
Find retiring AI model IDs in your code before they break. One command scans your repo for OpenAI (and, as a preview, Anthropic) model IDs that are being shut down. For each one it tells you the shutdown date, the replacement the provider recommends, and the code changes the new model needs.
Heads-up: OpenAI removes GPT-4o, GPT-4o mini, GPT-4.1 and GPT-4.1 mini from the API on 14 January 2027 and recommends
gpt-6-luna. In our tests,gpt-6-lunarejectsmax_tokens, and it rejects tool calls on Chat Completions unlessreasoning_effortis"none". So changing the model name isn't enough. The scan flags both.
The scan is free. You don't need an account, a licence or an API key, and your code never leaves your machine.
Install
pipx install lastorders # or: pip install lastorders
You need Python 3.10 or later.
Scan
lastorders scan . # scan the current repo
lastorders scan path/to/repo --out scan-results
lastorders scan . --offline # no network at all (uses the bundled migration pack)
You get scan.md, a readable report, and scan.json, the same data for tools. They go in lastorders-out/, or wherever --out points. Each finding includes:
- File, line and model ID, from code (Python, JS, TS),
.envfiles, YAML, JSON, TOML and docs - Shutdown date and recommended replacement, from the provider's published deprecations
- Risk level. High means the date is close or has passed, or the new model needs a code change your
code doesn't have yet, such as
max_tokensbecomingmax_completion_tokens,reasoning_effortfor tools andtemperature, or an unsupported endpoint - Fine-tuned models (
ft:...), listed separately. They shut down with their base model and can't be swapped automatically. - Models chosen by environment variable (
os.getenv("OPENAI_MODEL")), so you can check the values you have deployed - SDKs detected: the official
openaiandanthropicclients, LangChain and plain HTTP
Useful flags:
| Flag | What it does |
|---|---|
--fail-on-high |
exit code 2 if anything is high risk (for CI) |
--no-docs |
skip .md / .txt files |
--pack openai |
only use some providers' packs (default: all) |
--offline |
use the bundled pack only; makes no network calls |
--format json |
print the summary as JSON |
--summary-file F / --annotations |
CI outputs (used by the GitHub Action) |
Fix (patch preview)
lastorders fix . # writes lastorders-out/fix.diff + fix-plan.md; changes nothing on disk
lastorders fix . --verify # also checks the patch on a scratch copy (see below)
git apply lastorders-out/fix.diff
fix swaps the retiring model IDs and then makes the code changes the new model needs at each API call:
- Renames
max_tokens, tomax_completion_tokenson Chat Completions ormax_output_tokenson Responses. - Adds
reasoning_effort: "none"where gpt-6-luna needs it: Chat Completions calls with tools, and calls that settemperature,top_porlogprobs. On Responses it addsreasoning.effort. - Flags anything it can't decide safely in
fix-plan.md: legacyfunctionscalls, Assistants and legacy Completions calls (these stay on their current model in the patch), fine-tunes and fine-tuning jobs, LangChain wrappers, calls that pass**kwargsor a spread object, conflicting values, and calls whose model isn't visible in the code (use--assume-model).
Every change comes from the migration pack's rules. Python is edited with
libcst, so your formatting and comments are kept. JS and TS are edited
with a built-in parser. Rules the pack marks inferred are only suggested unless you pass --include-inferred.
Old models reject reasoning_effort. We tested gpt-4o and gpt-4.1 against the live API, and both return
HTTP 400. Any fix that adds it has to ship together with the model switch. When the model comes from an
environment variable, the plan marks the fix "ship with the model switch". --no-model-swap applies only
the changes that are safe on the old model.
--verify applies the patch to a temporary copy of your repo, then:
- checks the changed files still parse;
- re-runs the fixer and checks it changes nothing more;
- replays each fixed call twice: once as it was (old model, old arguments) and once as patched (new model, new arguments).
Without --live, the replay uses simulated responses. With --live and your own OPENAI_API_KEY (licence),
the calls go straight to OpenAI. A control run also sends the unpatched arguments to the new model, to show
each fix was needed. --evals evals/regression.yaml reruns your own suite with the fixed arguments.
GitHub Action
Add .github/workflows/model-scan.yml:
name: Model retirement scan
on:
pull_request:
schedule: [{ cron: "0 7 * * 1" }] # weekly, so new deprecations show up without code changes
permissions:
contents: read
jobs:
scan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: burntandtoast/lastorders@v0 # available once the repo is published
with:
fail-on-high: "true"
The Action posts a summary table to the job page, marks findings inline on the PR and uploads scan.json
as an artifact. Inputs:
| Input | Default | |
|---|---|---|
path |
. |
folder to scan |
fail-on-high |
false |
fail the job on high-risk findings |
include-docs |
true |
scan .md/.txt |
annotations |
true |
inline PR annotations |
packs |
all | e.g. openai,anthropic |
offline |
false |
bundled pack only, no network |
packs-url |
built-in | override the pack URL |
version |
action source | install this version from PyPI instead |
python-version |
3.12 |
|
fix-preview |
false |
also attach the automatic-fix patch + plan (simulated verify, no key) |
artifact-name |
lastorders-scan |
Outputs: total, high and report-dir.
Migration packs: where the data comes from
What the scanner knows lives in migration packs, versioned JSON files with one pack per provider. Each pack
holds the model IDs and aliases, shutdown dates, replacements, call-site patterns, and parameter and endpoint
rules. Every fact links to the provider's documentation and the date we checked it. Rules we confirmed
against the live API are marked live-tested, and anything we assumed is marked inferred.
- OpenAI: full pack
- Anthropic: preview (stub). It covers Claude API retirement dates from Anthropic's deprecations page. Amazon Bedrock and Google Cloud dates are not covered yet.
- Gemini, Azure OpenAI and Bedrock: planned
The tool checks for a newer pack once a day and falls back to the copy bundled with the package.
lastorders packs list shows which version and source you're using. The format is documented in
docs/PACKS.md, with a JSON Schema in migration_kit/pack_data/pack.schema.json.
Privacy and network use
- The scan runs entirely on your machine. Your code and prompts are never uploaded.
- The tool has no telemetry, analytics or tracking. (Our website counts visits anonymously with Cloudflare Web Analytics: no cookies, no ads, no tracking across sites.)
- The tool only ever contacts us to download the latest migration pack (a plain GET of a static JSON file,
with no identifiers) and, for paid features, to check a licence key. That check sends only the key and the
repo name (
github.com/owner/repo), and the signed answer is cached for a week, with a 14-day offline grace period after that. --offline(orLASTORDERS_OFFLINE=1) turns off all network access and uses the bundled pack.- The paid
evalcommand calls the AI provider directly with your own API key. Nothing goes through us.
Paid features
| Free | Licence (per repo) | Done for you | |
|---|---|---|---|
scan, GitHub Action, patch preview (fix / swap write a .diff), fix --verify (simulated replay) |
✓ | ✓ | ✓ |
fix --apply / swap --apply, fix --verify --live, init-evals + eval regression testing, client-ready report |
✓ | ✓ | |
| We do the migration, evals and handoff | ✓ |
One licence covers one GitHub repository, monorepos included. It's bound to the repo the first time
you use it. Buy one with lastorders licence buy (it prints a Stripe Checkout link for this repo), then pass the key
with LASTORDERS_LICENCE (a repository secret in Actions) or --licence. lastorders licence status shows
whether it's verified. Paid commands work --offline from the cached check. Repos without an origin remote
can set LASTORDERS_REPO=github.com/owner/repo. The licence server lives in server/; see
docs/LICENCE-SERVER.md.
init-evals reads the call sites the scan found, including prompts, JSON schemas and tool definitions where
they can be read from the code, and writes a starter evals/regression.yaml. You then edit it into 10 to 20
real examples. eval runs them against the old and new model with your own key.
Limitations
- Detection uses pattern matching. Model names built at runtime or stored in a database won't be found; env-var lookups are listed so you can check them.
- A pack is only as current as its
updateddate. Always check the provider's documentation before acting. - The scan suggests changes; it doesn't decide them for you. Review every patch.
Made by Burnt & Toast Studios. Not affiliated with OpenAI or Anthropic.
Metadata
Release files for lastorders 0.4.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| lastorders-0.4.0.tar.gz | 77.4 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| lastorders-0.4.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 163.2 kB
Release files / lastorders-0.4.0.tar.gz
| Download URL | lastorders-0.4.0.tar.gz |
|---|---|
| Size | 77.4 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
3ce858e5e213e9cc97f8cdca36b0ac6c0a8148df880d3b61647ec5448100c95c
|
|
BLAKE2b-256 checksum How to use checksums |
b557e5059ddcd190b6999b463ffaf23c952fb19defa99a02b705d9b58035a9ed
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
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 Oct 15, 2026.
Transparency logRelease files / lastorders-0.4.0-py3-none-any.whl
| Download URL | lastorders-0.4.0-py3-none-any.whl |
|---|---|
| Size | 85.7 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
684498e1adba280fcad53e08d36a115513cc442beaf273c3e782ac0725679986
|
|
BLAKE2b-256 checksum How to use checksums |
73633ac714b707fa50ced0691c99bcc48391f4d65cee6bc124917b53e64d0cad
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
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 Oct 15, 2026.
Transparency log