AIROM’s other overlays answer questions about risk. This one answers a question about time: what in this stack stops working, when, and what do I move to? A hosted model’s retirement is unlike any other finding AIROM makes. A CVE is a risk you weigh — severity, exploitability, reachability. A retired model is a calendar fact with a hard consequence: on the shutdown date the provider’s API stops answering and the application breaks, patched or not. Nothing about your code changes; the ground moves.
On by default, and it works offline. The catalog ships inside the binary, so unlike the CVE overlay this needs no network and survives --offline. Disable it with --no-eol.
airom fs .
Worst first, then soonest deadline. The footnote is the provenance: which page each claim came from, and when a maintainer last checked it.

States

retired is derived at scan time from the shutdown date rather than stored, so a curated record stays truthful as time passes: a deprecated entry becomes retired on its own date with nobody re-editing it.

The honesty contract

Absence is not health. A model the catalog does not cover gets no record at all. unknown means “nobody has curated this” — never “this is fine”.
  • Every record is transcribed from the provider’s own deprecation page, carrying that URL and the date a maintainer verified it. A catalog file missing either is rejected at load. Nothing is inferred from naming patterns.
  • Matching is exact, case-folded, explicit aliases only. A wrong retirement date is worse than no date.
  • Platforms are scoped. Amazon Bedrock, Google Vertex, and Azure OpenAI publish their own schedules for the same weights, so their provider keys deliberately do not match these records.
  • Migration advice carries the target’s state — providers point a deprecation at whatever was current when they wrote it, then deprecate that too, so the output says gpt-5.1-chat-latest (retired) rather than sending you onto a model that is already gone.
  • Staleness is visible. If the least-recently-verified provider is more than 90 days old, the scan says so rather than quietly serving data that may have moved — naming the lever that actually refreshes this catalog (see below).

How it appears in output

An EOL column (retired / 87d), a Model lifecycle block in the summary panel, and the detail table above with per-provider source footnotes.

The CI gate

eol:<state> is a threshold, matching the cve:<severity> convention: eol:deprecated fires on deprecated and retired. eol:before:<YYYY-MM-DD> is the planning gate, and the one worth putting in a release checklist: “fail if anything we ship depends on a model that dies before our next train leaves.” before:D means “not still serving on D”, so a model shutting down exactly on D matches — the tool already calls that day retired, and the gate must agree. A retired model matches any date (already gone, dated or not); only an undated deprecation matches nothing, because it cannot answer without inventing a deadline the provider never announced. Gating on a state that is not a finding (eol:supported, eol:unknown) is a usage error, as is gating on eol while --no-eol is set, or &-combining an eol selector with a cve one — lifecycle applies to hosted models and CVEs to versioned packages, so no single component is both. All are rejected at parse time: a gate that can only ever pass is worse than no gate.

Coverage

The catalog seeds OpenAI and Anthropic, the two providers whose deprecation pages publish structured, dated schedules. It is deliberately not a list of every model in existence: each record is hand-verified, and the cost of that discipline is coverage. A model outside it reports unknown, which is the honest answer. Adding a provider is a data change, not a code change.

Where the catalog comes from

Retirement dates move on a provider’s calendar, not on AIROM’s release schedule, so the catalog is delivered two ways: The two are merged per provider: a bundle shipping eol/openai.yaml alone says “here is newer OpenAI data”, not “Anthropic no longer has retirement dates”, so untouched providers keep their embedded records. Within a provider the bundle wins entirely. --no-cached-rules pins the scan to the embedded catalog. It is ed25519-verified like the rule packs, so a fresher catalog is not a less trusted one. A malformed bundle catalog is ignored with a warning in the scan output (Stats.Warnings, not just stderr) and the embedded catalog is used — a bad publish must not be worse than an old binary, or quieter. The staleness warning names whichever lever applies, so it never sends you in a circle. A catalog can also be validated before publishing:
The same command lints rule packs — one contract check for anything the bundle carries.