Short answer
Prompt versioning means treating every prompt, model setting, tool schema and evaluation dataset as a versioned artefact, so any output can be traced to the exact configuration that produced it and any release can be rolled back. Keep prompts in source control or a registry with immutable versions, pin model snapshots, version eval sets and scorers together, and record a configuration hash on every production call.
- Version the whole configuration: prompt, model snapshot, parameters, tools, retrieval settings and scorers.
- Log a configuration hash on every production call so outputs are traceable.
- Evaluation sets are append-only; corrections create a new version, never an in-place edit.
- Compare results only within the same dataset and scorer versions.
- Rollback should be an alias change that takes minutes, rehearsed before it is needed.
What has to be versioned
Version everything that changes the system’s behaviour, not just the prompt text. Two runs with the same prompt and a different model snapshot, temperature or retrieval index are different systems.
| Artefact | Examples | Why it needs a version |
|---|---|---|
| Prompt templates | System prompt, task instructions, few-shot examples | The most frequently edited part of the system |
| Model and parameters | Dated snapshot ID, temperature, reasoning effort, output token cap | Same prompt, different model, different behaviour |
| Tool definitions | Function names, argument schemas, descriptions | Models choose tools by their descriptions |
| Retrieval settings | Embedding model, chunking rules, index build, top-k | Answers change when the index changes |
| Evaluation datasets | Cases, gold labels, metadata | Scores are meaningless without the exact test set |
| Scorers | Scoring code, judge prompt, judge model | A new judge can move scores with no system change |
One manifest, one hash, logged on every call
Describe each call site’s configuration in a manifest kept in the repository, and compute a hash over the manifest and every file it references.
call_site: invoice_coding.classify_line
prompt: prompts/invoice_coding/classify_line.md
prompt_version: 3.2.0
model: provider-model-2026-09-08
params: {temperature: 0, max_output_tokens: 400}
tools: schemas/coding_tools.json
retrieval: {embedding_model: embed-2026-05, index_build: coa-index-2026-10-01, top_k: 8}
evaluation: {dataset: invoice-coding-eval-v7, scorers: coding-scorers-2.1.0}
import hashlib
import json
from pathlib import Path
def config_hash(manifest: dict, referenced_files: list[str]) -> str:
digest = hashlib.sha256(json.dumps(manifest, sort_keys=True).encode("utf-8"))
for path in sorted(referenced_files):
digest.update(Path(path).read_bytes())
return digest.hexdigest()[:12]
Write the hash into the trace of every production call. When someone asks why an answer changed between Tuesday and Thursday, you compare two hashes instead of reconstructing history from chat messages. Trace design is covered in AI audit logs.
Tracing a changed answer
Illustrative example: an accounts team reports that from Wednesday the system began coding courier invoices to Freight instead of Postage. With versioning in place, the investigation is a set of lookups rather than a debate.
- Pull traces for the affected invoices and compare configuration hashes before and after Wednesday. The hash changed, and the manifest diff shows the index build moved from coa-index-2026-10-01 to coa-index-2026-10-08.
- Diff the two index builds. A newly added chart-of-accounts note describes Freight in words that now outrank Postage for courier lines.
- Run the regression suite against both builds. The courier cases flip, which confirms the cause.
- Fix the source note, rebuild the index, add the courier cases to a new dataset version, and move the alias once the suite passes.
Had the hash not changed, the cause would lie outside your configuration: different inputs, or a change on the provider’s side. Knowing which it is narrows the search immediately.
Semantic versions for prompts
Give prompts version numbers that say what kind of change was made. Semantic Versioning defines MAJOR.MINOR.PATCH: increment MAJOR for incompatible API changes, MINOR for backward-compatible functionality, PATCH for backward-compatible fixes. Mapped to prompts:
| Change | Bump | Example | Evidence required |
|---|---|---|---|
| Output contract changes | MAJOR | A required JSON field added or renamed | Consumers updated; full regression suite |
| Behaviour changes, same contract | MINOR | New rule for handling credit notes | Full regression; every flipped case read |
| Wording fix, no intended change | PATCH | Typo or clarified sentence | Regression run anyway: models react to wording |
The last row matters. With language models there is no such thing as a change that cannot alter behaviour, so even a PATCH runs the suite.
Where prompts should live
Keep the repository as the source of truth for engineering teams: prompts change through pull requests, evaluations run in CI, and deploys are tied to commits. Use a registry when you need runtime switching or non-engineer editing. MLflow’s Prompt Registry, for example, makes prompt versions immutable and lets an alias such as production point at a specific version.
The pattern that works in either case: immutable versions, environment aliases (staging, production) that point at versions, and a rule that an alias only moves after the evaluation run for that version has passed. Our lesson on building a reusable prompt library covers the same idea for teams using AI chat tools.
Versioning evaluations so results stay comparable
An evaluation score is only meaningful with three identifiers attached: the system configuration hash, the dataset version and the scorer version. Change any one and the score is a different measurement.
- Append-only datasets. A wrong gold label is fixed by publishing a new version with a changelog entry, never by editing in place.
- Scorer bundles. Scoring code, judge prompt and judge model are versioned together.
- Like with like. Dashboards compare runs only within the same dataset and scorer versions; a scorer upgrade means re-scoring old outputs, which is why raw outputs must be stored.
- No leakage. Few-shot examples in a prompt must not appear in the evaluation set. Check by content hash on every run.
- Protected holdouts. Whoever, or whatever, tunes the prompt must not see the test set.
That last rule matters more as optimisation is automated. In Tiny Shakespeare CLM, a research repository by Levy Street’s Jeremy Baron described on our code policy models page, an autonomous Claude agent improved a model by editing code, with improvements committed alongside their metric changes. A hook blocked the agent from reading the development and validation splits, and those evaluations were operator-only commands. The repository’s published bits-per-character figures are training-set numbers; held-out scores stay with the operator.
A reproducible experiment record
Every experiment that informs a release decision should be reproducible from its record.
from dataclasses import dataclass, field
from datetime import datetime, timezone
@dataclass(frozen=True)
class ExperimentRun:
config_hash: str # system under test
dataset_version: str # e.g. "invoice-coding-eval-v7"
scorer_version: str # e.g. "coding-scorers-2.1.0"
repeats: int # hosted models vary between runs, so repeat
provider_region: str # where inference ran
outputs_uri: str # raw outputs, kept for re-scoring
started_at: str = field(default_factory=lambda: datetime.now(timezone.utc).isoformat())
Run each configuration several times and report the spread, because hosted models do not always return identical outputs for identical inputs. Methods for building the suite itself are in AI agent evaluations.
Rollback that takes minutes
Rollback should be a configuration change: move the production alias back to the previous version. Three details decide whether that works under pressure.
- Runtime resolution. The application resolves the alias at run time with a short cache, so a rollback does not need a deploy.
- State compatibility. Conversations, memory and stored outputs created under the new version must still work under the old one. MAJOR changes need a data migration plan before release.
- Rehearsal. Roll back in staging on a schedule, and time it. A rollback nobody has practised fails during the incident it was built for; see AI incident response.
Model changes are the largest kind of version change, covered step by step in AI model migration.
Where versioning goes wrong
| Failure | Symptom | Detection |
|---|---|---|
| Hot edits in a prompt tool | Behaviour changes with no deploy | Config hash change without a matching release record |
| Gold labels edited in place | Scores jump for no system reason | Dataset checksum per version; changelog required |
| Judge model changed | Scores move across all systems at once | Scorer version on every result |
| Index rebuilt silently | Retrieval answers drift | Index build ID in the manifest and traces |
| Few-shot leakage | Evaluation scores too good to be true | Hash overlap check between prompt examples and eval cases |
| Moving model alias | Gradual behaviour change | Alias ban in configuration linting |
| Secrets in prompts | Keys exposed to everyone with registry access | Secret scanning on prompt files and registries |
If you want an independent check of how your prompts and evaluations are versioned and run, it is part of our LLM evaluation services.
- Prompts, model snapshots, parameters, tools, retrieval settings and scorers are all versioned
- Each call site has a manifest, and its configuration hash is logged on every production call
- Prompt versions follow MAJOR.MINOR.PATCH rules, and every change runs the regression suite
- Prompt versions are immutable; environment aliases move only after evaluations pass
- Evaluation datasets are append-only with changelogs; raw outputs are stored for re-scoring
- Results are compared only within the same dataset and scorer versions
- Few-shot examples are checked for overlap with evaluation cases
- Test sets are hidden from whoever, or whatever, tunes the prompt
- Rollback is an alias change resolved at run time, rehearsed on a schedule
Sources
- Semantic Versioning 2.0.0, semver.org, 2013
- Prompt Registry, MLflow documentation, 2026
- Tiny Shakespeare CLM, GitHub (levy-street), 2026
Written by the Levy Street team in Wellington. Last updated 19 October 2026.