Providers, models and APIs
Retired models, removed endpoints and API changes, read from each provider's own pages only when your code talks to it, and kept only when the quote matches the page.
A model retirement never shows up as a new package version. Your code keeps sending gpt-4.1-nano until the day the provider stops answering. Teire reads the providers' own deprecation pages and changelogs and finds the model IDs and endpoints in your code. Then it fixes them like any other change.
Readers written for these providers
| Provider | Page read | Recognised by |
|---|---|---|
| OpenAI | developers.openai.com/api/docs/deprecations.md | openai, @ai-sdk/openai, @langchain/openai, langchain-openai; api.openai.com |
| Anthropic | platform.claude.com/docs/en/about-claude/model-deprecations.md, plus its parameter deprecations table | @anthropic-ai/sdk, @ai-sdk/anthropic, anthropic, langchain-anthropic; api.anthropic.com |
| Google Gemini | ai.google.dev/gemini-api/docs/deprecations.md.txt | @google/genai, @google/generative-ai, @ai-sdk/google, google-genai; generativelanguage.googleapis.com |
| Nebius Token Factory | the deprecation notices linked from docs.tokenfactory.nebius.com/llms.txt | its API host in your code (it uses the OpenAI SDK) |
| Stripe | docs.stripe.com/changelog.md and each breaking change's page, for the Node.js and Python SDKs | stripe; api.stripe.com |
These readers parse each page's own tables and headings in code, with nothing inferred. A provider counts as used when one of its SDKs is installed, in any of the six ecosystems, or its API host appears in a URL in your code. Its pages are read then, at most once every 6 hours, shared by every repository. Nothing is read on a schedule.
Any other provider
When your code calls an API host that has no reader, Teire discovers the provider. It finds hosts in two ways:
- a URL in your code whose host or path looks like an API (
api.,/v1,/api), - an installed SDK whose published code names an API host on its own domain: the npm tarball, the PyPI wheel, the Go module zip, the
.crate, the.gemor the Maven-sources.jarof the exact version you lock. Up to 40 SDKs are read per scan, as text, never run.
Then it looks for the provider's notices:
llms.txton the docs host and the domain, scoring links that say deprecat, retire, sunset or changelog,- if that finds no deprecations page, a Tavily search limited to the provider's own domains,
- last,
/docs/deprecationsand/deprecationson its busiest docs hosts.
At most 3 pages are kept per provider, deprecations first. Every fetch and redirect must stay on the provider's domains.

The quote gate
A page read by Nemotron becomes one record per model or endpoint, each with a verbatim quote of up to 400 characters. Code then checks every record before Teire acts on it:
- The quote is found in the page Teire fetched.
- The model ID is inside its own quote. A replacement missing from the quote is removed.
- Every source is on the provider's official domains.
- For a page Nemotron read, the ID, the replacement and the date all appear in the quotes.
An item whose quote is not in the page, or whose ID is not in its quote, is dropped. A record that fails the final checks is kept as unconfirmed and never applied to code on its own. Where your code passes its ID as a model, the scan says check by hand in a needs-a-human issue, naming why the record couldn't be confirmed. Comment @teire fix to try it anyway: the run uses the record and opens a draft labelled unconfirmed, with a warning at the top, whatever the checks say. The same rule applies to package release notes: an item that doesn't quote the fetched text is dropped.
Finding the models in your code
ast-grep searches the strings of your JS/TS, Python, Go, Rust, Ruby, Java and Kotlin code for the exact IDs the confirmed records name. It also searches config files (.env*, YAML, TOML, JSON, INI, .properties) for them as whole words. Where an ID sits decides the verdict:
| Where the ID is | Verdict |
|---|---|
Passed as a model: model: "…", model="…", openai("…"), ChatOpenAI(…) | affected |
| In a model-named variable, or under a model key in config | affected |
| Anywhere else, such as a registry, a list or a test | inconclusive, until traced |
Nemotron then traces the inconclusive ones. It is shown the files holding the IDs and the JS/TS or Python files that import them, and asked whether each ID reaches a request. Its answer counts only if the line it cites exists in a file it was shown and names a model. Test and fixture files are never fix sites.
If your code builds the provider's client from an environment variable such as OPENAI_BASE_URL, the deployment decides which service answers. Teire marks those findings inconclusive instead of affected.
Endpoints work the same way: a URL in your code on the provider's host whose path is the removed one, or below it.
API changes from OpenAPI specs
For API hosts your code calls by URL, Teire looks for the provider's OpenAPI spec. It searches the GitHub organisation behind the provider's SDK, or uses a specUrl you set in teire.yml. It diffs the spec with oasdiff 1.34.1 from your position, which is the API version pinned in your code (apiVersion, stripe_version…) or else the date of your last commit touching those files. Breaking changes on operations your URLs reach become findings.
The fix
One PR per provider. Each retired model is swapped for the replacement the provider names. If that replacement was later retired too, Teire follows it, up to 5 hops. When a provider names several options, the agent chooses. Parameter changes from the same provider ride along as migration notes when your code uses that parameter. Then your checks run before and after, as for packages. For a model that has already stopped working, the baseline's checks fail by definition. "Already failing" is not accepted there: the run keeps going until the checks pass after the change.
The public catalog
Everything Teire has read for the repositories it scans is public, and every page links to the others:
| Page | Shows |
|---|---|
| /changes | Every confirmed change, upcoming deadlines first, filterable by source and class |
/changes/<id> | One change: replacement, date, the source's exact words with the page's hash, and what Teire searches your code for. A change computed from published code that no release note confirms yet is marked as not confirmed |
/providers/<slug> | A provider: the pages Teire reads and their health, models with a change, the SDK packages it recognises, and its changes |
/packages/<ecosystem>/<name> | A package: the changes Teire computed per target version and its advisories. Signed in, Where you stand lists each copy your repositories install: its version, how far behind, its open findings, the planned upgrade, and what the API changes from your version to it |
A change only appears once a scanned repository depends on it. The same records are available as JSON from /api/catalog/changes, which the CLI reads.


Limits
Provider SDKs are recognised, and an unknown provider's API hosts discovered from its SDK, in all six ecosystems. Model IDs and URLs are found in all seven languages, and a model or API fix is verified with the checks of the project it changed, whatever its ecosystem. Stripe is read for its Node.js and Python SDK sections. Parameter and API-version records don't become findings on their own. The OpenAPI diff matches URLs in your code, not SDK method calls.
Maven and Gradle
Java and Kotlin projects, diffed with japicmp on the published jars, located again from your compiled classes during the fix, and verified with your build tool offline.
Runtimes
The runtime versions your project pins, in all six ecosystems, checked against their end-of-life dates. Teire reports them, and never changes a runtime for you.