← Tidelines/Releases

TypeGlish 0.7.2: the checker takes your word for it

A patch number on a release that mostly gives findings back. One new command lets you teach the compiler a noun it has never seen. Everything else in here is the checker admitting it was wrong, in five specific places, and saying so out loud.

by TypeGlish team8 min read#releasestypeglish 0.7.2
Take my word.

TL;DR 0.7.2 ships $DEFINE word, a command that teaches the compiler one of your nouns so the wallboard stops asking to be introduced, with five new blocking codes so a malformed declaration can never quietly do nothing. Then it takes findings away: the cross-file pass can now retract a local warning the composition disproves and prints a receipt for it, the importer repairs a no-space heading typo that was turning into 6 blocking errors, and two advisories that were simply wrong are gone. Monaco embedders have one thing to do: the editor surface is now the host's by default, so pass { chrome: true } if you want the brand background back. Upgrade with npm i -D typeglish@latest.

The interesting releases are usually the ones that add something. This one is mostly the opposite, and it is the better kind of work. Four of the five changes below delete a finding that should never have fired: a warning about a variable that a sibling file was using all along, an advisory that swallowed half a sentence and offered to name it, two nags at a list that was already well formed, and a cascade of six errors that traced back to a single missing space. The fifth, $DEFINE word, is new language surface, and it exists for the same reason: your product nouns are real, and the compiler kept treating them as strangers.

§1Teach it a noun it has never met

TypeGlish reads the as a lookup instruction. That is the whole basis of the Self-Containedness Law we pulled apart in the policy-doc teardown: when you write the wallboard, you are telling the model to retrieve a specific wallboard, and if the document never introduced one, the model resolves the pointer from its own priors instead of from your prompt. Hence prompt/unintroduced-definite, which fires on every definite the file has not established.

Correct, and for a genuinely ambiguous noun, useful. But some nouns are not ambiguous at all: they are your product. There is exactly one wallboard, everyone on the floor knows what it is, and no amount of "You manage a wallboard." makes the prompt better. Until now the only honest answers were to write a throwaway introduction line or live with the finding forever. 0.7.2 adds a third: declare it.

wallboard.tg✓ 0 findings
<$CONFIG>
  $DEFINE word wallboard
    - class:: noun
    - unique:: true
</$CONFIG>

# Role

You are a support agent.

# Instructions

Log every resolved ticket in the wallboard.
$CONFIG configures the runner; $DEFINE extends the language. - unique:: true is the load-bearing row: it declares that this lemma names exactly one thing, which is precisely what a definite article asserts, so the wallboard no longer needs an introduction. The guard on this post runs the real checker on that source every build, and it comes back 0 error, 0 warning, 0 info.

Run the identical file on 0.7.1 and you can see how new the surface is. The parser had never heard of the command, so the whole block fell through to the generic rule that content does not belong inside <$CONFIG>:

typeglish check wallboard.tg, on 0.7.1✗ exit 1
wallboard.tg:2:3  error  structure/config-section-content  Content inside <$CONFIG> never reaches the model — only $-commands ($IMPORT, $CONFIG, $TOOL, $DEFINE, $TEST) belong here. Move prompt content outside the section.
wallboard.tg:3:5  warn   structure/missing-period  Unterminated statement — end it with a period (or ! ?; a lead-in may end with ":"). Statement boundaries are a compile contract.
wallboard.tg:13:1  info   prompt/unintroduced-definite  "the wallboard" retrieves something this document never introduces - a model must guess which wallboard is meant.

 1 file — 1 error, 4 warning, 1 info
Trimmed to the interesting rows: the full 0.7.1 run repeats missing-period and bad-indent once per body row. Note the last line of the run, the one this release is really about: on 0.7.1 the file both fails to parse the declaration and still tells you the wallboard was never introduced.

The reason a new command is worth five new diagnostic codes is the failure mode it would otherwise have. A config block that accepts unknown keys is a config block that lies to you: you write a row, the compiler ignores it, and nothing anywhere says so. The params here are a closed schema of exactly two, class and unique, and stepping outside it is a blocking error that states the consequence in the message.

a param that does not exist✗ blocks
<$CONFIG>
  $DEFINE word wallboard
    - class:: noun
    - plural:: wallboards
</$CONFIG>

# Role

You are a support agent.

# Instructions

Log every resolved ticket in the wallboard.
The checker answers: "plural" isn't a param of $DEFINE word (class, unique) - the row was read WITHOUT it, so it configured nothing. That second clause is the whole design. And because this declaration dropped unique, the file still reports prompt/unintroduced-definite on line 13, which is the correct answer: nothing here claimed there is only one wallboard.

