Your prompt has a second reader
Everyone writes a system prompt for the model. The model is not the reader who deletes your rule, softens your escalation, or reinstates the contradiction you removed last quarter. That reader is a person, they arrive in six months, and they read a different document.
TL;DR A prompt file has two audiences: the model, which only ever sees the compiled artifact, and the next engineer, who sees the source. TypeGlish scores them separately as a runtime plane and a hygiene plane, so two files whose artifacts are byte-identical can grade A (95/100) and B (83/100), with the entire gap sitting in the @@ notes written for the human.
Prompt engineering talks about the model constantly and about the next maintainer almost never, which is strange, because every prompt defect we have written about on this blog was introduced by a person editing a file they did not write. The contradiction, the second refund cap, the softened restatement, the deleted privacy rule: none of those are model failures. They are edits made without the reason for the original line. So it is worth taking seriously that a prompt has a second reader, and that almost nothing in a plain prompt string is addressed to them.
§1Two audiences, one file
A raw prompt has a hard property: everything in it is runtime. There is no place to write down why a rule exists that does not also get sent to the model, weighed as an instruction, and paid for in tokens. So the why goes somewhere else, which in practice means a ticket, a Slack thread, or the memory of whoever wrote it. All three expire.
A compiled prompt splits the file in two. Some of it is addressed to the model, and some of it is addressed to whoever opens the file next. That second half is not a comment in the decorative sense; it is the half of the document that carries intent, and TypeGlish gives it its own name and its own place in the grade.
§2The proof: same artifact, different grade
Here is a small order-support prompt with four rules, each carrying a @@ note that says what the rule is for. Then the same file with every note deleted and nothing else touched.
<$CONFIG> $IMPORT tool lookup_order </$CONFIG> # Role @@ role: name the domain so "helpful" has a scope You are a support agent for Acme, an online retailer. # Constraints @@ identify: an order id is the only key the order system takes - You MUST ask for an order id before discussing a delivery. @@ lookup: a remembered delivery date is a guess, and a guess becomes a promise - You MUST call @[lookup_order] before stating a delivery date. @@ no_refunds: finance owns refunds, so a promise here binds a team that never saw it - You NEVER promise a refund. @@ brevity: three sentences keeps a support reply scannable - You MUST reply in at most 3 sentences.
<$CONFIG> $IMPORT tool lookup_order </$CONFIG> # Role You are a support agent for Acme, an online retailer. # Constraints - You MUST ask for an order id before discussing a delivery. - You MUST call @[lookup_order] before stating a delivery date. - You NEVER promise a refund. - You MUST reply in at most 3 sentences.
Both files check clean. Then score them, and the file splits along the seam.
✓ 2 files - 0 error, 0 warning, 0 info noted.tg - A (95/100) proven errors: none tiers: base+z3 planes runtime 94 (what the model reads) · hygiene 100 (source only) facets enforceability 77 x.21 · hardness 100 x.12 · directness 100 x.08 · consistency 100 x.17 structure 100 x.12 (hygiene) · annotation 100 x.12 (hygiene) · style 100 x.08 · security 100 x.08 bare.tg - B (83/100) proven errors: none tiers: base+z3 planes runtime 94 (what the model reads) · hygiene 50 (source only) facets enforceability 77 x.21 · hardness 100 x.12 · directness 100 x.08 · consistency 100 x.17 structure 100 x.12 (hygiene) · annotation 0 x.12 (hygiene) · style 100 x.08 · security 100 x.08 lever annotation 0/100 (up to +12 overall) - Put a "@@ why" note directly above each statement ("@@ name: why" also names it).
runtime is 94 in both. The entire twelve-point spread is annotation, weighted x.12, moving from 100 to 0.Now the part that makes this a fact rather than a philosophy. Build both files and the artifacts are the same text, the same length, and the same hash. The model cannot distinguish the A from the B, because nothing the grade is measuring ever reaches it.
✓ built .typeglish/dist/noted.txt ← noted.tg (1dcb890a978d, full) ✓ built .typeglish/dist/bare.txt ← bare.tg (1dcb890a978d, full) # diff .typeglish/dist/noted.txt .typeglish/dist/bare.txt # (no output) # Role You are a support agent for Acme, an online retailer. # Constraints - You MUST ask for an order id before discussing a delivery. - You MUST call lookup_order before stating a delivery date. - You NEVER promise a refund. - You MUST reply in at most 3 sentences.
@@ is compile-time only. The two builds even report the same short hash, 1dcb890a978d. Documentation in a compiled prompt is not a token trade-off, which is the whole reason the second reader can be served properly.bare.tg sourceSha256 f3b3a55aba64... artifactSha256 1dcb890a978d... noted.tg sourceSha256 362b038e87a2... artifactSha256 1dcb890a978d...
The model reads what you compiled. Your teammate reads what you wrote.
§3What the second reader actually needs
Not a restatement. The failure mode of prompt comments is a note that says in prose what the rule already says in English: @@ never promise a refund above You NEVER promise a refund. That is a line of text with no information in it, and it trains everyone to skim the notes.
What the second reader needs is the one thing the rule cannot carry: why the rule is there, and what breaks if it goes. Compare the two versions of the same annotation:
- @@ no_refunds: never promise a refund - a restatement. Tells the next editor nothing they cannot read one line down.
- @@ no_refunds: finance owns refunds, so a promise here binds a team that never saw it - a reason. Now the next editor knows that softening this rule is not a tone decision, it is a decision about another team’s liability, and they will go ask.
This is what makes annotation a correctness feature rather than a politeness one. A rule with a reason attached is a rule that survives contact with an editor in a hurry, and an undocumented rule is the one that gets trimmed for length. We watched that happen mechanically in delete a line, see who notices: most rules can be deleted from a prompt with no diagnostic at all, so the only defenses are a reference, a test, and a person who knows why the line is there. The note is how you talk to that person.
The named form earns its keep too. @@ name: why gives the rule a handle, and a handle is what lets a review comment, a $TEST id, and a changelog entry all point at the same thing. When a case is called no_refunds and the rule it defends is annotated no_refunds, the pair is legible to the next reader without anybody explaining the convention.
§4The second reader’s plane is checked, not decorated
It would be easy to dismiss this as a style score, so it is worth seeing that the compiler polices the human plane with the same blocking errors it uses on the runtime one. An annotation is bound to exactly one statement, and if that binding is broken the build stops.
# Role @@ role: name the domain so "helpful" has a scope You are a support agent for Acme, an online retailer. # Constraints @@ no_refunds: finance owns refunds @@ a promise here binds a team that never saw it - You NEVER promise a refund.
# Role @@ role: name the domain so "helpful" has a scope You are a support agent for Acme, an online retailer. # Constraints @@ no_refunds: finance owns refunds, so a promise here binds a team that never saw it - You NEVER promise a refund.
stacked.tg:6:1 error structure/stacked-annotation Stacked annotations: a `@@` note documents the ONE statement directly below it, and the line below is another `@@`. Merge the notes into one line, or give each note its own statement. unattached.tg:6:1 error structure/unattached-annotation A `@@` annotation documents the statement DIRECTLY below it: here the next line is a blank line. Move the note to the line immediately above its statement. ✗ 2 files - 2 error, 0 warning, 0 info
So the practical reframe is small and changes how you read your own file. When you open a prompt, ask which reader each line is for. Runtime lines are a contract with the model and every word costs something. Source lines are a contract with your successor and cost nothing at all, which means there is no budget argument against writing the reason down. The plane split in the score is just that question, asked by a machine: runtime 94, hygiene 50 is not a bad prompt, it is a well-built prompt nobody documented, and those are two different pieces of work.
A rule with no reason attached is a rule the next person is entitled to delete.
§5Common questions
- Should I put comments in a system prompt?
- In a compiled prompt, yes, without hesitation. A TypeGlish source file carries
@@notes and//comments that are stripped before anything is sent, so the documentation lives beside the rule it explains and costs the model nothing: two files that differ only in their notes build to the same artifact, with the same artifact hash. In a raw prompt string with no compile step there is no free place to put a comment, which is exactly why the why tends to end up in a ticket nobody reopens. - Why is my prompt score low when the prompt itself looks fine?
- Read the plane split before you touch a rule. The TG score reports
runtime(what the model reads) separately fromhygiene(source only), and two facets,structureandannotation, live on the hygiene side. A file can readruntime 94andhygiene 50at the same time, which does not say the prompt is bad; it says the documentation is missing. The lever line names the facet with the most headroom, so it will tell you which of the two you are actually looking at. - What does an @@ annotation do in TypeGlish?
- It documents the ONE statement directly below it, and it never reaches the model. The form
@@ name: whyalso names the rule, which gives you something to refer to in review and in a test id. Because the note is bound to a single statement, the binding is checked: a note stacked directly above another note isstructure/stacked-annotation, and a note whose next line is blank isstructure/unattached-annotation. Both are blocking errors, so an annotation cannot drift away from the rule it explains. - Do comments in a system prompt cost tokens?
- Not in a compiled prompt.
@@notes,//comments and every$-command are compile-time only:buildstrips them and writes the artifact the model receives, so an annotated file and a bare one can produce byte-identical output. You can verify it rather than trust it, by diffing the two artifacts or comparingartifactSha256in.typeglish/build-manifest.json.
The two planes in the score are the same seam as the two planes in the file, which your system prompt has a compile time works through from the compiler’s side: everything on the hygiene plane is scaffolding the model never sees. What is newer is that the grade now reports the halves separately instead of averaging them into one number, so a low score finally tells you which reader you shortchanged. For the mechanical case that an undocumented rule is a fragile rule, see delete a line, see who notices.