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.
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.
<$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>:
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
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.
<$CONFIG> $DEFINE word wallboard - class:: noun - plural:: wallboards </$CONFIG> # Role You are a support agent. # Instructions Log every resolved ticket in the wallboard.
"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:
<$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.
# 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.
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)
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:
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)
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.
#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.
On 0.7.1 that imports into a wall of findings, none of which mention the cause:
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
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:
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
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:
# Role You are a support agent. # Context The user no longer wants to speak or has asked twice.
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:
# 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.
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:
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
.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.
npm i -D typeglish@latest # 0.7.2 npx typeglish@latest check prompts/ # or no install at all
$DEFINE word block, which is a command you have to write first.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 wordfor? - Your product nouns. A term like
wallboardis a real object in your business that the compiler has never met, so the Self-Containedness Law asks you to introduce it andprompt/unintroduced-definitefires every time you writethe wallboard.$DEFINE word wallboardwith- class:: nounand- unique:: truedeclares 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 undeclaredthe resultstill gets flagged. - Does
$DEFINE wordsilence findings I actually want? - Only for the exact lemma you name, and only the introduction requirement. The params are a closed schema of two,
classandunique, and anything else is a blocking error rather than a silent no-op: a row like- plural:: wallboardsreturnsstructure/define-word-param, whose message says the row was read WITHOUT it, so it configured nothing. A bad class isstructure/define-word-class,uniqueon a verb isstructure/define-word-unique, a two-word lemma isstructure/define-word-form, and defining the same lemma twice isstructure/duplicate-define-word. All five block compilation. - What is the retraction law in the cross-file check?
- When
typeglish checkruns over a directory it composes files joined by$IMPORTand 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_parityand never uses it, the single-file pass warnsclarity/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
#Instructionswith 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, fourstructure/duplicate-stepand twostructure/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#wordis 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 basevsorvs-darktheme, so an embedding IDE keeps its own chrome. PasssetupTypeGlish(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-definiteon a swallowed clause andtypeglish/if-thenon 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 wordblock, which is a command you have to write first.