The other four are structure/define-word-class (a class outside noun, verb, adjective), structure/define-word-unique (unique on a verb, which the message calls a noun feature), structure/define-word-form (a lemma that is not a single word), and structure/duplicate-define-word (the same lemma declared twice). All five block compilation, and all five are in typeglish reference and typeglish --explain as of this version. One collision worth knowing: $DEFINE word AS @{tier} is equal to gold is still a named state called word. The AS decides which command you wrote.

§2The composition can now clear a finding

0.7.0 made a directory of prompts one program: files joined by $IMPORT compose before the proofs run, so a rule here and a rule in a file you transclude are checked against each other. That pass only ever added findings. 0.7.2 lets it subtract one, which turns out to matter for the most ordinary cross-file arrangement there is.

Here is the shape. A root file declares an input and hands the actual decision to a shared module:

prompts/copilot.tg
<$CONFIG>
  $REQUIRE variable minute_parity: one of even, odd
  $IMPORT file "identity.tg" as identity
</$CONFIG>

# Instructions

@<identity.identity>

Answer the customer question in two sentences.
Trimmed: the file also carries a # Role line. The variable is declared here because this is the file the host fills, and it is used over in identity.tg, inside a $SWITCH ON @{minute_parity} that the splice pulls in.

Check copilot.tg by itself and the single-file pass says something reasonable and wrong: you declared a variable and never used it. It cannot see the sibling. Before 0.7.2 that warning survived the program pass too, so the only way to clear it was to delete a declaration the composed prompt genuinely needs.

typeglish check prompts/0.7.1
prompts/copilot.tg:2:21  warn   clarity/unused-variable  $REQUIRE variable "minute_parity" is never used — no @{minute_parity} reference fills it. Remove it, or reference it in the prompt.
prompts/identity.tg:6:3  info   prompt/implied-doer  Nothing in this document says who follows its instructions - every imperative implies a doer the model must infer.

 2 files — 0 error, 1 warning, 1 info
program: 1 root — prompts/copilot.tg (2 files)
The advice in that warning is actively bad. "Remove it" would break the switch in the file it imports.

0.7.2 composes the two files, finds that the composed document does not reproduce the warning, and withdraws it. What it does not do is let it disappear quietly:

typeglish check prompts/✓ 0.7.2
prompts/identity.tg:6:3  info   prompt/implied-doer  Nothing in this document says who follows its instructions - every imperative implies a doer the model must infer.

 2 files — 0 error, 0 warning, 1 info
program: 1 root — prompts/copilot.tg (2 files)
program: retracted 1 finding the composition disproves — prompts/copilot.tg clarity/unused-variable (line 2)
That last line is the feature. A finding that vanishes without explanation is indistinguishable from a checker that got quieter, so the retraction is reported with the file, the code and the line it applied to. The info on identity.tg is untouched, because nothing about the composition disproves it.

The conservatism here is worth reading, because it is what keeps the feature from becoming a hole. A finding is retracted only if two things hold. First, its code has a row in a declared registry of retractable codes, each with a written reason, and there is no catch-all: an unregistered code never retracts however thoroughly a composition fails to reproduce it. Today that registry has exactly one row, clarity/unused-variable. Second, the finding's own line has to have been on trial, meaning it was actually present in the composed document, because an imported module's manifest rows are stripped at the splice and the composition never judged them. A file that belongs to no multi-file closure gets zero retraction, so if you check single files nothing about your output changed.

§3One missing space, six blocking errors

This one is a good argument for reading your worklist skeptically. Take a plain markdown prompt of the kind typeglish import exists for, and give it the typo everybody has typed: #Instructions, no space after the hash. CommonMark says that is not a heading, and the checker agrees, which means the document has no section structure at all and every numbered step in it lands in one scope.

legacy.md
#Instructions

1. Greet the customer by name.
2. Ask for the order number.
3. Look up the order.
4. Confirm the shipping address.

#Constraints

1. Never promise a refund date.
2. Never share internal notes.
Two missing spaces. Nothing else about this file is unusual, and both lists are numbered exactly the way anybody would number them.

On 0.7.1 that imports into a wall of findings, none of which mention the cause:

typeglish import legacy.md, on 0.7.1✗ 6 errors
  6 errors · 1 warn · 3 info (was 6 · 3 · 3)

