← Tidelines/Guides

How to write escalation rules for an AI support agent

Escalation is where a support agent earns trust or loses it, and it is the part of the prompt most likely to be a vague sentence in the persona. This guide turns "escalate when needed" into rules the compiler can hold you to: a real handoff, scoped triggers that can't collide, tiered severity, and a test that fails if the handoff ever breaks.

by TypeGlish team7 min read#guides
Know when to hand off.

TL;DR Write escalation as a tool call (not a line in the persona), scope every trigger with WHEN/UNLESS so two rules can't require and forbid the same handoff, tier severity with a $IF chain, and pin the handoff with a $TEST. The checker proves the collisions (logic/contradiction) and fails a defined-but-unused escalation tool, so a broken handoff can't ship quietly.

Every support agent has an escalation policy. In most prompts it is one sentence, something like "escalate to a human when appropriate," sitting in the persona paragraph and doing almost nothing. It reads fine in review and fails in production, because "when appropriate" is not a trigger, "escalate" is not an action the model can be sure it took, and nothing checks that the two ever connect. Escalation is worth more rigor than that: it is the release valve for everything your agent should not be deciding alone. Here is how to write it so the compiler is on your side.

§1Make the handoff a tool, not a sentence

The first fix is to stop treating "escalate to a human" as prose. Prose is something the model reads and paraphrases; a tool is something it calls. Declare the escalation path as a real tool and point a WHEN rule at it, so the handoff is an action with a name and a schema instead of a suggestion.

escalation.tg✓ compiles
$IMPORT tool escalate_to_human

# Role
You are a support agent for a telecom provider.

# Constraints
- WHEN a customer explicitly asks for a person THEN call @[escalate_to_human].
The @[escalate_to_human] pointer ties the rule to the real tool the host runtime provides. If you declare the tool but never reference it, the checker flags a dead escalation path; if you reference a tool that was never declared, that is a dangling pointer. Either way the handoff can't silently go missing. This is the same discipline as making any tool discoverable, applied to the one tool you most need the model to reach for.

With that in place, "escalate when appropriate" becomes a list of concrete triggers, each its own WHEN rule pointing at the tool: an explicit request for a person, a trigger outside the agent's authority (a legal threat, a security concern, a refund over your approval limit), and the honest one every agent needs, WHEN you are unsure of a policy THEN escalate instead of guessing. Three rules, one tool, zero vibes.

§2Scope every trigger so two rules can't collide

The moment you have more than one rule about escalation, you can write two that fight. It happens the natural way: one sprint adds "always escalate billing disputes to a specialist," a later sprint decides the agent is empowered to handle small ones and adds "never escalate a billing dispute," and no one reads both lines together. In plain English these coexist quietly and the model picks a winner per conversation. In TypeGlish they are a proven contradiction.

escalation.tg✗ blocked
# Constraints
- MUST escalate a billing dispute to a specialist.
- You are empowered to resolve billing disputes; NEVER escalate a billing dispute to a specialist.
The two rules name the same action, one requiring it and one forbidding it, so the checker proves the conflict instead of guessing which the model will follow.
tg check - output
escalation.tg:2:1  error  logic/contradiction  Logical conflict - "escalate a billing
  dispute to a specialist." is both required and forbidden. Keep one, or scope
  the two rules so they cannot both apply (IF <condition> THEN ...). (conflicts with line 3)

 1 file - 2 error, 0 warning, 0 info
A blocking error, not a warning: this refuses to build. The fix the diagnostic names is exactly right, and it is the rule that makes escalation policies survive edits.

The fix is to give each rule a scope so the two can never fire on the same input. Escalation policy is almost always about a threshold, so put the threshold in the rule.

escalation.tg✓ compiles
# Constraints
- WHEN a billing dispute is over 200 dollars THEN escalate it to a specialist.
- WHEN a billing dispute is 200 dollars or less THEN resolve it yourself.
Now the two rules partition the input instead of overlapping it. The checker is satisfied because there is no dispute that triggers both. Every escalation rule you write should answer "over what?" before it ships. Contradictions are a maintenance property, covered in full in your prompt argues with itself.

