// blog / guide
Prompt regression testing in CI: catch prompt changes before they ship
Code changes get tests. Prompt changes ship on a hunch. A twenty-line CI check catches the most common break, and the rest is a diff a reviewer can read.
What a prompt regression looks like
- A
{{placeholder}}gets renamed in the prompt but not in the code that fills it. - A constraint such as "answer in JSON" is trimmed while shortening the text.
- A wording tweak shifts the output format that downstream code parses.
The first is mechanical and checkable. The others need the prompt to run, and a human to look at the output. Do the cheap check automatically and make the expensive one easy.
1. One prompt per file, in git
prompts/
code-review.md # Review this diff for bugs: {{diff}}
bug-triage.md
inputs/
code-review.diff # a saved sample inputThe layout and commit habits are in how to version prompts in git.
2. Fail on a lost placeholder
This script compares the variables of each modified prompt with the base branch. I ran it on a scratch repo: removing {{lang}} from a prompt printed the FAIL line and exited 1; adding text while keeping every variable exited 0.
#!/usr/bin/env bash
set -euo pipefail
base="${1:-origin/main}"
fail=0
vars() { grep -o '{{[a-zA-Z_][a-zA-Z0-9_]*}}' | sort -u || true; }
for f in $(git diff --name-only --diff-filter=M "$base" -- prompts/); do
lost=$(comm -23 <(git show "$base:$f" | vars) <(vars < "$f"))
if [ -n "$lost" ]; then
echo "FAIL $f: placeholder removed or renamed: $lost"
fail=1
fi
done
exit "$fail"FAIL prompts/code-review.md: placeholder removed or renamed: {{lang}}It only looks at modified files. New prompts have nothing to regress against, and deleting a file is a review decision.
3. Run it, and show the diff in the log
name: prompts
on:
pull_request:
paths: ["prompts/**"]
jobs:
check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Placeholders intact
run: bash scripts/check-prompts.sh origin/${{ github.base_ref }}
- name: Word-level diff
run: git diff --word-diff=plain origin/${{ github.base_ref }} -- prompts/fetch-depth: 0 matters: the default shallow checkout has no base branch to compare against. The word diff makes a one-sentence edit readable; see how to diff two prompts.
4. Run changed prompts on fixed inputs
Structure checks do not tell you the output stayed useful. For that, fill the variables from a saved input and run the prompt through the agent command you already use, once for the base version and once for the new one. Keep the API key in a CI secret, and store both outputs as an artifact so a reviewer can compare them.
ple get "code review" --var diff="$(cat inputs/code-review.diff)" | claude -pple get prints the prompt raw with variables filled, so it pipes into any agent. The loop that scores variants is covered in test your prompts with your own agent. Write the reason for each change in a changelog entry.
What this does not do
It does not score output quality, and model output varies between runs, so do not fail a build on exact output text. Use the structural check as the gate, and the saved outputs as evidence.
FAQ
What is a prompt regression?
A prompt change that breaks something that worked: a deleted placeholder, a dropped constraint, or an instruction that now changes the output format your code parses.
Can CI tell me whether a prompt got better?
No. A script can check structure, such as variables and required lines, and can run the prompt on fixed inputs. Whether the output is better is still a judgment, so the job should surface old and new output for a reviewer.
Why check placeholders first?
They are the cheapest and most reliable check. A renamed or deleted {{placeholder}} means the code that fills it now sends nothing, and the model answers without the input.
Does this need an account or any service?
No. The check is git and bash and runs in any CI. Running the prompt on fixed inputs uses whatever agent command you already have, with your own credentials as CI secrets.
Where does the ple CLI fit?
Locally. ple save, log, diff and rollback track versions on your machine with no account, and ple get fills variables for a pipe. In CI the files in git are the source of truth. See the git versioning guide for the layout.
Try it before you sign up
Want the local side of this first? Save two versions of a prompt and diff them in your browser. No account, and nothing is sent to our servers.