> Markdown rendition of https://typeglish.dev/blog/shorten-agent-prompt ("How to shorten an agent prompt without losing a rule - Tidelines"). Canonical page: https://typeglish.dev/blog/shorten-agent-prompt · All pages: https://typeglish.dev/llms.txt

[← Tidelines](https://typeglish.dev/blog)/ Guides Oct 10, 2026

# How to shorten an agent prompt without losing a rule

Somebody wants the prompt shorter: the voice team wants the latency back, finance wants the bill down, the new hire cannot find anything. Cutting is easy. Knowing what you cut is the part nobody does.

by **TypeGlish team** 8 min read #guides

Shorter is a claim.

**TL;DR** Before you shorten an agent prompt, freeze the long version with typeglish prepare-rewrite, map every old line to the new line that carries it, and let typeglish review-rewrite name the rule your cut dropped, because the shorter draft will compile clean and score well either way.

Pellow Broadband runs a chat assistant called Wren. Its prompt has been edited by four people over a year, and like most prompts that age it says some things three times and one thing in a way nobody notices. This guide cuts it by about a third, drops a rule on the first try, and catches it.

## §1 Read what the long one actually says

wren.tg - a year of edits ✓ compiles

```typeglish
# Role
You are Wren, the chat support assistant for Pellow Broadband, a home internet provider.

# Constraints
- MUST keep every reply to at most 3 sentences.
- NEVER state an install date.
- WHEN the customer reports an outage THEN MUST call @[check_outage].
- It is absolutely essential that you MUST verify the identity of the customer.
- You MUST always be very, very careful to NEVER state an install date.
- Please make sure that you always escalate to a human agent when the customer asks for one.
- Keep replies short and simple, and keep them friendly.
- IF the customer asks to cancel THEN MUST call @[log_cancellation].

# Final reminders
- MUST keep every reply to at most 3 sentences.
- NEVER state an install date.

$TOOL check_outage
  - description:: Check for a known outage at the customer's postcode.
  - input::
    - postcode:: string: the customer's postcode.

$TOOL log_cancellation
  - description:: Record a cancellation request for the retention team.
  - input::
    - reason:: string: the reason the customer gives.
```

Sixteen lines of prompt. The install-date rule appears three times, the sentence cap twice, and the Final reminders section exists because someone read that models pay more attention to the end.

Before cutting anything, ask the checker which of these lines are rules and which are words around rules. The score's rules table answers that line by line:

tg score - wren.tg ⚠ C (66/100)

```
$ typeglish score wren.tg
wren.tg - C (66/100)  proven errors: none  tiers: base+z3
  planes  runtime 72 (what the model reads) · hygiene 50 (source only)
  facets  enforceability 81 x.21 · hardness 100 x.12 · directness 92 x.08 · consistency 0 x.17 · structure 100 x.12 (hygiene) · annotation 0 x.12 (hygiene) · style 100 x.08 · security 100 x.08
  lever   consistency 0/100 (up to +17 overall) - 4 findings below (L5 L6 L15 L16) - Fix the ledger rows with logic/ or clarity/ codes; state each fact in one place.
  rules   7 of 10 rule-shaped lines read · 1 not provable
    L8   = fact          It is absolutely essential that you MUST verify the identity of the customer.
                         a declared fact, not a rule - the world model reads it; it has no modal to enforce
    L9   ~ unprovable    You MUST always be very, very careful to NEVER state an install date.
                         "always" is not a verb the checker knows → use a verb from the catalog (redirect, escalate, ask, cite …) or add a numeric bound
    L10  ✗ invisible     Please make sure that you always escalate to a human agent when the customer asks for one.
                         no modal (MUST / NEVER / SHOULD) and "Please" is not a verb the checker knows, so it reads as prose → lead with a modal, or start with a verb from the catalog (Escalate …, Ask …)
    L11  ✗ invisible     Keep replies short and simple, and keep them friendly.
                         no modal (MUST / NEVER / SHOULD), and the checker knows "keep" but cannot prove this shape: two objects or actions joined by "and" - it proves one at a time, so it reads as prose → lead with a modal (MUST …) to make it a rule, and one object per line: split into two rules to make it provable
  L5  clarity/duplicate            −1  Duplicate rule - "keep every reply sentence" is required in 2 places (also lin
  L6  clarity/duplicate            −1  Duplicate rule - "state install date" is forbidden in 2 places (also line 16).
  L15  clarity/duplicate            −1  Duplicate rule - "keep every reply sentence" is required in 2 places (also lin
  L16  clarity/duplicate            −1  Duplicate rule - "state install date" is forbidden in 2 places (also line 6).
```

Four duplicate findings take consistency to zero. Lines 8 to 11 are the interesting ones: each is a rule wearing something that is not a rule.

That table is the cutting plan. It sorts the prompt into three piles.

**Copies.** Lines 15 and 16 restate lines 5 and 6, and the checker flags both pairs as `clarity/duplicate`. Line 9 is a third copy of the install-date rule that the checker does not count as one, because the checker takes *always* as the verb after `MUST`, finds no such verb, and marks the line unprovable rather than reading the `NEVER` buried behind *be very, very careful to*. You can see it is a copy. The checker cannot. Keep that in mind; it comes back in §5.

**Wrappers.* It is absolutely essential that you* turns line 8 into a declared fact: the checker reads *It is ...* as a statement about something called It. *Please make sure that you always* puts a word that is not a modal or a catalog verb at the head of line 10, and the whole line reads as prose. The wrapper is safe to cut. The act inside it is not.

**Rules.** Everything else, plus the acts inside the wrappers. Line 10 is the one to watch: it is the only place the prompt says a customer can ask for a person, and it looks exactly like the polite filler around it. If you have read [How to mark a rule as important in an agent prompt](https://typeglish.dev/blog/mark-rule-important), this is the same failure from the other direction: a label hides a rule from the checker, and it hides it from the person cutting too.

## §2 Freeze a baseline before you touch anything

The usual way to shorten a prompt is to open it in an editor and start deleting. The version you started from survives only in git history and your memory of it. `typeglish prepare-rewrite` makes the starting point explicit: it reads the prompt, numbers every statement, and binds all of it to a snapshot ID. It is read-only and calls no model.

tg prepare-rewrite - wren.tg ✓ 11 statements

```
$ typeglish prepare-rewrite wren.tg | sed -n '1,12p'
wren.tg
Snapshot tg1-3d25c2d7-f351068b · 11 statements
Read-only rewrite context; partial observations are not proof of meaning preservation.
TG score: C 66; estimated compiled tokens: 174
Aim for an A grade and fewer compiled prompt tokens. Treat 30–50% reduction as a stretch target, never a reason to drop requirements.
Resolve contradictory policies with the owner before rewriting those policies. Do not invent a priority or turn SHOULD into MUST to improve the score.
Rewrite related statements together using the complete original context. Preserve actors, actions, conditions, exceptions, quantities, order, references, literals and runtime inputs.
Use redundancy evidence to locate consolidation candidates. Overlap scores alone do not authorize deleting a statement.
Apply clear sections without changing scope or execution order. Keep ambiguous dependencies together.
Generate or refresh your own annotations after wording is final. Preserve authored notes unless their owner requests a change.
Prepare the candidate, map every original and candidate occurrence, and review-rewrite against the saved baseline. Address revision tasks and recheck the frozen candidate.
Verify representative and adverse scenarios against both versions. A high score, shorter output or complete mapping is not proof of behavioral equivalence.
$ typeglish prepare-rewrite wren.tg --json > baseline.json
```

The human-readable form is a brief for whoever does the cut, person or coding agent. The `--json` form is the baseline the review compares against. Save it before the first edit.

Read the brief once, because it is a better shortening policy than most teams write down. *Never a reason to drop requirements. Overlap scores alone do not authorize deleting a statement. Do not invent a priority or turn SHOULD into MUST to improve the score.* If you hand the cut to a coding agent, hand it this output with the file.

The baseline is bound to the exact source, configuration and compiler version. Edit `wren.tg` after saving it and the review refuses to run against a stale picture:

tg review-rewrite - one line added to the source after the baseline ✗ exit 2

```
invalid · binding stale · mapping invalid
Source tg1-13ebb242-1c59a720 → candidate tg1-230b90f3-b7f849c5
Baseline is stale: source, configuration or compiler version differs. Prepare the current source again.
```

Exit 2 is a refused request, not a finding. Re-prepare whenever the source moves.

## §3 Cut, then account for every line

Here is the first cut. It is what most of us would write in ten minutes: one copy of each rule, no wrappers, the two-part keep-it-short line reduced to the part the sentence cap does not already cover.

wren.short.tg - the first cut ✓ B (87/100)

```typeglish
# Role
You are Wren, the chat support assistant for Pellow Broadband, a home internet provider.

# Constraints
- MUST keep every reply to at most 3 sentences.
- MUST keep every reply friendly.
- NEVER state an install date.
- WHEN the customer reports an outage THEN MUST call @[check_outage].
- MUST verify the identity of the customer.
- IF the customer asks to cancel THEN MUST call @[log_cancellation].

$TOOL check_outage
  - description:: Check for a known outage at the customer's postcode.
  - input::
    - postcode:: string: the customer's postcode.

$TOOL log_cancellation
  - description:: Record a cancellation request for the retention team.
  - input::
    - reason:: string: the reason the customer gives.
```

0 errors, 0 warnings, 0 info. Every rule-shaped line reads. It looks finished.

By every number the checker prints, this is a better prompt: C (66) to B (87), no findings. It is also missing the only rule that lets a customer reach a person. Nothing in `check` or `score` can tell you that, because both of them look at the file you have. A deleted rule leaves nothing behind to flag.

The review step looks at both files. To run it, you write down where each source statement went: a mapping file of groups, each naming source statement IDs, the candidate statement IDs that now carry them, and a reason. You get the candidate IDs the same way as the baseline, by running `prepare-rewrite` on the candidate. Three of the seven groups for this cut:

mapping.json - three of seven groups

```
  {"sourceIds": ["tg1-3d25c2d7-f351068b:statement:111", "tg1-3d25c2d7-f351068b:statement:650"], "candidateIds": ["tg1-5b916899-60c1c70b:statement:111"], "reason": "the sentence cap, stated twice, kept once"},
  {"sourceIds": ["tg1-3d25c2d7-f351068b:statement:159", "tg1-3d25c2d7-f351068b:statement:340", "tg1-3d25c2d7-f351068b:statement:698"], "candidateIds": ["tg1-5b916899-60c1c70b:statement:193"], "reason": "one prohibition, stated three times, kept once"},
  {"sourceIds": ["tg1-3d25c2d7-f351068b:statement:260"], "candidateIds": ["tg1-5b916899-60c1c70b:statement:294"], "reason": "emphasis removed, same act"},
```

Several source lines may map to one candidate line; that is how a consolidation is declared. Each candidate line can sit in only one group, and the review rejects a mapping that reuses one.

Writing the mapping is where most of the value is, because you have to find a home for every source line by hand. If you skip a line, the review notices:

tg review-rewrite - the first cut ✗ mapping incomplete

```
$ typeglish review-rewrite wren.tg --candidate wren.short.tg --baseline baseline.json --mapping mapping.json | sed -n '1,4p'
wren.tg
invalid · binding current · mapping incomplete
Source tg1-3d25c2d7-f351068b → candidate tg1-5b916899-60c1c70b
Estimated rendered-token reduction: 0.46551724137931033
$ echo $?
2
$ typeglish review-rewrite wren.tg --candidate wren.short.tg --baseline baseline.json --mapping mapping.json --json | jq '.review.mapping | {status, unmappedSourceIds, unmappedCandidateIds}'
{
  "status": "incomplete",
  "unmappedSourceIds": [
    "tg1-3d25c2d7-f351068b:statement:412"
  ],
  "unmappedCandidateIds": []
}
$ typeglish statements wren.tg --statement tg1-3d25c2d7-f351068b:statement:412 | sed -n '3,4p'
[tg1-3d25c2d7-f351068b:statement:412] line 10
  - Please make sure that you always escalate to a human agent when the customer asks for one.
```

One source statement has nowhere to go, and it is line 10. Exit 2 means a CI step that runs this review fails the build.

Notice the reduction estimate on the failing draft: about 47 percent. That is the best number in this whole guide, and it belongs to the broken version. When a cut looks unusually good, the missing rule is often part of why.

> Check and score read the prompt you have. Only a review against the old one can see the rule you deleted.

## §4 Put the rule back in a shape that reads

The fix is not to restore line 10 as written. It was invisible to the checker before the cut and it would be invisible after. Strip the wrapper, make the trigger a condition, keep the force: *always* becomes `MUST`, and *when the customer asks for one* moves to the front as a `WHEN`. While the file is open, add the `@@` notes and a couple of test cases. Both are stripped before the model reads anything, so they cost you nothing on the token budget you are trying to cut.

wren.short.tg - the cut, with the rule back ✓ A (100/100)

```typeglish
# Role
@@ role: one chat assistant, one provider
You are Wren, the chat support assistant for Pellow Broadband, a home internet provider.

# Constraints
@@ brevity: three sentences fits the chat widget without scrolling
- MUST keep every reply to at most 3 sentences.
@@ tone: the friendly half of the old keep-it-short line
- MUST keep every reply friendly.
@@ no_install_dates: dates come from the field team, never from chat
- NEVER state an install date.
@@ outage_tool: an outage report is checked, not guessed
- WHEN the customer reports an outage THEN MUST call @[check_outage].
@@ identity: no account detail before the identity check
- MUST verify the identity of the customer.
@@ human_on_request: the line the first cut dropped
- WHEN the customer asks for a human agent THEN MUST escalate to a human agent.
@@ cancellation: retention works from the logged reason
- IF the customer asks to cancel THEN MUST call @[log_cancellation].

$TOOL check_outage
  - description:: Check for a known outage at the customer's postcode.
  - input::
    - postcode:: string: the customer's postcode.

$TOOL log_cancellation
  - description:: Record a cancellation request for the retention team.
  - input::
    - reason:: string: the reason the customer gives.

$TEST human_on_request
  - input:: Can I just talk to a person please?
  - expect::
    - escalates to a human agent

$TEST no_install_date
  - input:: When is the engineer coming to install my line?
  - expect::
    - does not state an install date
    - at most 3 sentences
```

Seven rules, all seven read. The tests sit on the two rules the cut changed most: the one it dropped, and the one it merged from three copies.

Prepare the new candidate for its IDs, add the eighth group to the mapping, and run the review again:

tg review-rewrite - the fixed cut ✓ mapping complete

```
$ typeglish review-rewrite wren.tg --candidate wren.short.tg --baseline baseline.json --mapping mapping.json
wren.tg
changes-found · binding current · mapping complete
Source tg1-3d25c2d7-f351068b → candidate tg1-230b90f3-b7f849c5
[...]
[preservation] tg1-230b90f3-b7f849c5:revision:6
Source tg1-3d25c2d7-f351068b:statement:412 → candidate tg1-230b90f3-b7f849c5:statement:739
[...]
  Before [412:504]: - Please make sure that you always escalate to a human agent when the customer asks for one.
  After [739:818]: - WHEN the customer asks for a human agent THEN MUST escalate to a human agent.
Statement order or structural context changed. Recheck condition scope, reference targets and sequencing.
Source-backed reference observations changed. These are partial reader observations; verify their scope in the original text.
  Before [436:439]: you
Source-backed force observations changed. These are partial reader observations; verify their scope in the original text.
  Before [440:446]: always
  After [787:791]: MUST
Source-backed quantity observations changed. These are partial reader observations; verify their scope in the original text.
  Before [500:503]: one
Source-backed condition observations changed. These are partial reader observations; verify their scope in the original text.
  After [741:745]: WHEN
  After [746:782]: the customer asks for a human agent
[...]
Estimated rendered-token reduction: 0.3448275862068966
Candidate TG score: A 100
[...]
$ echo $?
0
```

Trimmed at the `[...]` marks; the full report runs one block per mapped group. Status `changes-found` with exit 0 is the passing state: every line is accounted for, and here is what changed in each.

Read the block for the escalation rule, because it is the review doing its real job. It does not say the rewrite is right. It says what moved: the force word was *always* and is now `MUST`, a condition appeared that was not there, and the quantity *one* (from *asks for one*) is gone. Each of those is a question for you. Is `MUST` the same force as *always*? Yes, that was the intent. Is *asks for a human agent* the same trigger as *asks for one*? Yes, *one* referred to a human agent. You answer each cue, and then you have a reason to believe the cut, not just a shorter file.

The final cut is about 34 percent smaller by the review's estimate, inside the 30 to 50 percent range the brief calls a stretch target, and it went from C (66) to A (100).

## §5 What the review does not sign for

The review closes with six lines that are worth taking literally. Two of them:

tg review-rewrite - the closing notices, two of six

```
Mappings are agent assertions. Matching observations, diagnostics or scores does not establish semantic equivalence.
Rendered token counts are estimates (words × 1.33). Scores are compiler observations, not behavioral quality or rewrite safety.
```

A complete mapping proves that you put every line somewhere. It does not prove you put it in the right place. Look at the group for the old keep-it-short line, mapped to *MUST keep every reply friendly* with the reason *short is the sentence cap; friendly keeps its own rule*. That reason is honest about *short* and *friendly*. It says nothing about *simple*. The review lists the before and after text side by side, and the word is plainly missing from the after, but the mapping is complete, so nothing fails. Dropping it was a decision. Make it on purpose, with whoever owns tone, or put it back.

The same goes for the copies the checker could not see. Line 9, the *very, very careful* line, is mapped into the install-date group because a person read it and recognised the third copy. Had it really been a different rule, say *NEVER state an install fee*, mapped into the same group, the review would still have passed: `changes-found`, mapping complete, exit 0, with the fee line printed under Before for anyone who reads that far. The mapping is yours. Write each reason as if someone will read it in an incident review, because one day someone will.

And then test. The two cases above are the cheapest proof that the cut still does what the long version did on the lines you rewrote most:

tg test --dry - wren.short.tg ✓ 0 failed

```
$ typeglish test wren.short.tg --dry
✓ wren.short.tg  coverage: 3/7 rules exercised
  uncovered (no case shares the rule's wording):
    L9  keep every reply friendly.
    L13  call @[check_outage].
    L15  verify the identity of the customer.
    L19  call @[log_cancellation].
  · human_on_request - "Can I just talk to a person please?" (not run)
      · rubric - 1 prose expectation, judged on a live run (needs ANTHROPIC_API_KEY)
  · no_install_date - "When is the engineer coming to install my line?" (not run)
      ✓ at most 3 sentences
      · rubric - 1 prose expectation, judged on a live run (needs ANTHROPIC_API_KEY)
✓ 1 prompt - 0 failed
```

Three of seven is not full coverage, and the dry run says so by name. The cases go where the cut did the most damage first; the four uncovered rules came through unchanged and are next.

If the cut is big enough that you want a second opinion on the method itself, [Rewrite: a bloated support prompt, cut to rules that check](https://typeglish.dev/blog/rewrite-bloated-support-prompt) covers the rewriting half. This guide is the accounting half: the rewrite can be as aggressive as you like, as long as every line it removes has a named place it went.

## §6 Common questions

**How do I make my system prompt shorter without breaking my agent?**

Freeze a baseline of the long prompt with typeglish prepare-rewrite, write the shorter candidate, and map every source statement to the candidate statement that now carries it. typeglish review-rewrite then exits 2 and reports the mapping as incomplete if any source line has nowhere to go, which is how a dropped rule shows up before it ships.

**Which parts of a support agent prompt are safe to cut?**

Copies of a rule you state elsewhere, emphasis wrappers such as It is absolutely essential that, and politeness padding such as Please make sure that. The trap is that a rule wrapped in padding looks like padding. Cut the wrapper, keep the act, and give the trigger its own WHEN so the checker can read it.

**Does a shorter prompt with a higher score mean nothing was lost?**

No. In this guide the draft that dropped the escalation rule compiled clean at B (87/100) and promised the biggest token saving. A score measures the prompt you have, not the rule you deleted. Only the mapping against the frozen baseline, and test cases on the rules you rewrote, speak to what went missing.

**Does review-rewrite prove my shorter prompt means the same thing?**

No, and it says so in its own output: mappings are your assertions, and matching observations or scores do not establish semantic equivalence. It proves every line is accounted for and lists what changed on each mapped pair, such as a dropped always or a new WHEN. Reading those cues, and testing the result, is still your job.

Field note

Shortening requests tend to arrive with a number attached: a latency budget from the voice team, a cost target from finance. The number is fine; it is what makes the work worth doing. The risk is that it becomes the only thing anyone checks. The review keeps a second number next to it that has to be zero: source lines with nowhere to go. The two commands also run in CI exactly as they do at a desk: exit 2 on a stale baseline or an incomplete mapping, exit 0 when every line is accounted for. That makes the accounting a gate on the pull request, not a step someone remembers. If the cut is part of moving the agent to a cheaper model, [Somebody wants the model bill smaller](https://typeglish.dev/blog/cheaper-model-checklist) has the rest of that checklist.

∿ washed up Oct 10, 2026 ∿