§3Tier severity with a $IF chain

Thresholds handle one axis. Real escalation has levels: some things wait for a supervisor, some things page the on-call lead now. When precedence matters, a stack of loose prose conditionals leaves the ordering to the model. Hand it to the compiler instead with a $IF chain, which is ordered and first-true-wins by construction.

escalation.tg✓ compiles
$REQUIRE variable severity: one of low, high, critical

# Escalation
$IF @{severity} is equal to critical:
  Escalate to the on-call lead immediately.
$ELSE IF @{severity} is equal to high:
  Escalate to a supervisor within the hour.
$ELSE:
  Resolve the issue yourself.
The chain is evaluated deterministically: the losing arms never reach the model, so the prompt the agent runs on carries exactly one instruction. Use a $IF chain when the tiers are ordered and may lean on judgment; reach for a $SWITCH when they are members of one closed, typed set, the trade-off laid out in the prose conditionals vs $SWITCH bake-off.

§4Pin the handoff with a $TEST

You now have a real tool, scoped triggers, and tiered severity. One risk remains, and it is the quiet one: a future edit trims the prompt, the escalation rule goes with it, and every check stays green because a shorter prompt is still a valid prompt. The behavior you most need is the easiest to delete by accident. Pin it with a $TEST so the handoff has something watching it.

escalation.tg✓ compiles
$IMPORT tool escalate_to_human

# Role
You are a support agent for a telecom provider.

# Constraints
- WHEN a customer explicitly asks for a person THEN call @[escalate_to_human].

$TEST human_handoff
  - input:: Stop. I want to talk to a real person, not a bot.
  - expect::
    - calls the escalate_to_human tool
    - does not keep trying to resolve the issue itself
The input is an unambiguous handoff request; the expectation is that the agent hands off and stops. Delete the WHEN rule and the file still compiles, but typeglish test now has a failing case pointing straight at the missing behavior. That is the difference between hoping your agent escalates and knowing it does.

Put those four together and escalation stops being the soft spot in the prompt. The handoff is an action, not a phrase. The triggers are scoped, so they cannot argue. The tiers are ordered by the compiler, not the model's mood. And the whole thing is under test, so it survives the next person who edits the file. That is the entire job: take the one policy you least want the agent to improvise, and make it the most rigorously specified part of the prompt.

Field note

The @[tool] reference family, the logic/contradiction prover, the $IF chain, and $TEST suites all shipped in TypeGlish 0.1.0, and every .tg block on this page is re-checked against the real compiler by the CI guard on each build. Once your handoff is pinned, the next question is which of your other rules are actually load-bearing, which is exactly what pulling a good prompt apart, one rule at a time sets out to measure.

FAQCommon questions

When should an AI support agent escalate to a human?
Escalate on three triggers: an explicit request for a person, anything outside the agent's authority (legal threats, account security, high-value refunds), and low confidence, which is the "WHEN you are unsure THEN escalate" rule. Encode each one as a WHEN rule that calls a real escalation tool, not as a hope buried in the persona, so the handoff is an action the model actually takes.
How do I stop my escalation rules from contradicting each other?
Give every escalation rule a scope. Two rules that name the same action, one requiring it and one forbidding it, are a provable contradiction: the checker flags logic/contradiction and refuses to build. Scope them with WHEN or UNLESS so they cannot both fire on the same input, for example escalate a dispute over 200 dollars and resolve one at or under 200 dollars yourself.
Should escalation be a tool or an instruction?
A tool. "Escalate to a human" written as prose is a wish the model can paraphrase and never act on. Import or define an escalation tool and point a WHEN rule at it with an @[tool] reference, so the handoff is an action with a schema. The checker also fails a tool that is defined but never referenced, so a dead escalation path cannot ship unnoticed.
How do I test that my agent actually escalates?
Write a $TEST whose input is a clear escalation trigger, like "I want to talk to a real person," and whose expectation is that the agent calls the escalation tool and stops trying to resolve the issue itself. Run typeglish test and the case fails the moment a future edit weakens the handoff, so the behavior is pinned rather than trusted.
∿ washed up Jul 18, 2026 ∿