the worklist:
  grammar
    L3 error structure/duplicate-step: Duplicate step "1" — 2 steps carry this number, so a reference to it is ambiguous. Renumber one of them. (conflicts with line 7)
    L10 error structure/duplicate-step: Duplicate step "1" — 2 steps carry this number. (conflicts with line 2)
    L10 warn structure/unordered-step: Step 1 appears after step 4 — steps are out of order.
    L1 error structure/dangling-step-ref: Reference to step instructions, which is not defined.
    L8 error structure/dangling-step-ref: Reference to step constraints, which is not defined.

 6 errors block build — causes: structure/duplicate-step x4, structure/dangling-step-ref x2
Trimmed to unique rows; duplicate-step fires four times. Look at dangling-step-ref on line 1: because #Instructions is prose, the leading # reads as an anchor reference to a step called instructions. Six blocking errors, and not one of them says "you are missing a space."

0.7.2 repairs the typo at the door, and reports the repair rather than performing it silently:

typeglish import legacy.md, on 0.7.2✓ builds clean
  2 headings normalized (#Instructions -> # Instructions) - a no-space hash is a heading typo, not prose
  0 errors · 0 warns · 3 info (was 6 · 3 · 3 — 6 errors resolved by the repairs and lifts above)

the worklist:
  optimization
    L3 info prompt/implied-doer: Nothing in this document says who follows its instructions…
    L4 info prompt/unintroduced-definite: "the order number" retrieves something this document never introduces…
    L6 info prompt/unintroduced-definite: "the shipping address" retrieves something this document never introduces…

 builds clean — next: typeglish build support.tg
6 errors and 3 warnings to zero of each, on a file where nobody changed a word of the prompt. The three info findings are the same three both versions found, and they are the real worklist. The language stays strict, by the way: this leniency lives in the importer only, because a mid-line #word in a .tg file is a real anchor reference and always was.

§4Two advisories that were simply wrong

Both of these are false positives, and both were the kind that erode trust fastest, because the advice attached to them was visibly nonsense.

The first is a boundary problem. When a sentence opens with the and runs several words before its verb, the compiler cannot prove where the name ends, so it declines to bind and offers you the explicit %name literal% form. Fine in principle. In practice the match ran greedily to the last declaration verb on the line and could swallow an entire earlier clause:

escalation.tg✓ clean on 0.7.2
# Role

You are a support agent.

# Context

The user no longer wants to speak or has asked twice.
An unremarkable sentence. On 0.7.1 it produced: Multi-word definite subject - "the user no longer wants to speak or" runs 7 words, followed by the suggestion to wrap it as %user no longer wants to speak or%. The has the matcher was looking ahead to belongs to the second clause.

0.7.2 stops the walk at the first finite verb, on the reasoning that a name never swallows a verb, and the file checks at 0 error, 0 warning, 0 info. The advisory still fires on spans the compiler genuinely cannot bound, which is what it was for.

The second is a pattern the checker did not recognize. English distributes one conditional across a lead and a list all the time: the action lives in the lead line, the conditions are the members. Every member looked like a guard with no THEN:

playbook.tg✓ 0 warnings on 0.7.2
# Role

You are a support agent.

# Instructions

Call the escalation playbook if:
1. When a customer asks for a manager more than once.
2. When a refund exceeds your approval cap.
0.7.1: two typeglish/if-then warnings, one per member, each asking for a THEN that is already sitting in the lead line. 0.7.2 recognizes the lead by its trailing guard keyword plus colon and exempts the members. Nagging each one to grow its own THEN was pattern-blind.

Worth saying what did not happen: this is a recognition fix, not a suppression. The playbook.tg above still reports prompt/unintroduced-definite on the escalation playbook, because nothing in the file introduced one. Two warnings went away and the finding that was right stayed. If you want that last one gone too, you now know the command: it is the one in §1.

§5The editor surface belongs to the host

The single entry under Features in this changelog is for people embedding typeglish/monaco, and it is the one change here that can alter what you see. setupTypeGlish takes an options object now:

typeglish/monaco
setupTypeGlish(monaco);                        // tokens only; your IDE keeps its chrome
setupTypeGlish(monaco, { chrome: true });      // the brand surface, both themes
setupTypeGlish(monaco, { chrome: myColors });  // your own Monaco colors map
The default flipped. Through 0.7.1 the theme always carried the brand surface, so every editor that mounted a .tg file sat on a deep-ocean background whether the surrounding app wanted one or not. Left unset now, colors is the empty map and Monaco falls through to its base vs or vs-dark theme.

The reasoning is a nice statement of what a language package is for: its job is to say what a token means and paint it accordingly, and deciding that every editor embedding a .tg file must sit on a particular background is the host's call, not the language's. The token colors are untouched, so the hardness and directness weights that the language server renders still read the same. If your app wanted the brand surface, it is one argument. If you never noticed the background was not yours, this is the release where it becomes yours.

upgrade
npm i -D typeglish@latest              # 0.7.2
npx typeglish@latest check prompts/    # or no install at all
Expect fewer findings, not more. Nothing in this release adds a diagnostic to prose you already wrote: the five new codes fire only inside a $DEFINE word block, which is a command you have to write first.
Field note

Energy check: this is a patch, and the version number is deliberate. The changelog's own Documentation entry records walking a 0.8.0 back to 0.7.2, which is the honest call for a release whose new surface is one optional command, even though a new command in a patch is unusual. Two notes on the reporting. Everything above was measured by installing the published 0.7.1 and 0.7.2 tarballs side by side and running the real CLI against the same files, so every before and after is a diff between two shipped builds rather than a benchmark; the numbers quoted (6 errors, 4 warnings, 1 retraction, 0 findings) are counts from those runs. And one claim we left out on purpose: the reference also documents $DEFINE word as making a lemma spelling-legal, which we could not exercise, because the spell tier did not fire on our test machine even for blatant misspellings. What is verified here is the part we could run. The full changelog lives on GitHub. For the release that made a directory of prompts one program, read the 0.7.0 notes.

FAQQuestions about 0.7.2

What is $DEFINE word for?
Your product nouns. A term like wallboard is a real object in your business that the compiler has never met, so the Self-Containedness Law asks you to introduce it and prompt/unintroduced-definite fires every time you write the wallboard. $DEFINE word wallboard with - class:: noun and - unique:: true declares that the lemma names exactly one thing in this document, and the finding stops. It is scoped to the lemma you declared, not a blanket mute: in the same file, an undeclared the result still gets flagged.
Does $DEFINE word silence findings I actually want?
Only for the exact lemma you name, and only the introduction requirement. The params are a closed schema of two, class and unique, and anything else is a blocking error rather than a silent no-op: a row like - plural:: wallboards returns structure/define-word-param, whose message says the row was read WITHOUT it, so it configured nothing. A bad class is structure/define-word-class, unique on a verb is structure/define-word-unique, a two-word lemma is structure/define-word-form, and defining the same lemma twice is structure/duplicate-define-word. All five block compilation.
What is the retraction law in the cross-file check?
When typeglish check runs over a directory it composes files joined by $IMPORT and checks them as one program. As of 0.7.2 that pass can also take a finding away. If a root declares $REQUIRE variable minute_parity and never uses it, the single-file pass warns clarity/unused-variable, but an imported sibling that reads @{minute_parity} proves the declaration is used. The composed pass does not reproduce the warning, so it is withdrawn, and the run prints a receipt line naming the file, the code and the line rather than letting the warning vanish quietly.
Which findings can be retracted?
Exactly one today: clarity/unused-variable. The retractable set is a declared registry with a reason per row and no catch-all, so an unregistered code never retracts no matter how thoroughly a composition fails to reproduce it. A file that belongs to no multi-file closure gets zero retraction, which keeps single-file behavior identical to before.
Why did one missing space cause six errors on import?
Because #Instructions with no space after the hash is not a heading in CommonMark, so the checker correctly read it as prose. With the real headings gone, every numbered step pooled into one scope and collided: importing a twelve-line prompt with two such headings returned 6 blocking errors, four structure/duplicate-step and two structure/dangling-step-ref. In 0.7.2 the importer repairs the typo and reports it, and the same file imports at 0 errors and 0 warnings. The language itself stays strict, because a mid-line #word is a real anchor reference.
I embed typeglish/monaco. Does 0.7.2 change anything for me?
Yes, and it is the one change here that can alter what you see. setupTypeGlish(monaco) now takes an optional second argument, and the surface colors are no longer applied by default: background, gutter, line highlight, selection and cursor fall through to Monaco's base vs or vs-dark theme, so an embedding IDE keeps its own chrome. Pass setupTypeGlish(monaco, { chrome: true }) to get the previous brand surface back, or pass your own Monaco colors map. The token colors, which are the part that teaches what a word means, are unchanged either way.
Should I upgrade, and will my prompts still check the same?
Yes to upgrading: npm i -D typeglish@latest. Expect findings to go away rather than appear. The two retired advisories, prompt/multiword-definite on a swallowed clause and typeglish/if-then on the members of a condition list, were false positives, and the retraction law only ever removes a warning. Nothing in this release adds a diagnostic to prose you already wrote; the five new codes fire only on a $DEFINE word block, which is a command you have to write first.
∿ washed up Jul 31, 2026 ∿