Prompts are code, and they need the same discipline

A prompt change alters system behaviour in production. If it can reach users without review, a test, or a way to roll back, then the most volatile part of your system is also the least governed.

Share

Ask a team where their prompts live and the answers vary alarmingly. In the code, in a database, in a spreadsheet somebody maintains, in a vendor console that three people can edit. Ask who reviewed the last change and the answer is often nobody.

This is strange, because a prompt is the most behaviour-defining string in the system. Changing one is a production change. It just does not feel like one, because it does not look like a diff.

What goes wrong

Nobody can say what is running. The prompt in the repository is not the prompt in production, because someone fixed a customer issue in the console on Friday. Reproducing a bug requires knowing which text was used, and that information no longer exists.

Improvements regress silently. Adding an instruction to fix one edge case degrades three cases that were working. Without an evaluation suite, the regression ships and is discovered by a customer weeks later, by which time nobody connects it to that change.

Traces become unreadable. A logged run six weeks ago has inputs, tool calls and output — but the prompt has changed twice since. The trace records what happened and not why, and the why was in the prompt.

Rollback is not available. The old text is gone. Recovering it means asking whoever edited it what it said before.

The discipline, which is not elaborate

Prompts live in version control. Not in a database row, not in a vendor UI. Files in the repository, changed through the same process as any other code, with an author and a reason attached to each change.

Every prompt has a version identifier, and every run records it. A hash of the text is sufficient. Store it with the trace. Now a run from March can be explained by the prompt that was actually used in March, and "did this behaviour change" becomes a query rather than a memory exercise.

A prompt change runs the evaluation suite. This is the one that matters most. If a prompt edit can merge without the suite passing, the suite is decorative. Treat it exactly as you would a change to a pricing function — because that is the same class of change.

Someone else reads it. Prompts have bugs that are invisible to their author: an instruction that contradicts one three paragraphs up, an example that demonstrates the wrong output format, a constraint that quietly assumes English. A second reader catches these the way a second reader catches any other logic error.

Configuration is separate from instruction. Thresholds, limits and model names do not belong in prose. Pull them into config so a limit change is a config change, and reading the prompt tells you the intent rather than the parameters.

The objection, and the answer

The usual pushback: this slows down iteration, and iteration speed is the whole advantage of prompting over training.

It is true that a review step adds time. It is also true that the reason prompt iteration feels fast is that nothing is checking the work — and speed measured without correctness is not speed, it is just motion. A cycle where a change takes twenty minutes and you know it did not break anything is faster in any horizon longer than a fortnight than one where changes take two minutes and each one is a coin toss.

Keep the fast loop for exploration. Put the gate before production. Those are different environments and they can have different rules.

The one-line test

Can you answer, right now, what prompt text served a request from six weeks ago, and what changed since?

If not, the most volatile component in your system is also the only one with no change history — and that is worth an afternoon to fix.