You are about to add one more rule
Nobody reviews the fourth line of a prompt as carefully as they reviewed the first forty. The launch checklist ran once, months ago. This is the checklist for every Tuesday after that.
TL;DR Eight checks before a new rule lands in a live agent prompt, each with a command behind it, because the naive version of the rule passes all of your automatic gates: it compiles with 0 errors, survives check --strict, and scores A (93/100) while promising delivery dates the same file forbids and offering twice the goodwill the same file caps. A green check is the floor of the gate, not the gate.
Ops messages you on Monday. Late orders are generating complaints, so could the bot tell people their order ships within 24 hours and offer them ten percent off. It is one line. You have written a thousand lines like it. The prompt is in production, it has been fine for four months, and the whole change is about ninety seconds of typing.
That is the moment this list is for. Not the launch, which got a review, a sign-off, and a checklist of its own. Not the incident, which gets a triage order and everybody's attention. The steady state, where a prompt accumulates one reasonable line at a time until it is a different prompt than the one anybody approved.
§1The file, and the rule that passes everything
Here is the live prompt. It is genuinely good: every rule bounded or scoped, an annotation over each one, a test, and a clean bill of health at A (95/100) with nothing at all in the findings list.
# Role @@ role: the addressee, so every rule below has a doer You are an order-support agent for Acme, an online retailer. # Facts @@ order: the record every conversation is about The %order number% IS a six-digit code. @@ total: the number the goodwill cap is a percentage of The %order total% IS the amount the customer paid at checkout. @@ goodwill_cap: above this an agent needs a human to sign off The %goodwill cap% IS at most 5 percent of the %order total%. # Constraints @@ brevity: three sentences keeps a chat reply scannable - MUST keep every response to at most 3 sentences. @@ ask_order: the order number unlocks account context - ALWAYS ask for the %order number%. @@ no_dates: a promised date the warehouse misses becomes a second complaint - NEVER promise a delivery date. @@ angry: a heated customer gets a human - IF the customer is angry THEN escalate to a human agent. $TEST late_order - input:: My order was supposed to arrive Tuesday and it is still not here. - expect:: - at most 3 sentences
NEVER promise a delivery date, and a goodwill cap declared as a fact at 5 percent. Ops has just asked for a delivery promise and ten percent.Now the ninety-second version of the change. One conditional, both halves of the ask, phrased the way the request was phrased.
@@ late_orders: ops asked for this on Monday - IF an order is late THEN promise a delivery date within 24 hours and offer 10 percent off the %order total%.
$ npx typeglish check naive.tg ✓ 1 file — 0 error, 0 warning, 0 info $ npx typeglish score naive.tg naive.tg — A (93/100) proven errors: none tiers: base+z3 planes runtime 91 (what the model reads) · hygiene 100 (source only)
A green check means nothing was proven. It has never meant nothing is wrong.
§2Three checks on the words, before you save the file
1. Write the rule with the nouns and verbs the file already uses. This is the highest-value item on the list and it costs nothing. The prover compares rules that land in the same slot, so your phrasing decides whether it can see a collision at all. Watch the same policy pass and fail depending on three extra words.
$ npx typeglish check bare.tg # - MUST promise a delivery date. bare.tg:19:1 error logic/contradiction Logical conflict — "promise a delivery date" is both required and forbidden. Keep one, or scope the two rules so they cannot both apply (IF <condition> THEN ...). (conflicts with line 12) ✗ 1 file — 2 error, 0 warning, 0 info $ npx typeglish check qualified.tg # - MUST promise a delivery date within 24 hours. ✓ 1 file — 0 error, 0 warning, 0 info
2. One action per rule. The ask arrived as a compound and the naive line kept it that way: promise a date and offer a discount. A compound rule cannot be individually scoped, tested, deleted or measured, and the checker will not complain, because a sentence with three verbs in it is legal English. This one is on you. Two policies means two lines.
3. Commit to a modal, and put the number in. The other thing that happens under time pressure is hedging your way out of a decision you did not want to make. Ops said a small discount, so you write should probably offer a small discount, which reads like caution and lands as permission to skip the rule entirely.
hedge.tg:23:3 info prompt/hedging Hedging — "SHOULD probably" turns this instruction into a suggestion the model may skip. Delete the hedge, or commit to a modal (MUST / NEVER / SHOULD). ✓ 1 file — 0 error, 0 warning, 1 info
info line, so it does not block and it does not fail your build. Worth reading anyway: a suggestion the model may skip is a precise description of what you shipped, and hardness drops from 100 to 86 on the score card because a statement takes the minimum over its force words.§3Four checks on the file, before you open the PR
4. Run check, then run check --strict. They give different answers and different exit codes, which means only one of them is your CI result. Strict escalates every IMPORTANT finding to a blocking error. The everyday case on an edit like this one is a tool you imported for the new rule and then never actually pointed at, because the rule ended up phrased as prose.
$ npx typeglish check refund.tg refund.tg:2:3 warn structure/unused-import Imported tool "issue_refund" is never used. ✓ 1 file — 0 error, 1 warning, 0 info # exit 0 $ npx typeglish check refund.tg --strict refund.tg:2:3 error structure/unused-import Imported tool "issue_refund" is never used. ✗ 1 file — 1 error, 0 warning, 0 info # exit 1
5. Compare the score to the number this file scored yesterday, not to a grade floor. A grade floor is a launch gate. It cannot see a regression, because there are eleven points of room between an A and a B and a year of small edits fits in there comfortably. Put the previous number in the command.
$ npx typeglish score hedge.tg --min B hedge.tg — A (93/100) proven errors: none tiers: base+z3 planes runtime 91 (what the model reads) · hygiene 100 (source only) # exit 0 - passes $ npx typeglish score hedge.tg --min 95 typeglish score: 93 (A) is below the --min floor 95 # exit 1 - caught
--min takes a grade or a number. Use the number, keep it in the repo next to the prompt, and raise it when a change earns it. A ratchet is the only version of this gate that keeps working after month three.6. Look for what your rule did to the rules already there. A new line does not only get judged; it changes the standing of its neighbours. Two failures show up constantly on edits. The first is restating something the file already says, at a weaker strength, because you did not know it was there.
$ npx typeglish check softer.tg # - SHOULD ask for the %order number%. softer.tg:23:3 error logic/force-subsumption Subsumed on the obligation axis: line 17 already guarantees this rule ("always" entails "should" for the same action), so it adds nothing but waver. Delete it, or give it a genuinely distinct scope. ✗ 1 file — 1 error, 0 warning, 0 info
The second is arithmetic. Your rule carries a number, the file carries numbers, and the two only have to be checked against each other once, which is now.
$ npx typeglish check longer.tg # - MUST explain the delay in at least 5 sentences. longer.tg:15:1 error logic/numeric Numeric conflict — "at most 3 sentences" and "at least 5 sentences" can't both hold. (conflicts with line 12) longer.tg:23:1 error logic/numeric Numeric conflict — "at most 3 sentences" and "at least 5 sentences" can't both hold. (conflicts with line 8) longer.tg:23:1 info prompt/unintroduced-definite "the delay" retrieves something this document never introduces - a model must guess which delay is meant. ✗ 1 file — 2 error, 0 warning, 1 info
7. Cover the new rule with a $TEST, and read the coverage number rather than the tick. A passing suite that never exercises your rule tells you nothing about your rule. Coverage attribution follows the words, so an expectation phrased in the rule's own language attributes to it while a bare assert often attributes to nothing.
$ npx typeglish test orders.tg --dry # one case, one bare assert ✓ orders.tg coverage: 0/3 rules exercised · late_order — "My order was supposed to arrive Tuesday and it is still not " (not run) ✓ at most 3 sentences ✓ 1 prompt — 0 failed $ npx typeglish test orders.tg --dry # two cases, asserts + prose in the rules' words ✓ orders.tg coverage: 2/4 rules exercised · late_order — "My order was supposed to arrive Tuesday and it is still not " (not run) ✓ at most 3 sentences ✓ rubric 0.00 — not run (--dry) · late_shipment — "My order still has not shipped and it is three days past the" (not run) ✓ contains "24 hours" ✓ rubric 0.00 — not run (--dry) ✓ 1 prompt — 0 failed
--dry is fully offline and needs no API key, so this belongs in the same CI step as check; the trade between deterministic asserts and judged prose is worked through in deterministic asserts vs. an LLM judge.§4One check on the artifact, before you merge
8. Build it and diff what the model actually receives. You edited source. The model reads a build artifact, with the annotations stripped, the tests removed, the name literals unwrapped and the declarations folded. The diff of that file is the real changelog of your edit, and it is usually shorter than you expect.
$ npx typeglish build orders.tg ✓ built .typeglish/dist/orders.txt ← orders.tg (1e612329ac3a, full) $ diff orders-before.txt .typeglish/dist/orders.txt 11a12,13 > - IF an order has passed its promised ship date THEN tell the customer that it ships within 24 hours. > - IF a goodwill offer is above the goodwill cap THEN escalate to a human agent.
@@ notes and a whole $TEST block went into the source in the same edit and cost the artifact zero bytes, which is the answer to whether documenting a rule is worth the tokens. The hash goes in your change record: it is how you later prove production was running this build and not somebody's hand-edit.§5The rule, rewritten
Run the list against Monday's ask and it stops being one line, because it was never one policy. It was a shipping communication and a goodwill authority, and the goodwill half is a decision above your pay grade: ops asked for ten percent in a file whose cap is five.
That is the item the checklist really earns. Not the typo, the escalation. Ten percent is either a new cap, which is one edit in one place with a sign-off attached, or it is an escalation path. It is not a number you quietly put in a second rule.
# Role @@ role: the addressee, so every rule below has a doer You are an order-support agent for Acme, an online retailer. # Facts @@ order: the record every conversation is about The %order number% IS a six-digit code. @@ total: the number the goodwill cap is a percentage of The %order total% IS the amount the customer paid at checkout. @@ goodwill_cap: above this an agent needs a human to sign off The %goodwill cap% IS at most 5 percent of the %order total%. # Constraints @@ brevity: three sentences keeps a chat reply scannable - MUST keep every response to at most 3 sentences. @@ ask_order: the order number unlocks account context - ALWAYS ask for the %order number%. @@ no_dates: a promised date the warehouse misses becomes a second complaint - NEVER promise a delivery date. @@ angry: a heated customer gets a human - IF the customer is angry THEN escalate to a human agent. @@ ship_window: a ship date is a warehouse fact; a delivery date is a courier guess, and only one of them is ours to promise - IF an order has passed its promised ship date THEN tell the customer that it ships within 24 hours. @@ goodwill_route: ops asked for 10 percent, which is above the cap, so this is an escalation and not a discount - IF a goodwill offer is above the %goodwill cap% THEN escalate to a human agent. $TEST late_order - input:: My order was supposed to arrive Tuesday and it is still not here. - expect:: - at most 3 sentences - asks for the order number $TEST late_shipment - input:: My order still has not shipped and it is three days past the ship date. - expect:: - contains "24 hours" - tells the customer that it ships within 24 hours
ship_window annotation is the load-bearing part of this edit. It records that a ship date and a delivery date are different promises, which is the distinction that lets this rule coexist with NEVER promise a delivery date rather than sneak past it. Without the note, the next person reads two rules about dates and deletes the wrong one.orders.tg — A (92/100) proven errors: none tiers: base+z3
planes runtime 89 (what the model reads) · hygiene 100 (source only)
facets enforceability 65 x.21 · hardness 100 x.12 · directness 90 x.08 · consistency 100 x.17
· structure 100 x.12 (hygiene) · annotation 100 x.12 (hygiene) · style 100 x.08 · security 100 x.08
lever enforceability 65/100 (up to +7 overall) — Write rules as MUST / NEVER <verb> … with
concrete bounds ("at most 3 sentences"), not vague qualities.
enforceability fell from 77 to 65: a conditional is inherently less enforceable than a bound, and this change added two of them. Item 5 did its job. It made you look, and then you accept it, because the alternative is an unconditional rule that would be wrong. A regression gate that you never override is set too loose to be useful.Eight items sounds like a lot until you notice that six of them are one command each and two are decisions. The realistic version is a script in the repo running check --strict, score --min <last>, test --dry and a build diff, so the machine half is a single invocation and your attention goes where it belongs: on whether the rule is phrased in the file's own words, and on whether anybody actually has the authority to approve ten percent. Every figure on this page is re-run against the real compiler by CI, including the ones showing a defect slipping through, so if a future release starts catching the qualified delivery promise, this post fails the build and gets rewritten.
FAQCommon questions
- How do I safely add a rule to a system prompt that is already in production?
- Treat the edit as a change to a running system rather than a piece of writing. Phrase the new rule with the nouns and verbs the file already uses, keep it to one action, run
checkand thencheck --strict, compare the score against the number the file scored before your edit rather than against a grade floor, look for an existing rule your new one now subsumes or contradicts, cover the rule with a$TESTand read the coverage number, and diff the built artifact so you can see the two lines you actually changed in what the model receives. The launch checklist proves the prompt is fit to ship once. This is the one you run on every edit afterwards. - Does typeglish check catch every problem with a new rule?
- No, and assuming it does is the trap. A one-line rule that promises a delivery date within 24 hours and offers 10 percent off compiles with 0 errors, 0 warnings and 0 info and scores A (93/100), in a file whose existing rules say
NEVER promise a delivery dateand cap goodwill at 5 percent. The prover only reaches a conflict when the two rules land in the same slot, so the qualifier within 24 hours is enough to make the prohibition invisible to it. A green check means nothing was proven, not that nothing is wrong. - What is the difference between typeglish check and check --strict?
- Plain
checkblocks on provable defects and reports everything else as a warning or an info line, so it exits 0. The--strictflag escalates every IMPORTANT finding to a blocking error, which changes the exit code and therefore your CI result. Importing a tool your new rule never actually points at is the everyday case:checkreports one warning and exits 0,check --strictreports it as an error and exits 1. Run both on an edit, because the warning you skim past today is the dead reference somebody deletes around next month. - Why did my prompt score go down after I added a correct rule?
- Usually because a conditional rule is less enforceable than a bounded one, and
enforceabilitycarries the heaviest weight on the score card at x.21. Adding two correctIF/THENrules to a clean prompt took our example from A (95/100) to A (92/100), with enforceability moving 77 to 65, and nothing was wrong with either new rule. That is what the regression check is for: it is a prompt to go and look at the reason, not an automatic veto. Accept the drop when the reason is sound, and write down why in an annotation so the next person does not re-litigate it.