The arithmetic in your prompt
Prompts are full of numbers: at most three sentences, at least two options, call one tool. Writers treat them as emphasis. The checker treats them as constraints it can actually solve, which means it can catch the ones that add up to nothing.
TL;DR Every number in a prompt is a constraint, not a suggestion. When two of them can't both be true, like at most 3 sentences and at least 5 sentences, the model quietly satisfies one per reply and the other looks ignored. TypeGlish reads the numbers as real inequalities and proves the conflict at compile time with logic/numeric, so you fix it before it ships.
Ask a builder why their agent's replies keep blowing past the length limit and they will usually blame the model. Sometimes that is fair. More often the prompt contains two numbers that cannot both be honored, and the model is doing the only thing it can: picking one, differently, every time. A number in a prompt is not decoration and it is not emphasis. It is a claim about the shape of a valid answer, and like any claim it can be checked, and like any pair of claims it can be inconsistent. Most prompt tools cannot see that far, because to them "at most 3" is just three words. To a checker with a solver behind it, it is an inequality.
§1A number is a promise the checker can hold
There are two ways to write a magnitude, and only one of them is checkable. "Keep replies short" names a feeling; nothing can hold the model to it and nothing can hold you to it either, which is why it drifts. "Reply in at most 3 sentences" names a bound. The difference is not style. A bound is a value a checker can compare, count against, and reason about; a vibe is invisible to every tool you own. The moment you commit to a number, you have handed the compiler something it can actually work with, including the ability to tell you when you have committed to two numbers that fight.
A vague magnitude constrains nothing. A precise one can be proven inconsistent. Only one of those is a spec.
§2Two limits, one reply
Here is how it happens in real prompts, and it is never on purpose. Someone adds a brevity rule for scannability. Months later, someone else adds a thoroughness rule for the returns flow. Both are sensible. Together they demand a reply that is at most three sentences and at least five, on every message, which is no reply at all.
# Role You are a support agent for an online electronics retailer. # Constraints @@ brevity: replies over three sentences get skimmed - MUST keep every reply to at most 3 sentences. @@ thorough: a returns explanation has to cover the conditions - MUST answer in at least 5 sentences.
A prose linter cannot catch this, because there is nothing wrong with either sentence. You need something that reads the numbers as numbers. TypeGlish hands both bounds to Z3, its solver, asks whether any value satisfies them at once, and gets back "no." That "no" is a proof, not a heuristic, so it is a blocking error rather than a warning.
support.tg:6:1 error logic/numeric Numeric conflict - "at most 3 sentences" and "at least 5 sentences" can't both hold. support.tg:8:1 error logic/numeric Numeric conflict - "at most 3 sentences" and "at least 5 sentences" can't both hold. ✗ 1 file - 2 error, 0 warning, 0 info
§3The fix is a decision, not a bigger number
The wrong instinct is to nudge a number until the error goes away. The right one is to notice the checker has surfaced a decision you never actually made: which rule governs which reply. There are two honest answers. Reconcile the bounds into one satisfiable band, or scope them so they never apply to the same message. Scoping keeps both intentions, brevity for routine replies and depth for the returns explanation, without asking a single reply to be two lengths at once.
# Role You are a support agent for an online electronics retailer. # Constraints @@ brevity: a routine reply over three sentences gets skimmed - MUST keep a routine reply to at most 3 sentences. @@ thorough: a returns explanation has to cover the conditions - WHEN explaining the return policy THEN answer in at least 5 sentences.
✓ 1 file - 0 error, 0 warning, 0 info
§4The rest of the arithmetic
Length bounds are the most common case, but the same solver reasons about every quantity you put in a prompt. It is worth knowing what else it can prove, because these are the numbers that break agents quietly:
- Action counts (
logic/action-count) - one action given two different counts, like "call five tools" and "call six tools" for the same step. The agent cannot do both. - Set cardinality (
logic/cardinality) - two counts for one set that cannot both hold, like "there is only one escalation path" and "there are many escalation paths." - Insufficient sets (
logic/insufficient-set) - a directive that needs more items than the set actually holds, like "offer three alternatives" when only two are defined.
They share a shape with the length case: each is a claim about a quantity, each is invisible to a reader skimming for tone, and each is decidable the instant you treat the numbers as numbers. That is the whole move. Vague magnitudes ask the model to guess and let it guess differently every time. Precise ones let a solver check your work, and occasionally tell you that the work does not add up, which is the most useful thing a spec can do before it ships.
The logic/numeric proof is Z3-backed and shipped in TypeGlish 0.1.0. A numeric conflict is the arithmetic cousin of the modal conflicts in your prompt argues with itself: same idea, different operator, both proven rather than guessed. And the reason vague magnitudes never get caught is the reason to write measurable rules in the first place, which is the before-and-after in the rewrite of a bloated support prompt.
FAQCommon questions
- Why does my agent ignore the length limit in my prompt?
- The usual cause is a second rule that contradicts the first. If one rule says at most 3 sentences and another says at least 5, no output satisfies both, so the model picks one per reply and the limit looks ignored. A vague limit like "keep it short" has the opposite problem: there is no number to hold it to. Give every length rule a concrete bound and make sure two bounds cannot both fire on the same reply.
- Can I set both a minimum and a maximum length in a system prompt?
- Yes, as long as the minimum is not greater than the maximum and the two apply to the same situation. At least 2 and at most 5 sentences is a satisfiable band. At least 5 and at most 3 is a numeric impossibility, and TypeGlish rejects it at compile time with
logic/numeric. If you want a short default but a longer answer for one case, scope the longer bound with aWHENso the two never apply to the same reply. - How do I stop two rules in my prompt from contradicting each other on length?
- Decide which rule wins instead of shipping both and hoping. Either reconcile the numbers into one satisfiable band, or scope them so they never fire together, for example at most 3 sentences for a routine reply and
WHENexplaining the return policyTHENat least 5 sentences. Runningnpx typeglish checkproves whether any two numeric rules can both be true; if they cannot, it fails the build withlogic/numericand names the two numbers. - What is the difference between at most and at least in TypeGlish?
- They are inclusive numeric bounds. "At most 3" means 3 or fewer; "at least 5" means 5 or more. The checker reads them as real inequalities and solves them, so it can prove when a set of bounds has no solution (at most 3 and at least 5 cannot both hold) rather than treating the words as decoration. That is why a numeric conflict is a blocking error, not a style warning.