Put it back the way it was on Tuesday
Nine checks for the afternoon somebody asks you to undo the week. A rollback feels like the safe option because it only removes things, and that is the exact reason it goes wrong: a revert is an edit, and it has to survive every line that landed after the one you are putting back.
TL;DR Name the rollback target as an artifact hash, never as a day; revert the directory the prompt composes from, because a single-file revert leaves an imported house-rules file at today's version and lands you on a prompt that never existed; then rebuild and require the recorded hash, run check because last week's wording against this week's rules can be a blocking contradiction, and read the artifact diff line by line to see what you are giving back. Two things ride along invisibly: the $CONFIG model row, which no artifact diff can see, and the host's input bag, which the file never held.
It is half past three on a Friday. Containment on the billing queue has been sliding since Wednesday, a team lead has three transcripts that all look wrong in the same way, and the sentence everyone has landed on is that it was fine on Tuesday. The ask is reasonable and the ask is urgent, and both of those things push you toward the same wrong move, which is to open the file, find the line you think it is, and put the old wording back.
Nine checks, run against a small energy-billing prompt. It is not a broken prompt; it is a prompt three people edited in one week. That is the normal case and it is the whole difficulty.
<$CONFIG> $IMPORT file "house.tg" as house $CONFIG model claude-haiku-4-5 - via:: anthropic $REQUIRE variable balance: number </$CONFIG> $SERVICE anthropic - base:: https://api.anthropic.com # Role @@ role: one sentence names the speaker, so every later "you" is the agent You are Ora, the billing assistant for Fernhill Energy. @<house.Constraints> # Constraints @@ plan_cap: ops doubled the ceiling after the winter bills landed - You MUST offer a payment plan of at most 24 months. @@ plan_floor: collections will not take a plan shorter than this - You MUST offer a payment plan of at least 18 months. @@ meter: never quote a figure the meter has not confirmed - You MUST NOT quote a final bill amount. @@ arrears_route: the arrears team owns a large balance $IF @{balance} is at least 300: - You MUST transfer a customer to an arrears adviser. $ELSE: - You MUST offer a monthly instalment. $TEST behind - input:: I am two months behind on my bill. - expect:: - offers a payment plan
house.tg carries the brevity rule and the AI-disclosure rule every Fernhill prompt shares. Hold on to that, because it is check 4 and it is the one that catches people.$ git log --format='%h %ad %s' --date=short 72189ff 2026-09-16 billing: add the 18-month floor, the house complaints rule, and move to haiku 0a4733e 2026-09-16 billing: raise the payment-plan ceiling to 24 months ff83d07 2026-09-16 billing: the desk prompt as it ran on Tuesday
§1Before you touch the file
Check 1: name the target as a hash, not as a day. "Tuesday" is not an identifier. It is a shared memory, and in a week nobody will agree on it. What you want is the artifact hash your deploy recorded for the build you are going back to, and the build manifest is the shape that record comes in.
{
"source": "billing.tg",
"sourceSha256": "2b3e35b010cd8ddcfbd5730279504ce4d33e044f726eb09a0e9a1b15504e5b77",
"artifact": ".typeglish/dist/billing.txt",
"artifactSha256": "cd9c4b99bc51753a0c9c015c5d985880d68d71efa82045d9fe43e10f8d3ce37b",
"vars": null,
"typeglish": "0.9.0",
"checkMode": "full",
"report": { "ok": true, "counts": { "error": 0, "warn": 0, "info": 0 }, "strict": false },
"builtAt": "2026-09-16T09:29:02.017Z"
}
artifactSha256 identifies the bytes the model actually read, so it survives a rename, a comment, and a reformat. vars records the input bag the build was pinned to, or null for a template build. And typeglish records the compiler, which is what makes a rebuilt artifact comparable with the one it is replacing. Note what this row is and is not: the manifest holds the latest build per artifact path, so this is cd9c4b99bc51, what is live. Tuesday's hash has to come from wherever the deploy logged it, and in this repo that is 6d35707cb150. If nobody logged it, the fallback is to rebuild Tuesday's commit and take what comes out, while saying out loud that you are trusting the typeglish field to still read 0.9.0.Check 2: reproduce the complaint as a $TEST before you change anything. This is the check most likely to be skipped and the only one that outlives the afternoon. You have three transcripts. Turn the clearest one into a case with a deterministic assert, and add it to the file you are about to roll back and the file you are rolling back to. If the rollback fixes the behaviour, the test is now a regression test that will fail the day somebody re-lands the change without thinking. If the rollback does not fix it, you have learned that in twenty seconds rather than after a deploy, which is the more valuable outcome and the one nobody plans for. Your agent said the wrong thing, now what is the longer version of this hour; the short version is that the transcript is evidence and a transcript nobody wrote down is a rumour.
§2The revert is an edit
Check 3: run check on the revert, because last week's wording has to live with this week's rules. Here is the move everybody makes under time pressure. The plan ceiling looks like the culprit, so put it back to what it was on Tuesday and leave everything else alone. In isolation that line is unimpeachable: it is the line that was running when the numbers were fine.
# Role @@ role: one sentence names the speaker, so every later "you" is the agent You are Ora, the billing assistant for Fernhill Energy. # Constraints @@ plan_cap: ops doubled the ceiling after the winter bills landed - You MUST offer a payment plan of at most 24 months. @@ plan_floor: collections will not take a plan shorter than this - You MUST offer a payment plan of at least 18 months.
# Role @@ role: one sentence names the speaker, so every later "you" is the agent You are Ora, the billing assistant for Fernhill Energy. # Constraints @@ plan_cap: twelve months is the ceiling collections signed off - You MUST offer a payment plan of at most 12 months. @@ plan_floor: collections will not take a plan shorter than this - You MUST offer a payment plan of at least 18 months.
$ npx typeglish check . billing.tg:19:1 error logic/time Conflicts with line 14. Time conflict — "at most 12 months" and "at least 18 months" cannot both bound "you offer a payment · plan": the windows never intersect. billing.tg:19:1 error logic/numeric Conflicts with line 14. Numeric conflict — "at most 12 months" and "at least 18 months" can't both hold. billing.tg:21:1 error logic/time Conflicts with line 13. Time conflict — "at most 12 months" and "at least 18 months" cannot both bound "you offer a payment · plan": the windows never intersect. billing.tg:21:1 error logic/numeric Conflicts with line 13. Numeric conflict — "at most 12 months" and "at least 18 months" can't both hold. ✗ 2 files — 4 error, 0 warning, 0 info program: 1 root — billing.tg (2 files) # exit 1 $ npx typeglish score billing.tg billing.tg — F (79/100) proven errors — grade capped at F tiers: base+z3 $ npx typeglish build billing.tg typeglish build: billing.tg refused — nothing written
Check 4: revert the directory, not the file. So do it properly: take the whole prompt file back to Tuesday's commit rather than hand-picking a line. This passes, which is the problem.
$ git checkout ff83d07 -- billing.tg $ npx typeglish check . ✓ 2 files — 0 error, 0 warning, 0 info program: 1 root — billing.tg (2 files) $ npx typeglish build billing.tg ✓ built .typeglish/dist/billing.txt ← billing.tg (7744c9d03bb6, full)
7744c9d03bb6. The target was 6d35707cb150 and the thing you are replacing was cd9c4b99bc51, so this is a third prompt: not the one that shipped on Tuesday, not the one running now, and one that has never been in production or in front of a reviewer. house.tg is still at Thursday, because a revert of one file is a revert of one file, and the shared file is part of the deployed prompt.Check 5: rebuild and require the recorded hash. This is the null test, and it is four seconds. Revert everything the prompt composes from, rebuild, and demand the twelve characters the manifest wrote down for the day you are going back to. Equality is the whole claim of a rollback, and until this command passes it is an assertion.
$ git checkout ff83d07 -- . $ npx typeglish check . ✓ 2 files — 0 error, 0 warning, 0 info program: 1 root — billing.tg (2 files) $ npx typeglish build billing.tg --bundle ✓ built .typeglish/dist/billing.txt ← billing.tg (6d35707cb150, full)
$IMPORT mechanics are the point of the paragraph that lives in three prompts, and this is their bill coming due.§3Read what you are giving back
Check 6: diff the live artifact against the one you are about to deploy, and read every line. A rollback is a change with a direction, and the direction does not make it small. Three days of decisions come out in one command, and the useful discipline is to say out loud, for each line, who decided it and whether they know it is going.
$ diff live/billing.txt .typeglish/dist/billing.txt 5d4 < - WHEN a customer raises a complaint THEN you MUST transfer them to a complaints handler. 9,10c8 < - You MUST offer a payment plan of at most 24 months. < - You MUST offer a payment plan of at least 18 months. --- > - You MUST offer a payment plan of at most 12 months.
Check 7: read the bundle, because the model rides along and the artifact cannot see it. Thursday's commit moved the prompt to a smaller model in the same breath as the rules. Rolling the file back rolls that decision back too, and there is no trace of it in the prompt the model reads.
$ cat .typeglish/dist/billing.agent.json
{
"model": {
"id": "claude-opus-4-8",
"service": { "name": "anthropic", "base": "https://api.anthropic.com", "headers": [] }
}
}
claude-haiku-4-5 and against claude-opus-4-8 and both come out at 6d35707cb150. A $CONFIG row is control plane, stripped before a byte is emitted, so the artifact hash you have been leaning on for the last four checks is blind to it by design. That is correct behaviour and it is a hole in your rollback: an artifact-only review cannot tell a prompt rollback from a prompt rollback plus a model change. If the swap is the thing you actually wanted to keep, somebody wants the model bill smaller is the list for unpicking the two.Check 8: the host's input bag does not roll back, because it was never in the file. Half the deployed prompt arrives at request time, and a git history has no opinion about it. The same reverted source, built against two bags, is two different prompts.
$ npx typeglish build billing.tg --vars '{"balance": 250}' --out-dir v250
✓ built v250/billing.txt ← billing.tg (fb15eae9d05e, full)
$ npx typeglish build billing.tg --vars '{"balance": 400}' --out-dir v400
✓ built v400/billing.txt ← billing.tg (dfe052b5cadd, full)
$ diff v250/billing.txt v400/billing.txt
10c10
< - You MUST offer a monthly instalment.
---
> - You MUST transfer a customer to an arrears adviser.
@{balance} also changed this week. Your prompt cannot tell a missing input from a real one is the same seam, seen from the other side.§4Landing it
Check 9: land the rollback as a commit forward, with the tests from check 2 still in the file. Not a force push, not a reset, not a deploy from a detached head. The prompt is source and its history is the audit trail: somebody will ask in October why the complaints rule disappeared for four days, and the answer needs to be a commit message rather than a recollection. Put the hash in it, both of them, the one you left and the one you landed on.
$ npx typeglish test billing.tg --dry # before the rollback ✓ billing.tg coverage: 5/6 rules exercised $ npx typeglish test billing.tg --dry # after the rollback ✓ billing.tg coverage: 4/5 rules exercised
And the part a checklist cannot do for you. Every command above answers the question "did I land where I meant to", and none of them answers "should I have". A rollback trades a known-bad week for a known-good one and pays for it in whatever was genuinely better about the week you are deleting. In this file that is a ceiling ops raised for a reason, a floor collections asked for, and a regulatory rule with a clock on it, all of which will have to be re-landed on Monday by somebody reading a diff. The narrower fix, reverting one rule with its guard intact, is usually the right one, and check 3 exists because the narrow fix is the one the compiler has the most to say about.
§5Common questions
- How do I roll back an AI agent system prompt?
- Treat it as an edit, not an undo. Name the target as the artifact hash the build manifest recorded for the day you want back, rather than as a day. Revert the directory the prompt composes from rather than the one file, because an imported house-rules file is part of the deployed prompt and a single-file revert leaves it at today's version. Rebuild and require the hash to equal the recorded one, which is the null test that proves you landed where you meant to. Then run
check, because a revert composes last week's wording against every rule added since and can be a blocking contradiction. Finally diff the live artifact against the one you are about to deploy and read every line you are giving back. - Why does reverting one line of my prompt break the build?
- Because a revert is an edit, and the line you are putting back has to live with the lines added after it left. A billing prompt holding a payment plan of at most 24 months and a payment plan of at least 18 months is clean. Restore the ceiling to the 12 months it was on Tuesday and the same file is 4 blocking errors, two
logic/timeand twologic/numeric, gradedF (79/100), and the build refuses to write anything. This is the rollback working. A partial revert that reintroduces an old bound under a new floor is exactly the change no reviewer catches by eye, and it is the one the prover catches every time. - Does a git revert of my prompt file roll back the deployed prompt?
- Not by itself, if the prompt composes from more than one file. Reverting only
billing.tgwhile the importedhouse.tgstays at today's version checks clean, builds, and produces an artifact that is neither the prompt that shipped on Tuesday nor the one running now. The two differ by a regulatory complaints rule that was added to the shared file and that a single-file revert silently keeps. Revert the directory, rebuild, and compare the hash against the manifest. And one thing a git revert can never bring back at all is the host's input bag, because it arrives at request time and nothing in the file pins it. - What does a prompt rollback silently change besides the rules?
- The model, and no artifact diff can see it. A
$CONFIG modelrow is control plane: it is stripped before a byte is emitted, so the same prompt built againstclaude-haiku-4-5andclaude-opus-4-8produces the identical artifact hash. If the model was swapped in the same week as the rules, a rollback of the file swaps it back, and the only place that shows is thebuild --bundlesidecar, which names the model id and the service it requests through. Read the sidecar as part of the rollback, and log the compiler version from the build manifest too, so a rebuilt artifact is an apples-to-apples comparison with the one it is replacing.
The reason a rollback is worth nine checks rather than one command is that it is the only prompt change routinely made by somebody who is not trying to change anything. Every other edit on this blog arrives with an intent you can hold the result against: a rule to add, a bound to move, an arm to scope. A rollback arrives with an intent of "less", and "less" is not a specification, so the thing that decides what actually ships is whatever the tooling happens to reach. A single-file git checkout reaches one file and produces a prompt that has never existed. A hand-edited line reaches the wording and not the week it has to live in, which is 4 error and a refused build if you run the compiler and a silent policy contradiction if you do not. What holds it together is the same discipline as the rest of the pipeline and the same one nobody enjoys: the artifact is the deliverable, its hash is its name, and the diff against the live artifact is the only honest statement of what a rollback does. Get those three in the ticket and the October question answers itself. If you are building the gate, the prompt is frozen, the artifact is not is what counts as a change, and we moved eleven lines, six shipped a different prompt is why the source diff is not the document to review.