A Version Number Is Not An Identity
Every prompt file has a version field. Nobody bumps it. Hash the content instead, and your cache stops lying to you.
Every prompt format I’ve seen has a version: field near the top. Mine does too. It is the most-lied-to line in the file.
Not out of malice. You are two hours into tuning a system message, you have changed it eleven times, and bumping 1.0.0 to 1.0.1 is not on your mind for any of them. By the time you open the pull request the content has moved and the number has not.
Which would be a cosmetic problem, except that something downstream believes it.
What believes it
The response cache. If a cache keys on name and version, then an edited prompt with a stale version is a cache hit on the old answer. You change the instruction, run it, and get back a response generated by text that no longer exists. You conclude the edit did nothing.
That bug is genuinely horrible to find, because everything in front of you is correct. The file says what you want. The code loads the file. The output is from last Tuesday.
Hash the content
So don’t ask the human. A prompt’s identity should be a hash over the things that actually determine its behaviour — the messages, the input and output schemas, and every include it resolves:
a = load_prompt("greet.yaml") # version: 1.0.0
b = load_prompt("greet-copy.yaml") # version: 9.9.9, same content
assert a.fingerprint == b.fingerprint
Two files, two different version strings, one prompt. That is the correct answer, and no field anyone maintains by hand can produce it.
Includes are the interesting part
The reason to fold resolved includes into the hash isn’t completeness, it’s the shared partial.
prompts/
├── _partials/house_style.j2
├── support/refund.yaml
└── greet.yaml
Edit house_style.j2 — one sentence of tone, shared by forty prompts — and the fingerprint of all forty changes. Every cached response derived from the old style is now unreachable, automatically, because the key moved.
With a hand-maintained version you would have to remember to bump forty files. You would not. Nobody would.
So what is version for
Humans. It’s a label you put in a changelog and say out loud in a meeting: “we’re on the 2.0 support prompts now.” That’s a real thing to want, and it’s fine to keep the field.
It just must not be load-bearing. The moment a machine keys on a number a person is responsible for updating, you’ve built a correctness bug and scheduled it for whenever someone is tired.
Advisory metadata for people, content hashes for machines. Keep them apart.
This is how identity works in PromptKit — Prompt.fingerprint over messages, schemas and resolved includes, with version kept as metadata that changes nothing. The composition guide covers the include side.