Pinning a Dated Cohere Model Version
8 min read · updated August 11, 2026
command-r-plus is an alias. command-r-plus-08-2024 is a snapshot. The first can change under a running service without any deploy on your side; the second cannot. Pinning takes about ten minutes and the last step is the one that makes it worth doing.
What an alias actually does
A bare model name resolves to whichever snapshot Cohere currently considers the default for that family. When a new snapshot ships, the alias moves. Your requests are then served by a different model, with different output style, different verbosity, possibly different limits — and nothing in your logs marks the moment unless you recorded the served model per request.
The trade-off is worth stating honestly, because pinning is not free. Aliases mean you are never left behind, and they mean you never have to act — a snapshot retirement passes without an incident because the alias already moved you. Pins mean output is stable and your evaluations stay meaningful, and they mean a retirement is an outage unless somebody was watching.
The change is rarely dramatic and that is what makes it expensive. A new snapshot is better on average and different in detail: it may use headings where the old one used paragraphs, hedge where the old one asserted, or return four bullet points where your parser expected three. Aggregate quality goes up while your particular integration goes sideways, and because nothing in your repository changed, the investigation starts by looking at everything except the cause.
For anything with a prompt that was tuned, an evaluation suite, or a downstream parser, pin. Silent behaviour change is the more expensive failure, because it arrives without a signal and gets diagnosed as something else. But pin and monitor, or you have only moved the problem to a date you have not written down.
Step 1: list the dated snapshots
- Ask the API rather than the docs. The models endpoint is the live list, and it tells you what your key can actually call:
curl -s "https://api.cohere.com/v1/models?page_size=100&endpoint=chat" \ -H "Authorization: Bearer $CO_API_KEY" \ | jq -r '.models[] | [.name, .context_length, .is_deprecated] | @tsv'
- Read the naming convention. Cohere’s snapshots carry a month and year —
command-r-08-2024,command-r-plus-08-2024,command-r7b-12-2024,command-a-03-2025. A name with no date suffix is an alias. That is the whole rule, and it makes an audit of your codebase a grep for model strings without a date. - Pick the snapshot the alias currently points at if you are pinning an existing service. Pinning to the current default is a no-op behaviourally, which is exactly what you want from a change whose purpose is to prevent future change.
Step 2: swap the name, in one place
- Find every literal.
rg -n "command-[a-z0-9-]*"across the repository, including test fixtures, notebooks, and any prompt template that names a model in prose. - Move it to configuration. One constant, one environment variable, one place:
// config/models.ts export const CHAT_MODEL = process.env.COHERE_CHAT_MODEL ?? "command-r-plus-08-2024"; export const RERANK_MODEL = process.env.COHERE_RERANK_MODEL ?? "rerank-v3.5";
The environment override is what makes the eventual migration a configuration change you can roll back in seconds rather than a deploy. - Pin the rerank and embed models too. They version independently of Chat and are just as capable of changing your retrieval quality overnight.
Step 3: verify what was served
Pinning the request is only half of it. Log what came back, so that a mismatch is visible rather than assumed away:
const res = await cohere.chat({ model: CHAT_MODEL, messages });
logger.info({
requested_model: CHAT_MODEL,
response_id: res.id,
input_tokens: res.usage?.tokens?.inputTokens,
output_tokens: res.usage?.tokens?.outputTokens,
finish_reason: res.finishReason,
});There is a subtlety worth knowing here: unlike some providers, Cohere does not return the served model name as a field on the chat response, so “which model answered?” is answered by what you sent rather than by what came back. That is precisely why logging the requested model matters — with an alias there is no record at all of which snapshot served a given request, and with a pin the request itself is the record.
The request id is what a support conversation will ask for, and the token counts are what tell you a prompt grew. Keeping the requested model on every log line means that when output quality changes, the first question — did the model change? — is answerable from data rather than from memory.
Step 4: watch the pin
- Poll
is_deprecatedweekly for the exact snapshots in your configuration:curl -s "https://api.cohere.com/v1/models/command-r-plus-08-2024" \ -H "Authorization: Bearer $CO_API_KEY" | jq '.is_deprecated'
Send a true result somewhere a person reads. The full picture of what the flag means is in Cohere’s deprecation notices for Command models. - Keep an evaluation set you can rerun. Twenty to fifty real inputs with expected properties — not expected strings. This is what turns a migration from a leap into a measurement, and it is the only reason the pin was worth having.
- Migrate deliberately when a notice appears. Change the environment variable in staging, run the evaluation set, compare, then promote. Because the model name is configuration, rollback is instantaneous if the new snapshot is worse on your task.
The whole point of the pin is that this sequence happens on a Tuesday afternoon of your choosing rather than on the morning the alias moved.
What pinning does not pin
A pinned snapshot fixes the weights. It does not fix everything that determines the bytes you get back, and being clear about the boundary prevents a false sense of reproducibility.
- The serving stack. Inference kernels, batching strategy and hardware change underneath a fixed set of weights. This is part of why temperature 0 is not a determinism guarantee — identical inputs to identical weights can still produce different output when the arithmetic is batched differently.
- Default prompt content. The default preamble and the safety preamble are supplied by the API, not by you, and their wording is not part of the model name. A change there is a change to your prompt that you did not make and cannot see. Supplying your own preamble removes one of the two; the safety one remains.
- Parameter defaults. Anything you do not set can be changed by the provider or by an SDK upgrade. Setting
temperature,max_tokensand the citation mode explicitly — even to their current defaults — makes the request self-describing and immune to a default moving. - Your own inputs. By far the largest source of drift in practice. Retrieved documents change as the corpus changes, and a prompt assembled from a template that somebody edited is a different prompt. Pinning the model narrows the search when output changes; it does not make the corpus a constant.
The honest summary is that pinning converts a large, invisible, provider-driven source of change into a small, dated, scheduled one. That is worth doing, and it is not the same thing as reproducibility. An evaluation set that you can rerun on demand is what actually tells you whether behaviour changed, and it is the artefact worth investing in before any of the four items above.