Why your agent promises the refund instead of issuing it
The transcript reads fine. Your refund has been approved and will be processed within five working days. Nothing was processed, no tool was called, and the agent was following the prompt exactly: the rule it read describes a refund happening, and never says who makes it happen.
TL;DR A rule with no subject gives the agent nothing to execute, so it narrates the outcome instead: TypeGlish flags the two mechanical shapes as prompt/agentless-passive and prompt/nominalized-process, and the third shape (It is important to ...) produces zero diagnostics while dropping directness from 50 to 15 and enforceability from 100 to 50 on the same instruction. Rewriting five policy sentences as five MUST <verb> rules moved one support prompt from D (54/100) to A (90/100).
Every contact-centre prompt has a Constraints section, and a good share of those sections were pasted from somewhere: a refunds policy, a QA rubric, the page of the ops wiki that describes what is supposed to happen. Those documents are written for humans who already know they are the ones doing it. They describe a process. An agent prompt has to assign one.
§1A prompt with nobody in it
Here is the refunds half of a broadband support prompt. Five rules, all of them true, none of them wrong about policy, and it has a tool wired up so the agent can actually move money.
<$CONFIG> $IMPORT tool issue_refund </$CONFIG> # Role You are a support agent for Northwind Broadband. # Constraints - A refund must be approved by a supervisor. - It is important to keep the customer informed throughout. - A review of the account notes should take place at the start of every contact. - Escalation to the retention team is required when a customer asks to cancel. - Every chat reply must be kept to at most 4 sentences.
Say each rule out loud with the words and I am the one doing it on the end. A refund must be approved by a supervisor, and I am the one doing it is not a sentence. Neither is the review, nor the escalation. Only the last rule, the one about reply length, actually lands on the agent, and it lands by accident: every chat reply must be kept to at most 4 sentences is about the replies, not about who writes them.
This is the whole failure mode. A model given a description of a process will produce a description of the process. It says the refund will be processed, because that is the register of the text it was handed.
doer-before.tg:2:3 warn structure/unused-import Imported tool "issue_refund" is never used. doer-before.tg:9:1 info prompt/agentless-passive The agent survives only in a by-phrase, demoted from the subject seat. Prefer the active: put the doer first. doer-before.tg:11:1 warn prompt/nominalized-process The action is packed into a noun and nobody performs it. Use the verb itself with a doer: "Review each refund." instead of "A review must take place." doer-before.tg:11:1 info prompt/unintroduced-definite "the account" retrieves something this document never introduces - a model must guess which account is meant. ... doer-before.tg:12:1 warn prompt/agentless-passive The doer is deleted (agentless passive) - who performs this? Name the actor or use the imperative: "Verify the order." instead of "The order is verified." doer-before.tg:12:1 info prompt/unintroduced-definite "the retention team" retrieves something this document never introduces - a model must guess which team is meant. ... doer-before.tg:13:1 warn prompt/agentless-passive The doer is deleted (agentless passive) - who performs this? Name the actor or use the imperative: "Verify the order." instead of "The order is verified." ✓ 1 file - 0 error, 4 warning, 3 info
The severity split is the interesting part. A refund must be approved by a supervisor still contains a supervisor, so the checker calls it a demotion rather than a deletion and files it as info: a reader can recover the actor. Escalation to the retention team is required contains nobody at all, and that is a warning. The grammar is doing exactly the work you would want a reviewer to do, and doing it on every line, every commit.
§2The line the checker cannot see
Count the lines in that output and one rule is missing. It is important to keep the customer informed throughout produced nothing. No warning, no info, and nothing under --strict either. It is the emptiest rule in the file and it is the only one the diagnostic list does not mention.
That is worth isolating, because it is the shape people reach for when they want a rule to sound serious. Two files, one rule each, the same instruction:
# Role You are a support agent for Northwind Broadband. # Constraints - MUST escalate every complaint to the retention team.
- It is important to escalate every complaint to the retention team. Both files check at 0 error and 0 warning. The scores are not close.active-one.tg - B (80/100) proven errors: none tiers: base+z3 planes runtime 90 (what the model reads) · hygiene 50 (source only) facets enforceability 100 x.21 · hardness 100 x.12 · directness 50 x.08 consistency 100 x.17 · structure 100 x.12 (hygiene) · annotation 0 x.12 (hygiene) style 63 x.08 · security 100 x.08 expletive-one.tg - C (70/100) proven errors: none tiers: base+z3 planes runtime 77 (what the model reads) · hygiene 50 (source only) facets enforceability 50 x.21 · hardness 100 x.12 · directness 15 x.08 consistency 100 x.17 · structure 100 x.12 (hygiene) · annotation 0 x.12 (hygiene) style 100 x.08 · security 100 x.08
There is a smaller detail in the same pair that says more about the mechanism than the numbers do. The active version earns one prompt/unintroduced-definite info, because the retention team is a definite reference to something the file never introduced. The expletive version earns nothing at all, on a line containing the same words. The checker did not decide that reference was fine. It never got far enough to have an opinion, because It is important to ... never registered an action for the reference to attach to.
Deleting the doer does not make the rule vague. It removes the rule from the plane where rules are checked.
So the practical rule for the gate: a clean check proves the absence of provable defects, and this family is mostly not provable. typeglish score --min B is the line of CI that catches it, because directness and enforceability are exactly the facets that ask whether a statement tells somebody to do something.
§3The tool nobody calls
One finding in that first run was not about grammar at all, and it is the loudest thing in the file: structure/unused-import on issue_refund. The tool is declared, the integration exists, the schema is right, and no rule in the prompt ever reaches it.
Of course it does not. A tool call is an action, an action needs a verb, and a verb needs a subject. Four of the five rules deleted theirs. The unused import is not a separate mistake, it is the shadow the missing doer casts, and it is the one finding in this whole family that a CI gate will stop.
doer-before.tg:2:3 error structure/unused-import Imported tool "issue_refund" is never used. doer-before.tg:9:1 info prompt/agentless-passive The agent survives only in a by-phrase ... doer-before.tg:11:1 warn prompt/nominalized-process The action is packed into a noun ... doer-before.tg:12:1 warn prompt/agentless-passive The doer is deleted (agentless passive) ... doer-before.tg:13:1 warn prompt/agentless-passive The doer is deleted (agentless passive) ... ✗ 1 file - 1 error, 3 warning, 3 info
--strict escalates every IMPORTANT finding, and exactly one of these five qualifies. The three doer warnings stay warnings. If your pipeline runs check --strict and nothing else, the only version of this bug it will ever stop is the version where you happened to import a tool.Which is a useful accident, and worth leaning on deliberately. An agent prompt whose imports are all used is a prompt in which something, somewhere, tells the agent to act. We wrote up the reverse case in why your agent won't use the tool you gave it: there the tool was mentioned but never pointed at, here it is not mentioned at all, and both end at the same place, with an integration your platform bill is paying for and your transcripts never touch.
None of this is resolved at build time either. The prose goes to the model exactly as written:
✓ built .typeglish/dist/doer-before.txt ← doer-before.tg (22f75a33e195, full) # Role You are a support agent for Northwind Broadband. # Constraints - A refund must be approved by a supervisor. - It is important to keep the customer informed throughout. - A review of the account notes should take place at the start of every contact. - Escalation to the retention team is required when a customer asks to cancel. - Every chat reply must be kept to at most 4 sentences.
$CONFIG block strips and the five sentences ship byte for byte. Whatever the tool registry says the agent can do, this is the document that decides whether it does anything.§4Put a doer in every rule
The rewrite is mechanical and it is not a style pass. Take each sentence, ask who performs it, and if the answer is the agent, make the agent the subject. If the answer is somebody else, the rule is not an instruction and it needs to become one: a refund must be approved by a supervisor is a fact about your org chart, and the instruction hiding inside it is ask a supervisor.
That question also finds the missing rule. Approval and payment are two actions in the policy sentence and one event in the reader's head, which is exactly why the tool went uncalled. Written out, they are two lines.
<$CONFIG> $IMPORT tool issue_refund </$CONFIG> # Role You are a support agent for Northwind Broadband. # Constraints @@ refund_authority: agents can approve up to the desk limit, above it a supervisor signs - MUST ask a supervisor to approve a refund when the amount is over 50 dollars. @@ refund_action: the approval is not the refund, somebody still has to move the money - MUST call @[issue_refund] when a supervisor approves a refund. @@ progress_updates: silence on a long lookup reads as a dropped chat - MUST tell the customer what you are doing when a lookup takes over 30 seconds. @@ notes_first: the last agent already asked the questions you are about to ask - MUST read the account notes before you answer the first question. @@ retention_path: cancellations are the one contact type with a human queue behind them - MUST escalate to the retention team when a customer asks to cancel. @@ brevity: chat replies over 4 sentences stop being read - MUST keep every chat reply to at most 4 sentences. $TEST refund_reaches_the_tool - input:: My supervisor already approved a 80 dollar refund on order 4412. - expect:: - at most 4 sentences $TEST cancel_goes_to_retention - input:: I want to cancel my broadband today. - expect:: - at most 4 sentences
doer-after.tg - A (90/100) proven errors: none tiers: base+z3 planes runtime 90 (what the model reads) · hygiene 93 (source only) facets enforceability 85 x.21 · hardness 100 x.12 · directness 75 x.08 consistency 100 x.17 · structure 100 x.12 (hygiene) · annotation 86 x.12 (hygiene) style 68 x.08 · security 100 x.08 lever enforceability 85/100 (up to +3 overall) - Write rules as MUST / NEVER <verb> ... with concrete bounds ("at most 3 sentences"), not vague qualities. ✓ doer-after.tg coverage: 2/6 rules exercised · refund_reaches_the_tool - "My supervisor already approved a 80 dollar refund on order 4" (not run) ✓ at most 4 sentences · cancel_goes_to_retention - "I want to cancel my broadband today." (not run) ✓ at most 4 sentences
structure/unused-import is gone, not because it was silenced but because a rule now calls the tool.The score is the smaller half of the result. The larger half is that six rules with subjects are six things a $TEST can be pointed at, and coverage can report on. Escalation to the retention team is required was never testable, because there was no actor whose behaviour a case could observe.
§5The sentences to grep for
You do not need the compiler to start on an existing prompt. Four patterns account for nearly all of it, and three of them are literally searchable:
It is important / essential / critical to ...- the dummy subject. Delete the frame, keep the verb, add a modal. This is the one no diagnostic will find for you.... is required / is expected / should be ...- the deleted actor. Ask who, and put them in front.A review / a check / verification of ... takes place- the action packed into a noun. The verb is right there inside the noun; use it.... must be approved by a supervisor- the demoted actor, surviving in a by-phrase. Softest of the four, and still worth flipping, because the rule is usually not about the supervisor at all. It is about what the agent does next.
The reason this concentrates in pasted text is that policy documents genuinely should be written that way. A refunds policy is not addressed to anybody in particular, which is what makes it a policy. The policy doc somebody pasted into your agent arrives with that voice intact, and the paste is a translation job nobody bills for: from a document that describes what happens, into a document that tells one party what to do.
§6Common questions
- Why does my agent say it will do something instead of doing it?
- Because the rule it is following does not say who acts.
A refund must be approved by a supervisornames an event with no agent in it, so the model has nothing to execute and reports the event instead. The fix is not a firmer modal, it is a subject:MUST ask a supervisor to approve a refundtells the agent what to do, andMUST call the refund tool when a supervisor approvestells it that approval and payment are two separate actions. TypeGlish flags the deleted doer asprompt/agentless-passiveand the noun-packed action asprompt/nominalized-process. - Should I avoid passive voice in a system prompt?
- Avoid the agentless passive specifically, which is the passive with no by-phrase at all. The problem is not the grammar, it is the missing subject:
Escalation to the retention team is required when a customer asks to canceldoes not say that the agent escalates, so it reads equally well as background about how the company works. A passive that keeps its doer is far less dangerous, and TypeGlish grades it that way, reporting the by-phrase form as info rather than warn. - Does the checker catch every rule with no doer in it?
- No, and the gap is worth knowing.
It is important to keep the customer informed throughoutproduces zero diagnostics ontypeglish check, including under--strict. The score is where it shows: that single line as a whole file scores C (70/100) with directness 15 and enforceability 50, against B (80/100) with directness 50 and enforceability 100 for the same instruction written asMUST. Gate ontypeglish score --min B, not on the diagnostic list alone. - Why is my agent tool never called?
- Check whether any rule contains a verb whose subject is the agent. A tool is wired up by a rule that tells the agent to call it, so a Constraints section written entirely in policy prose imports a tool that nothing reaches. TypeGlish reports this as
structure/unused-import, and it is the one finding in this family thattypeglish check --strictescalates to a blocking error, which makes it the cheapest CI signal that your prompt describes work rather than assigning it.
The doer family is the reason a brief and a prompt are different documents, which is the thing we kept running into while building a cancellation-save agent, prompt-first: typed straight in, the head of CX's five sentences landed on prompt/agentless-passive at the cancellation should always be honoured in the end, a line everybody in the room agreed with and nobody could execute. Briefs describe outcomes. Prompts assign actions. typeglish --explain prompt/agentless-passive is a fast way to see which of yours is which.