Skip to content

Anti-Pattern: The Prompt Nobody Owns

5 min read · updated August 3, 2026

Prompts are the only part of an AI system that is simultaneously load-bearing logic and untyped text pasted into a file. Every property you rely on elsewhere — an owner, a test, a review, a version — is absent by default, and nothing in the tooling notices.

How it happens to careful teams

The first prompt is a string literal next to the call, because that is obviously where it goes. The second is a copy of the first with two words changed, because the second feature is similar and copying is faster than parameterising something that might diverge. The third lives in a config file, because somebody wanted to change it without a deploy. The fourth is assembled at runtime from three fragments and a user setting.

None of those four steps is a mistake in isolation, and that is the entire mechanism. There is no moment where a reviewer can say “this is the wrong thing to do”, because at each step it is the right thing to do. What accumulates is a system whose most consequential behaviour is defined by text in four places with no index, no owner and no test.

A second contributor: prompts are edited by people who are not committing code. A support lead who notices the tone is wrong, a domain expert who knows the classification rules, a designer fixing a phrase. Those edits are legitimate and valuable, and if the only path to making them is a pull request, they either do not happen or they happen through whoever has commit access — who then owns text they do not understand.

The four ways it bites

You cannot answer “what changed”

Output quality drops. The question is whether the prompt changed, the model changed underneath you, the input distribution moved, or the retrieval index was rebuilt. With prompt text spread across a config store, a database row and two string literals, the first of those four is not answerable in less than an afternoon — and until it is answered, the other three cannot be investigated. Every hour of that is an outage in slow motion.

Fixes do not propagate

Somebody discovers that adding one clause removes a whole class of failure. That clause now exists in one of the five places the same instruction lives. The other four keep the bug, and because they are copies rather than references, nothing will ever tell you they are out of date. Copies of a prompt diverge in exactly the way copies of code diverge, but without a linter, a shared type or a compiler to notice.

Every edit is an untested deploy

A prompt change is a behaviour change to a program. If it does not go through a gate, the gate is production. That is tolerable when the feature is small and intolerable at the point where somebody edits a shared system prompt to fix one feature and silently changes four others that inherit it.

The knowledge leaves with a person

Prompts accrete clauses that look arbitrary and are not — a line that exists because of a failure mode discovered eight months ago, a strange ordering that raised accuracy on a specific model family. Without a comment or a linked eval case, the next person cleans it up. Prompt text is unusually good at looking like it can be tidied and unusually bad at surviving tidying.

Signals you have it already

  • Grep for the same distinctive phrase from your main system prompt across the repository and the config store. More than one hit that is not an intentional include is a copy, and copies have already diverged.
  • Ask who approves a prompt change. If the answer is “whoever is editing it”, or if it differs depending on which prompt, there is no owner.
  • Try to reconstruct the exact prompt for a request from last Tuesday. If you cannot — because the template was edited since and nothing recorded which version served the request — then no production incident involving output quality is investigable. This is the single most useful test, and the fix is a version identifier logged with every call.
  • Count the prompts with no test at all. Not a good eval; any assertion whatsoever that fails when the prompt is deleted. In most codebases the honest answer at this point is all of them.

The ownership model

The fix is small and it is organisational before it is technical. Four properties, each of which can be added independently.

PropertyDescription
One definitionEach prompt exists once, addressed by an identifier. Variants are parameters or explicit overrides of the named base, never copies. If two features genuinely need different text, they are two named prompts, not one prompt edited twice.
One named ownerA person, not a team, recorded next to the prompt. Their job is not to write it — it is to be the reviewer who knows why the odd clauses are there.
A version on every callThe identifier and version go into the log line for every request, alongside the model id. Without this, correlating a quality change with a prompt change is guesswork.
A gate on changeA set of cases the prompt must still pass. It does not need to be large — a dozen inputs with a pass/fail rule catches most regressions — but it must run automatically, because a gate that requires someone to remember is not a gate.

Note what is deliberately not on that list. There is no requirement for a vendor tool, a database-backed registry or an editing interface. Files in the repository with an identifier, an owner comment and a test directory satisfy all four, and a git-based workflow is the cheapest thing that works. The case for a separate prompt registry is real but narrower than it is usually sold: it is about decoupling prompt releases from code releases, which matters when non-engineers must edit and you cannot ship on demand. If you can ship on demand, files are better, because they get code review for free.

One structural decision does most of the work regardless of where the text lives: keep the prompt and its evaluation cases adjacent. A prompt whose test file sits beside it is a prompt whose weird clause has a case named after the failure it prevents, and that is the only durable way to stop the clause being removed by somebody tidying up.

Migrating a codebase that has the problem

You do not have to fix all of it, and the order matters because the first step makes the rest measurable.

  • Inventory before refactor. Find every place a prompt is constructed and list them. Do not consolidate yet — an inventory is cheap and reveals which prompts are actually hot.
  • Add the version to the logs first. Even before consolidating, stamp each call site with a stable identifier. From that day forward, quality questions become answerable, and the answer improves every week the log accumulates.
  • Consolidate by traffic, not by tidiness. The prompt serving most requests gets an owner, a home and a test. The one behind an admin tool used twice a month can stay a string literal forever; moving it is churn.
  • Freeze copies as you find them. When you discover two divergent copies, resist merging them immediately — they may have diverged for a reason nobody remembers. Name both, test both, then merge when a test tells you they behave the same.
  • Write the gate before the cleanup. Refactoring prompt assembly without cases to run against is the one change in this list that can silently break the product, because the refactored version will still produce fluent output.

The end state is unglamorous: prompts that are ordinary code, in the repository, with an owner and a handful of tests. The reason it is worth the week is that every other quality practice — evaluation, canarying, incident response — assumes you can name the prompt that served a request. Without that, none of them can be built on top.

Anti-Pattern: The Prompt Nobody Owns · Multigrid