> Markdown rendition of https://typeglish.dev/blog/typeglish-0-7-0 ("TypeGlish 0.7.0: your prompts are one program - Tidelines"). Canonical page: https://typeglish.dev/blog/typeglish-0-7-0 · All pages: https://typeglish.dev/llms.txt

[← Tidelines](https://typeglish.dev/blog)/ Releases Jul 31, 2026

# TypeGlish 0.7.0: your prompts are one program

The cross-file release. Point `typeglish check` at a directory and every file joined by `$IMPORT` is checked as one program, so a `NEVER` in your shared policy file and a `MUST` in the agent that imports it finally collide at edit time instead of in production.

by **TypeGlish team** 8 min read #releases `typeglish 0.7.0`

One program.

**TL;DR** 0.7.0 makes `typeglish check <dir>` a program pass: files joined by `$IMPORT` compose before the proofs run, and a cross-file contradiction lands on its own `(file, line)` and blocks exactly like a local one (`--no-program` restores the old per-file behavior byte for byte). `$REQUIRE section` plus `typeglish import --fix-citations` clear the citation errors that kept composed production prompts out at the door, `typeglish fmt` is a new subcommand that joins hard-wrapped fragments in place, and `typeglish reference` now documents 99 diagnostic codes where 0.6.0 documented 48. Upgrade with `npm i -D typeglish@latest`.

[0.6.0 opened the door](https://typeglish.dev/blog/typeglish-0-6-0) for the prompt you already have: point `import` at it, get a checked `.tg` back, work the worklist down. Then everyone who walked through that door hit the same wall, because nobody ships one prompt. You ship a shared policy file, a chat agent, a voice agent, and an escalation module, and the reason you split them up was to write the refund policy exactly once. Up to 0.7.0 the checker read each of those files alone, which means the one defect that composition invites, a rule in one file that contradicts a rule in another, was the one defect it could not see. This release closes that. Upgrade with `npm i -D typeglish@latest`, or run it with no install at all: `npx typeglish@latest check prompts/`.

## §1 The join law: two files, one program

Here is the smallest version of the bug, and it is the shape every prompt set grows into. The policy team owns one file with the refund rules in it. The retention team owns the chat agent, which imports that file and adds a rule of its own. Both files are short, both are readable, and both are correct on their own terms.

prompts/refund-policy.tg ✓ compiles

```typeglish
You are a support agent for Acme Analytics.
- NEVER waive a restocking fee.
```

The shared module, and the guard on this post proves it: checked by itself, this file is **0 error, 0 warning, 0 info**. Nothing is wrong with it. Nothing will ever be wrong with it.

prompts/chat-agent.tg

```
$IMPORT file "./refund-policy.tg" as policy
@<policy>
- MUST waive a restocking fee.
```

The agent that composes it in. Checked by itself this file is also clean: **0 error**. Somebody on the retention team wrote an absolute, in their own file, without reading the policy module they transclude on the line above. This is not carelessness. It is what file boundaries are *for*, and it is why the defect survives review.

Before 0.7.0, that was the end of the story: two green files, one agent that has been told both to always waive the fee and to never waive it, and a coin flip at runtime. Now point the checker at the directory.

typeglish check prompts/ ✗ exit 1

```
prompts/chat-agent.tg:3:1  error  logic/contradiction  Logical conflict — "waive a restocking fee" is both required and forbidden. … (conflicts with prompts/refund-policy.tg line 2)
prompts/chat-agent.tg:3:1  info   prompt/implied-doer  Nothing in this document says who follows its instructions - every imperative implies a doer …
prompts/refund-policy.tg:2:1  error  logic/contradiction  Logical conflict — "waive a restocking fee" is both required and forbidden. … (conflicts with prompts/chat-agent.tg line 3)

✗ 2 files — 2 error, 0 warning, 1 info
program: 1 root — prompts/chat-agent.tg (2 files)
```

Verbatim, with the fix-advice clause on each error line elided as `…` for width. Read what the line numbers do. The error is reported **twice**, once on each file, and each report sits on the true line of its own offending rule: `chat-agent.tg:3` is the `MUST`, `refund-policy.tg:2` is the `NEVER`, and each names the other file and line as the conflict. Whichever file you have open, the error is in your gutter, pointing at the rule you can actually edit. That is the part that makes this usable rather than merely correct, and it is what the release means by cross-file findings that "block like local ones": exit code 1, and `typeglish build` refuses.

Two properties of the program pass are worth knowing before you put it in CI, because both of them are about restraint.

**It is scoped to files that can actually collide.** The pass does not diff every prompt against every other prompt. It composes what `$IMPORT` joins, and nothing else. Drop a support agent that says `NEVER waive a restocking fee` and a billing agent that says `MUST waive a restocking fee` into one directory with no import between them, and the checker reports **0 errors** and tells you exactly why it stayed quiet: `program: 2 independent files — no $IMPORT compositions, nothing co-checked`. Those two agents never run in the same context, so there is no conflict to prove. Same soundness bar as always, now with a wider field of view: the compiler reports what it can prove and stays silent otherwise, which is the argument we made the first time in [Your prompt argues with itself](https://typeglish.dev/blog/prompt-contradictions).

**The composition is transitive.** A root that imports a file that imports a third file is one program of three files, and the summary line says so: `program: 1 root — tri/top.tg (3 files)`. The reference records the shift plainly. In 0.6.0, `import/nested` was documented as "an imported file itself imports another; nesting is not allowed". In 0.7.0 the same code means something else entirely, which you can read straight out of `typeglish --explain import/nested`: "A problem inside an imported file (imports compose transitively), reported at the `$IMPORT` line that pulled it in." The code went from naming a shape the language refused to naming a pointer at the real problem one level down.

One practical note that will save you an afternoon: **point it at the directory**. Naming a single file still checks that file alone, so `typeglish check prompts/chat-agent.tg` on the pair above exits 0 while `typeglish check prompts/` exits 1. If your CI line names files, it is not running the program pass. And if you need the old behavior exactly, it is one flag: `--no-program` checks every file alone, which the help calls "the pre-program behavior, byte-identical".

## §2 The import funnel is whole

The second theme is the unglamorous work that decides whether the door in [0.6.0](https://typeglish.dev/blog/typeglish-0-6-0) actually leads anywhere. The changelog entry is blunt about the target: "the import funnel is whole, 50 blockers to 0 on a real production prompt set." That number is the compiler team's count on their own corpus, not a benchmark we can hand you, but the mechanism behind it is the interesting part, and you can reproduce it in a minute.

A composed production prompt cites sections that something else supplies. The host prepends a preamble, or the platform injects a handoff block, and your prompt says "follow `<handoffs>`" because at runtime `<handoffs>` is right there. The compiler cannot see the host, so it saw a pointer to nothing: `structure/dangling-section-ref`, a blocking error. Correct for a typo. Wrong, and unfixable, for a prompt whose runtime really does compose that section in. Multiply by a prompt set and you get a funnel that stops at the door for a reason the author cannot act on.

0.7.0 gives you the missing declaration. `$REQUIRE section <names>` says: a host composes these in, so treat a citation of them as resolved. The importer now finds those citations, prints the exact line to add, and will write it for you.

typeglish import legacy.md 2 errors block build

```
  grammar
    L5 error structure/dangling-section-ref: Reference to section <handoffs>, which is not defined.
    L6 error structure/dangling-section-ref: Reference to section <escalation>, which is not defined.

✗ 2 errors block build — causes: structure/dangling-section-ref x2 · 2 citations (--fix-citations applies them)
  2 cited sections nothing declares. If a host composes them in (a prepended preamble), declare them at the top of the file (below any $CONFIG block) - if not, one is a typo:
      $REQUIRE section handoffs, escalation
  next: typeglish check legacy.tg for the full detail
```

Verbatim, with the absolute path of the written file shortened. Note the shape of the help: it does not guess. It names both readings, a host that composes the section in or a typo, hands you the line that fixes the first, and leaves the judgment with you. `--gate` makes that verdict a CI signal: plain `import` exits 0 because the conversion succeeded, `import --gate` exits 1 because errors would block `build`.

Add `--fix-citations` and the flag *is* the consent. Two blockers become zero, and the file it writes builds clean.

typeglish import legacy.md --fix-citations ✓ builds clean

```
imported -> legacy.tg
  lifted: customer_name
  0 errors · 1 warn · 1 info (was 2 · 1 · 1 — 2 errors resolved by the repairs and lifts above)
  declared by --fix-citations: handoffs, escalation
    verify each is a section the composed agent really supplies - a typo gets declared too.
    A wrong name? delete it from the $REQUIRE line and quote the markup in the prose instead
```

The counts tell the whole story: `0 errors` now, `was 2` before. And read the two lines under the declaration, because they are the honest half. The flag applies what the report proposed; it cannot know whether `handoffs` is a section your host really supplies. A typo gets declared exactly as readily as a real citation, so the tool says so in its own output rather than letting you find out in production.

Here is the file it wrote. The citations resolve, the placeholder became a typed variable with a pointer at the point of use, and every word of the original is where the author left it.

legacy.tg - what import wrote ✓ compiles

```typeglish
$REQUIRE variable customer_name

$REQUIRE section handoffs, escalation

You are a support agent for Acme Analytics.

Always be polite. Follow <handoffs> when the customer asks for a human.
Never state a specific price. Escalate per <escalation> if they push back.
Look up the order for @{customer_name}.
```

The guard on this post runs the real checker against this exact block and asserts no blocking error, which is the claim that matters: a composed prompt that cites what its host supplies now compiles.

And the declaration is **scoped, not a blanket mute**, which is the detail that keeps it honest. It resolves the names you listed and nothing else, so the typo case still fails exactly as it should.

typo.tg structure/dangling-section-ref

```typeglish
$REQUIRE section handoffs, escalation
You are a support agent for Acme Analytics.
- ALWAYS follow <handofs> when a customer asks for a human.
```

One letter missing from the citation, and the blocking error is still there: `Reference to section <handofs>, which is not defined.` The guard on this post re-proves that too. Declaring `handoffs` did not teach the compiler to accept any tag it does not recognize; it taught it about one section, by name. You also get two `structure/unused-import` warnings, because now nothing cites the sections you declared, which is a second, quieter way of being told about the typo. If you have pasted a policy doc into an agent lately, this pairs with [the pasted-policy teardown](https://typeglish.dev/blog/teardown-pasted-policy).

## §3 `typeglish fmt`, the command the finding names

0.7.0 adds a subcommand, and its charter is deliberately boring: `typeglish fmt` fixes **shape**, in place, mechanically. It joins hard-wrapped fragments, splits compound rules, and normalizes whitespace. Like `import`, it does not touch your words.

The reason it exists is that the checker was already telling people to do this by hand. A rule that got hard-wrapped by an editor at 80 columns reads, to a parser, as two statements where the second one is a sentence fragment.

support.tg - hard-wrapped by an editor structure/wrapped-fragment

```typeglish
You are a support agent for Acme Analytics.
- ALWAYS confirm the order id before you promise a delivery date, and
  escalate to a human when the customer asks twice.
```

Three warnings on one wrapped rule: `structure/missing-period` on line 2, `structure/bad-indent` and `structure/wrapped-fragment` on line 3. The wrapped-fragment message does the diagnosis in full: "Reads as a hard-wrapped continuation of line 2 — it starts lowercase, classifies as plain prose, and line 2 has no terminator. If they are ONE statement, join them (`typeglish fmt`); if this line stands alone, capitalize its first word." In 0.6.0 that parenthetical named a command that did not exist yet.

typeglish fmt support.tg

```
$ typeglish fmt support.tg --check
support.tg: 1 change needed
✗ 1/1 file need formatting — run typeglish fmt

$ typeglish fmt support.tg
✓ formatted support.tg (1 change)
✓ 1 formatted, 0 unchanged
```

Verbatim from both runs. `--check` writes nothing and exits 1 when a file would change, so it drops into CI beside `check` the way any formatter's check mode does. The plain run rewrites the file and reports the count.

support.tg - after fmt ✓ compiles

```typeglish
You are a support agent for Acme Analytics.
- ALWAYS confirm the order id before you promise a delivery date, and escalate to a human when the customer asks twice.
```

One join, and the file goes from three warnings to zero. What is left is a single `info` about "the order id" being a definite this document never introduced, which is a real observation about the prompt rather than an artifact of how it was typed. That is the split worth having: `fmt` takes the typing mistakes off the worklist so the findings that remain are about meaning.

## §4 The full-code ratchet: every code has a name you can look up

The last theme is one you will feel most if you have ever put an agent in front of this compiler. TypeGlish diagnostics are namespaced codes, and the promise of a code is that you can look it up: `typeglish --explain logic/contradiction` prints what it means, straight from the compiler. In 0.6.0 that promise had holes, and here is one, reproducible in two commands.

0.6.0: a code the compiler could not explain

```
$ npx typeglish@0.6.0 check unclosed.tg
unclosed.tg:2:1  error  structure/unclosed-tag  Tag <handoffs> is opened but never closed — add a </handoffs>.

$ npx typeglish@0.6.0 --explain structure/unclosed-tag
typeglish --explain: unknown code "structure/unclosed-tag" — codes look like category/name (e.g. logic/contradiction), or a score facet (e.g. enforceability)

$ npx typeglish@0.7.0 --explain structure/unclosed-tag
structure/unclosed-tag (error — blocks compilation)
  A section tag opened but never closed — the section extent is undefined.
```

The same checker, in the same release, blocking your build with a code its own explainer called unknown. Nothing was broken about the check; the code just was not declared in the registry `--explain` and `reference` read from. The changelog calls closing these the **full-code ratchet**, and ratchet is the right word: 0.7.0 landed the last two escapes, after an earlier change in the same release closed the first fifty.

The visible result is in the language reference. The diagnostics table that `typeglish reference` prints, the document the CLI tells agents to read first, goes from **48 codes in 0.6.0 to 99 in 0.7.0**. Be clear about what that number is and is not: those are mostly not new checks. They are checks that already ran and already blocked builds, now with a documented name, a severity, and a one-line meaning you can look up. `structure/unclosed-tag`, `structure/duplicate-tool`, `structure/no-default-branch`, `structure/dangling-service` and dozens of others became addressable in this release rather than becoming real.

That matters to a human once a quarter and to an agent constantly. An agent that gets handed `structure/bad-guard-expr` and can resolve it to "a `<tag when=…>` guard that is not a valid condition, so the section could not resolve away soundly" can act. An agent that gets handed a code its tooling calls unknown will guess, and a guess about a compiler error is how a fix becomes a second bug. The same reasoning is why `reference` exists as a command at all.

## §5 Also in 0.7.0

- **Directory builds are partial and honest.** `typeglish build prompts/` compiles everything that passes, names each refusal on its own line with the diagnostics that caused it and nothing written for that file, reports the tally as built *n* of *m* with the refusals counted, and exits non-zero. You get the artifacts you earned and an accurate exit code, rather than one bad file blocking the set or a green run that quietly skipped things.

- **A new import error for a real ambiguity.** `import/ambiguous-file` blocks when an import path could be answered by several files in the workspace, because a path that resolves to one of two files by luck is a defect you find much later. Qualify the path so exactly one resolves.

- **The Monaco editor works straight off npm.** The published package now ships `dist/lsp-worker.js`, which was missing from the 0.6.0 tarball. If you embed `typeglish/monaco`, the language server worker is in the box.

- **A Voiceflow export is a door too.** `typeglish import` on a `.vf` file writes a git-ready `prompts/` fileset plus a manifest instead of a single file, and a fileset checks in its manifest reading order, which is exactly the directory-shaped program the rest of this release is about.

- **The last raw-ordinal escape.** The also-list on `clarity/duplicate` now speaks line numbers instead of raw statement ordinals, so "already declared identically on line 4" points at the line your editor calls 4.

Field note

Energy check: this is a big release for anyone with more than one prompt file, and a quiet one if you have exactly one. Two honest caveats. First, upgrading can turn a green prompt set red, because a directory target now runs the program pass and a set of files that each passed alone can fail together. That is the release working, not a new rule to argue with, and every finding is still proven rather than guessed; `--no-program` is there if you need the old output byte for byte while you fix things. Second, the program pass only fires on directory targets, so a CI line that lists files one by one gets none of this. Change it to name the directory. As always there are no benchmark or adoption numbers here: the "50 blockers to 0" line is the compiler team's count on their own prompt set, quoted as what the release reports rather than as a measurement we ran. 0.7.0 also lands engine work we have not demonstrated, including the argument slot, the project default, and registry hardening, which show up as more precise readings rather than as new commands. Those are in the changelog on [GitHub](https://github.com/Bradenream/TypeGlish). For the release that opened the door these files walk through, read [the 0.6.0 notes](https://typeglish.dev/blog/typeglish-0-6-0), and for why one prompt splits into several in the first place, [Say it once, or say it's optional](https://typeglish.dev/blog/say-it-once).

## FAQ Questions about 0.7.0

**How do I check prompts that import each other?**

Point `typeglish check` at the directory, not at a file: `typeglish check prompts/`. A directory target expands to its `.tg` files and checks them as one **program**, so files joined by `$IMPORT` compose before the proofs run. Naming a single file still checks that file alone, which is why a cross-file contradiction can pass file by file and fail on the directory.

**Does upgrading change how my existing files check?**

It can, in one specific way: a directory target now runs the cross-file pass, so a set of files that each passed alone can fail together. The failure is a real defect rather than a new rule, and it is still proven, never guessed. If you need the old behavior exactly, `typeglish check <dir> --no-program` checks every file alone, byte-identical to the pre-program output.

**Does the program pass check every prompt against every other?**

No. It is scoped to files that can collide at runtime, meaning files joined by `$IMPORT`. Two unrelated prompts in one directory are never co-checked: a support agent with `NEVER waive a restocking fee` and a billing agent with `MUST waive a restocking fee` report 0 errors, and the summary line says it co-checked nothing: two independent files, no `$IMPORT` compositions between them. They never run in the same context, so there is nothing to prove.

**What is `$REQUIRE section` for?**

It declares a section a **host** composes in at runtime, usually a prepended preamble, so citing that tag resolves at compile time. Without it, a citation nothing declares is `structure/dangling-section-ref`, a blocking error, which is right for a typo and wrong for a prompt whose runtime really supplies the section. It is scoped to the names you list: with `$REQUIRE section handoffs, escalation` in the file, a misspelled citation still errors. `typeglish import` prints the line to add and `--fix-citations` applies it.

**What does `typeglish fmt` do?**

It fixes formatting in place: joins hard-wrapped fragments, splits compound rules, normalizes whitespace. Mechanical, shape only, never wording. It is the command `structure/wrapped-fragment` names in its own message. `typeglish fmt --check` writes nothing and exits 1 when a file would change, which is the CI mode.

**Why did `--explain` not know some codes before 0.7.0?**

Because some codes the checker could emit were never declared in the registry `--explain` reads. In 0.6.0, a file with an unclosed section tag failed with `structure/unclosed-tag` while `--explain structure/unclosed-tag` answered "unknown code". 0.7.0 closes those escapes, and the reference's diagnostics table goes from 48 codes to 99. Most are existing checks that now have a documented name an agent can look up, not new checks.

∿ washed up Jul 31, 2026 ∿
