npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

typeglish

v0.11.0

Published

The TypeGlish language + compiler — turn English into logically consistent, checkable programs for LLMs.

Readme

TypeGlish

npm CI license

Turning English into logically consistent, controlled, maintainable, executable programs for LLMs.

A controlled language with the rigor of a programming language — operators, declarations, types, and a static consistency checker — that compiles English to clean, XML-tagged prompts. Think the TypeScript of English: you still write English, but a grammar, a type system, and a solver have your back.

The long-term goal: make English safe for agents to work with — a static analyzer for the instructions, policies, and knowledge agents consume, run at corpus scale to catch contradictions the way a compiler does for code. This repo is the rules and the compiler for TypeGlish, plus a playground to build and work on the language. See ROADMAP.md for where it's headed.

Why

A prompt is a program written in English — but English has no compiler. Nothing tells you when two instructions contradict each other, when a constraint is impossible to satisfy, or when a reference is undefined. TypeGlish adds that missing layer.

$REQUIRE variable customer_name: string

# Role
You are a customer support agent for Acme. The customer's name is @{customer_name}.

# Constraints
- NEVER state a specific price; ALWAYS direct pricing questions to sales.
- MUST keep every response to at most 3 sentences.
- IF you are unsure THEN say so AND offer to escalate.
  • Operators — modals (MUST / NEVER / SHOULD …), control flow (IF … THEN … OTHERWISE), connectives (AND / OR / NOT), and the copula (IS / ARE / AM). Case-insensitive.
  • Statement terminators — every statement ends with . ! ? (a lead-in may end with :); unterminated is a compile error, one-click fixable — the semicolon rule, one level up. The terminator never leaks into a bound value: Tone IS warm. binds warm.
  • Layout is syntax — the indent unit is 2 spaces and indentation mirrors section nesting (a nested tag one unit deeper, its content one deeper than that); one space between things. Alignment columns, trailing whitespace, and tabs are compile errors with one-click fixes — "LLM spacing" doesn't compile. Blank lines, by contrast, are free: the compiler packs the emitted prompt — consecutive prose statements join onto one line, a run of blank lines collapses to a single break, and structure (lists, headings, tags, fences) keeps its own line. Fences and literal zones stay verbatim, and cosmetic indent is stripped at compile, so the model reads clean packed text either way.
  • A strict character set — the instruction plane is plain ASCII text: em-dashes, curly quotes, arrows, bullets, math symbols, emoji, and invisible characters are compile errors with one-click ASCII fixes. Not aesthetics: each mark hides meaning from the checker (a curly apostrophe conceals a possession contradiction; ≤ 3 hides the bound at most 3 proves). Human language never flags — accents, scripts, currency stay legal — and symbols keep their literal homes (<examples>, <"…"> zones, fences, quotes).
  • Declarations — Persona IS a support agent binds a reusable object AND renders (binding and instruction are the same statement); @{Persona} expands the value elsewhere (case-insensitive).
  • Adjective axes — every adjective lives on an opposition axis (WordNet-seeded pairs + weighted spectra: cold … cool … warm … hot), so Tone IS casual. vs Speak formally. is a proven contradiction wherever the claim sits — copula, adverb (speak fast), be-imperative, or a bare fragment (Formal tone only.). Claims land on their owner (you by default — a prompt is instructions), graded by the frequency square (Sometimes … × 2 stays legal). Vocabulary is declarable: $CONFIG adjective ornate defines a word onto an axis (the pair rule as schema law), and an undefined adjective in a claim seat is an error by default — dialable per project. A declaration whose pointer also expands puts the value in front of the model twice — the checker flags it (prompt/duplicated-declaration).
  • Adverbs, classified — degree words are transparent where they should be and ONLY there: Speak very formally. still contradicts Speak casually., while Never be too casual. stays compatible with Be casual. (banning the excess is not banning the quality). Canon verbs carry their manner (Reply formally. collides with Respond casually. — one action, both sides), and every adverb family — degree, manner, delay, rate, sequence — answers one classification, with frequency/focus derived from the keyword layer, never duplicated. Degree words DO THE MATH: a claim is an interval on its axis, very shifts it toward the pole, slightly bounds it — so slightly warm vs very warm is a proven contradiction, and one truth per axis holds: The tool is very fast. then The tool is fast. flags the looser value as dead weight.
  • Types — Animals ARE one of alligator, orangutan declares a closed, mutually-exclusive set.
  • String literals — "…" escapes to literal prose: no operators parsed inside, quotes stripped on compile, @{refs} still expand.
  • Sections & structure — group with # headings or <xml_tags> (same-line and inline content welcome); <$name> strips control-plane scaffolding, <?name> strips just the wrapper tag, <"name"> keeps its body verbatim (a literal zone for reference tables and syntax samples — quotes are the one escape, here at section scale), and <examples> is the literal zone by name. Structure is enforced: content must live in a section, # headings must sit inside XML sections once you use any, and section names must be distinct and meaningful — duplicate/near-duplicate names error, vague ones warn.
  • Definition lists — term:: definition rows for glossaries and cheat-sheets: position-insensitive to author (agents never break alignment), parse-literal (samples inside never open zones or bind) yet content-checked — one statement per line holds inside a body (the editor wraps; a hard-wrapped continuation is a compile error), terminators and the character set apply — and the compiler owns the emitted layout (nested sub-bullets, fenced samples) so the model reads clean markdown regardless of authoring; duplicate terms flagged.
  • Statement annotations & references — @@ a note documents the statement below it (a docstring that compiles away and is inert to every analysis tier); @@ name: … also names that statement. References are typed sigils, each validated at compile time: @{variable} reads host state, @<section> inlines a section, @[tool] references a tool — inline it emits the checked bare name, alone on a line it surfaces name — description (a dangling reference is an error, and an exact tool name in bare prose is too: point it or quote it).
  • A consistency checker — propositional + SMT (Z3). Catches MUST escalate vs NEVER escalate, and numeric contradictions like at most 3 sentences vs at least 5 sentences that propositional logic provably can't decide. Its quantifier layer gives the English of quantity its logic: the square of opposition (all / some / no / most / only), set sizes (there is only one tool vs there are many tools; nouns fold by lemma, so people ⇄ person), grammatical number as a claim (one dog counts exactly one — counting things is exact, floors are explicit (at least, more than, over); a bare plural own claims 2 or more, so You have one dog. vs You have dogs. is a contradiction; a dog stays existential — an instance, never a count — and a modifier never blocks the read: great dogs still counts dogs, with great landing as a quality claim on the same slot Your dogs are great. claims), action counts (call five tools vs call six tools — one count per directive slot), supply vs demand (there is only one tool vs call five tools), definite reference (the tool with two tools declared), and transitive syllogism chains. Claims key by what they are about (noun + restrictor tail); frame, subject, and owner are refinement fields that must agree where present but never exempt a claim from checking. Directives default to the ADDRESSEE — a bare rule, You must…, a declared alias (You are Claude. → Claude must…), and a declared role (You are a support agent. → the support agent must…) are one subject's rules, while an undeclared the assistant stays scoped (no guessing; opt nouns in via glish.tgc $CONFIG addressee one of …) and the user is never you. Guards parse in both spellings — IF … THEN … and the comma form English writes (If the user is angry, never quote prices.); Don't reads as DO NOT.
  • A predicate system — actions parse into verb + theme + roles + tool binding against a curated catalog, so the checker also proves verb-level facts: synonyms merge (output/print), antonyms conflict (MUST output vs MUST suppress flips the badge), bare imperatives are obligations, and fire book_appointment ≡ call book_appointment.
  • A semantic auditor (advisory) — per-line residual value and overlap, scored at the atom level by a local NLI model with an LLM-judge escalation (every verdict distilled as training data for an offline replacement). Heavy duplication warns; proposed cuts are behaviorally verified; a greedy reducer consolidates toward a minimal, orthogonal prompt.
  • The TG score — one proof-backed number per prompt (typeglish score, CI-gateable with --min B). Proven errors gate to F; graded facets measure enforceability (the checker's own visibility), hardness (how binding the language is — force words on a spectrum, must/never/all at the poles, may/sometimes in the soft middle; 1.0 renders pure bold), consistency, structure, annotation coverage (every statement should carry a @@ note saying what it's for), style, security, and density; every deducted point cites a finding + fix (the ledger is the to-do list). Calibrated against an authored good/bad corpus with a tested separation margin.
  • $TEST — the file carries its own eval suite — cases whose - input:: / - expect:: bullets live beside the rules they test, or in an auto-discovered sibling <name>.test.tg, and compile away entirely. Deterministic asserts (contains, matches, at most N sentences) are code-checked; prose expectations are judge-scored. Run them with typeglish test (--dry validates the suite + reports rule coverage fully offline; live runs need ANTHROPIC_API_KEY); feeds coverage (prompt/untested-rule), the profile, promptfoo emit, portability, and the optimizer.
  • $EXAMPLE — the file carries its own few-shot — one exchange per block (- input:: / - good::, optional - bad::), the same bullet record. Each - good:: compiles into the prompt as a labelled few-shot exchange; - bad:: is held out — never shown to the model, so it can't be imitated. A malformed block is a structure/bad-example error.
  • The profile — per-statement attribution: what a line says (IR, predicates), what duplicates it (residual), which cases exercise it, and the measured ablation Δ per case (npm run profiles -- --behavioral, budget-confirmed; repo dev tool). Those fold into a per-statement verdict — potency (Δ) crossed with redundancy (residual) and coverage → keep / cut (implied or dead) / test, with attribution and honest degradation when a tier hasn't run. npm run annotate (repo) writes it into the margin as //@ machine comments — compile-stripped, human comments untouched. Shared statement hovers use snapshot-qualified occurrence IDs; optional evidence is bound to the full source/configuration, and measured behavior also needs runner, judge, bindings, imports and rubric provenance.
  • Portability, measured — npm run portability (repo dev tool) runs the suite across a model panel (promptfoo owns the matrix; TypeGlish owns zero dependencies) and reports cross-model agreement WITH per-model pass rates beside it — consistency ≠ correctness is encoded, not footnoted.
  • A dependency map — the playground's Map view renders the prompt as the graph it already is: the depended-upon symbols (inputs with their domains, tools, variables, tests) on one side, the section skeleton with a reference chip on every wired line on the other, and hover to light up an edge — where a symbol is used, or what a line depends on. Broken edges (a <closing> that resolves to nothing, an unused import) are marked in place, from the same resolution engine as the squiggles, so the map can never disagree with the checker. Deterministic and free.
  • A fix list, ranked by score impact — the playground's Fixes panel is the score ledger made actionable: every deduction below 100, ordered by the points it costs, pinned to its line, with a one-click fix where one exists. Deterministic and free — it updates as you type, and it never spends a model call. This is "highlight what needs changing," computed, not judged.
  • A GEPA optimizer with the compiler in the loop — npm run optimize (repo dev tool; a deliberate CLI opt-in — the editor highlights, the human changes) runs reflective prompt evolution (per-instance Pareto, minibatch acceptance) where provably-broken mutants are rejected free before any eval spend, mutants that touch their own $TEST blocks are rejected as fitness hacking, and the accept rule breaks ties toward fewer tokens — the bloat spiral of naive optimization loops structurally loses. Every model call (evals AND reflections) is charged against the budget, so the pre-run quote is a hard spend ceiling; the result lands as a new .optimized.tg, never overwriting the seed.
  • Conditionals, resolved — deterministic IF chains / guarded sections make a prompt a template: (source, state) → prompt. Two stages, one seam (prepareTemplate): render is state-free and total — an unresolved chain compiles to conditional English (If voice is true: … / Otherwise: …), never a leaked sigil; resolve is state-dependent and partial — it collapses only the branches the bag can decide. The playground's values panel exposes it: set an input and the Compiled view resolves that chain to the one branch the model gets; leave it unset and it stays conditional.
  • A compiler — text → parse → IR → check → emit: @{references} expand, comments / @@ notes / $-commands / $TEST blocks strip, $EXAMPLE blocks emit their good few-shot (bad held out), and structure is preserved as authored — # headings stay markdown, <tags> stay tags (the two are never interconverted; they carry different signals).
  • Agent files — a single .tg file can be a whole agent: $CONFIG sets the model and settings, $TOOL / $SERVICE define tools as YAML-shaped code with HTTP bindings, and compile() emits the prompt plus an agent bundle (settings + JSON-Schema tool definitions). npm run tg:run agent.tg runs it live — tool-use loop, bindings, and {env.*} secrets included.

The full language reference is in SPEC.md.

Quickstart

The package ships runnable examples in examples/ — real agents, checked in CI so they can never rot. Five commands from install to a deployable prompt:

npm i -D typeglish
npx typeglish check node_modules/typeglish/examples/support-agent.tg
npx typeglish check node_modules/typeglish/examples/support-agent-draft.tg
npx typeglish score node_modules/typeglish/examples/support-agent.tg --min B
npx typeglish build node_modules/typeglish/examples/support-agent.tg
npx typeglish test node_modules/typeglish/examples/support-agent.tg --dry
npx typeglish --explain prompt/hedging

The two support agents are the same agent twice: the draft is hedged prose ("Try to avoid…", "kind of short") and the linter lights it up; the final commits to modals and scores an A. build writes the deployable artifact plus a hash manifest; --explain tells you what any finding means and how to fix it. Then write your own agent.tg and run the same loop.

The repo

src/core/        the language + compiler (pure TS — runs in Node, browser, and tests alike)
  typeglish-grammar.ts   the grammar (Peggy / PEG)
  parser.ts, ast.ts      parse a clause → statement AST
  ir.ts                  lower the AST → logical-form IR (directives, conditions, numeric bounds)
  layers/                ONE FILE PER SEMANTIC LAYER — assignment, possession, definiteness,
                         quantity, frequency, deontic, order, redundancy, references, statements,
                         style, spelling; the registry (layers/index.ts) welds the roster
  world.ts               the world model: the object graph + aliases + addressee → buildWorld()
  diagnostics.ts         the orchestrator: build the world once → run every layer's checks
  prompt.ts              render + PromptDoc (what the model reads; the ablation API)
  compile.ts             render → semantic XML + the agent bundle
  tool.ts                $TOOL / $SERVICE definitions (tool schemas + HTTP bindings)
  agent.ts               the runner: the tool-use loop + HTTP bindings (Node-side, like z3)
  solver/z3.ts           the SMT consistency checker (deontic + numeric)
  predicate.ts, verbs.ts the predicate system: action parser + the curated verb catalog
  semantic/              the advisory tier: atoms, NLI engine, judge + distillation, reducer
src/lib/         the published surface — the `typeglish` bin (check / build / score / test / resolve /
                 reference / mcp / claude-hook; cli-surface.ts is the table --help derives from),
                 build.ts (artifact + hash manifest + the scaffolding failsafe), deploy-gate.ts,
                 claude-hook.ts, test-run.ts (the $TEST runner), project.ts (glish.tgc discovery),
                 `typeglish/monaco`, `typeglish/spell`, `typeglish/vf` (the platform boundary:
                 vf-read.ts + voiceflow-write.ts, severed from the compiler — ~24 kB, not 2.36 MB)
src/mcp/         the MCP head — `typeglish mcp`: one stateless tool per served verb (check, build,
                  score, review, explain, statements, prepare-rewrite, brief-rewrite, review-rewrite, reference — MCP_TOOLS in cli-surface.ts), results
                 byte-shaped like the CLI --json (the LSP pattern, one transport over)
lsp/             the stdio LSP head (editor language services)
plugin/          the Claude Code plugin — skill + PostToolUse check hook + PreToolUse deploy gate
                 (served by .claude-plugin/marketplace.json at the repo root)
docs/agents/     TYPEGLISH.md — the GENERATED agent language reference (AGENTS.md-style consumers)
examples/        runnable sample agents — shipped in the package, compiler-locked in CI (examples.test.ts)
src/web/         the playground — a Monaco editor that consumes `src/lib` (it's the first consumer).
                 ONE app, TWO surfaces (hosted.ts): localhost = the dev cockpit (Copilot, Test runs,
                 the dogfooded copilot.tg seed); any build = the PUBLIC playground (curated seeds,
                 no server features). brand/ is the Sandcastle design system vendored from
                 typeglish.dev (npm run sync:brand)
server/          the Node side (LLM calls + the server-side Z3 logic check) as Vite middleware

Changing the language? Every operator, type, character rule, and diagnostic code lives in exactly one single-source-of-truth module — see the SSOT registry in CLAUDE.md (invariant #1). Edit the SSOT, run npm run gen:syntax, and let the drift-lock tests tell you what else to update; a hardcoded copy anywhere else fails CI.

Install

Zero-setup — the CLI has no required runtime dependencies (the Z3 proof tier is an optional dependency npm fetches by default; --omit=optional skips it), so npx just works:

npx typeglish check prompts/ [--json]       # exit 1 on any provable error (a directory checks
                                            #   every .tg inside, fileset manifest order first)
npx typeglish check prompt.tg --fix         # apply the declared-safe fixes in place first (whitespace,
                                            #   the character set, terminators), then check the result
npx typeglish review prompt.tg              # one run, one report: findings, the rules table, the score,
                                            #   and the fixes ranked by projected gain — in the order you act
npx typeglish build prompts/                # everything that passes → .typeglish/dist/*.txt
                                            #   artifacts + a hash manifest; refusals named
npx typeglish fmt prompts/ --check          # mechanical formatting gate (in place without --check)
npx typeglish score prompt.tg --min B          # the TG score; exit 1 below the floor (the CI gate)
npx typeglish resolve prompt.tg --vars '{"tier":"premium"}'
npx typeglish --explain logic/contradiction    # what any diagnostic code (or score facet) means
npx typeglish --explain enforceability prompt.tg  # …and, with a file, where it applies: the lines, the rules table
npx typeglish mcp                              # the same tools over MCP stdio (for shell-less agent hosts)
npx typeglish lsp                              # the language server over stdio (VS Code / Neovim / Zed / any LSP editor)

build is the deploy contract: the artifact — compile(source).xml — is what a prompt-taking system (a system prompt, an assistant API, Voiceflow) should receive, and the manifest proves any payload byte-for-byte ("this exact prompt came out of a passing compile"). A file with a blocking error refuses to build; nothing failing can enter the manifest.

In a project, npm i -D typeglish gives you the full checker: z3-solver (the SMT proof tier — contradictions, unsatisfiable bounds, exhaustiveness) is an optionalDependency, so npm installs it by default and degrades gracefully where it can't. Spell-check stays opt-in:

npm i -D typeglish                                # full tier out of the box (z3 auto-installs)
npm i -D typeglish --omit=optional                # lean install — skip the 33MB z3 WASM
npm i -D nspell dictionary-en dictionary-en-gb    # + spell-check (the typeglish/spell module)

Without z3-solver, check runs the synchronous tier (still the full language/consistency/structure check) and says so on stderr — a degraded checker is never silent. Requires Node ≥ 20.19.

Embed in your product (Monaco)

Any product with a Monaco editor gets the full TypeGlish experience — syntax highlighting, the object-record hover (each card ends in its relations map — painted, line-linked edges), completion, live consistency squiggles, object-reference highlighting, and list/operator authoring — in a couple of calls:

import * as monaco from 'monaco-editor';
import { setupTypeGlish, attachTypeGlish } from 'typeglish/monaco';
import 'typeglish/monaco.css';

setupTypeGlish(monaco);                                              // once per monaco instance
const editor = monaco.editor.create(el, { language: 'typeglish', theme: 'typeglish-dark' });
attachTypeGlish(monaco, editor);                                    // per editor → squiggles, highlights, authoring

Need just the compiler (no editor)? The core runs anywhere — Node or browser:

import { compile } from 'typeglish';
const { diagnostics, consistent, xml } = compile(source);

Every rule lives in the framework-agnostic core; typeglish/monaco only wires it to Monaco's APIs. The playground in src/web/ is the first consumer of exactly this surface.

Live playground sync with your coding agent

Choose Connect CLI in the playground, copy its agent prompt, and give that prompt to your coding agent on the same computer. The prompt asks the agent to do two things:

npm install --global typeglish@latest
typeglish sync --connect <details> --agent "<agent name>"

The connection details bind the CLI to this tab's origin, loopback port, and secret. The agent keeps the sync command running and the playground connects automatically. There is no pairing link to paste back, no folder to select, and no request to move the agent into another project. The current playground folder supplies its prompts to an isolated session workspace created by the CLI; no existing local folder is searched or imported. Keep the tab and command running. Waiting survives a tab reload.

Automatic connection details and sessions do not expire with time. Copying the prompt refreshes its secret and port; copy it again for the agent if its port is occupied. Cancel connection stops waiting. Neither action stops an unrelated local process. Treat the prompt's connection details as private. An explicit retry with the same details recovers a lost pairing response without creating a second session.

For manual setup, npx typeglish sync ./prompts --origin https://typeglish.dev still prints a five-minute pairing link. Expand Use a pairing link instead in the dialog to paste it. Use the exact playground origin (including a development port when applicable). Your coding agent works on ordinary local .tg / .tgc files; the playground picks up edits, additions, renames and deletions. Browser text edits save back to the same files. No account, model credentials, remote relay or embedded agent is involved.

The agent waits for instructions after connecting. Subsequent edits use the session workspace path printed by the CLI. That workspace is stored in the OS temporary directory and retained on exit for recovery; export work you want to keep permanently. Explicit folder sync remains available with typeglish sync <folder>. File-management actions in the playground are disabled while paired; make those changes through your agent.

The bridge binds only to 127.0.0.1, accepts one paired session and the specified browser origin, and skips symlinks, hidden directories, node_modules, dist, and vendor. It supports up to 512 files, 512 KiB per file, 8 MiB total, and 20 folder levels. Manual pairing links expire after five minutes; disconnecting revokes the session and original connection details. Automatic pairing has no time limit; for an expired manual pairing link, restart the command.

Concurrent browser/disk edits produce a conflict with both versions visible. Choose which version to keep. Browser writes check the last disk revision and retain before/after recovery copies under .typeglish-sync in the folder; these copies may contain sensitive prompt text, are never synced, and are excluded from Git by a local ignore file. Filesystem writes by other processes do not share a lock, so revision checks cannot rule out a change in the final check/rename interval. Prefer one active editor per file. On a network interruption, the same open bridge reconnects automatically.

The connection and unsent drafts survive reload in that tab's session storage. The pre-connection playground draft has a separate recovery slot: disconnect, then choose Restore previous playground draft. Closing the tab ends that recovery lifetime; save or download unsent work first. Hosted pages access the loopback bridge directly and may require local-network permission; browser policies can block this. If connection fails, allow that permission or use a local playground with an exact matching --origin. No prompt content is uploaded to the hosted site by this bridge.

For an unreleased source checkout, substitute node --import tsx src/lib/cli.ts for npx typeglish (or node dist/cli.js after npm run build:lib).

Portable authoring tools

The playground, language server and package share the same authoring operations:

import { analyzePrompt, annotatePrompt, cleanPrompt, refinePrompt, selectPromptContent, compressPrompt, consolidatePrompt, refreshAnnotations, applyPromptEdit } from 'typeglish';

const analysis = analyzePrompt(source); // diagnostics, explanations, grammatical words, classification coverage, score, cache
const proposal = annotatePrompt(source); // add missing @@ notes; preserve existing notes
const annotated = applyPromptEdit(source, proposal); // refuses a stale source snapshot
const cleaned = cleanPrompt(annotated); // formatting + declared-safe repairs
const refined = refinePrompt(annotated); // supported statement refinements; authored notes stay intact
const selection = selectPromptContent(refined.text); // independent editorial selection + source-span decisions
const compressed = compressPrompt(refined.text); // selection + shorter realization in one plan
const conservative = compressPrompt(refined.text, { policy: 'conservative' }); // no editorial content selection
const consolidated = consolidatePrompt(compressed.text); // remove covered policies; inspect surviving-witness receipts
const refreshed = refreshAnnotations(annotated); // explicitly replace repairable existing notes

Statement optimization uses an explicit concise-instruction policy: it can reduce selected rhetorical emphasis, shorten assigned-goal framing and consolidate adjacent repeated standing guidance. These edits retain supported actions and scope, but intentionally relax some effort/quality maximization; they do not promise identical model behavior. contentSelection and selectionRounds receipts identify those choices; each round carries its own source snapshot. Unknown constructions and authored annotations remain intact. Neither operation uses an LLM.

Consolidation is independently callable and runs between compression and organization in the import pipeline. It preserves unique content and removes only supported covered policy sentences; repeated events, unresolved references, timing differences and authored notes remain protected. Receipts name an earlier surviving witness for every omission. The CLI and explicit LSP source.consolidate.typeglish action share the same core edit plan and original source guards.

explainStatements(source) also exposes the existing parser result and span-carrying compiler facts. These explanations are deterministic readings, not proof of arbitrary English equivalence. Existing notes can be current, stale, or unverified; missing notes do not warn. Annotation coverage in the TG score still measures presence, not accuracy. The default compile behavior is unchanged; opt in with annotationChecks: true, or use analyzePrompt. coach: false removes annotation advisories.

analyzeWords(source, { glishConfig }) exposes the shared grammatical records independently: original token spans, lexical candidates, contextual class, lemma and evidence. Hover, highlighting and word profiles use these records too. classificationCoverage(source) reports resolved, ambiguous and unknown tokens separately; it measures classification coverage, not semantic understanding or classification accuracy. Unknown vocabulary is never silently labeled a noun. The editor APIs accept the same WordAnalysisOptions: semanticTokens(source, options), cardAt(source, line, column, options), hoverAt(source, line, column, alerts, options) and wordObjects(source, tokens, options). Monaco's attachTypeGlish accepts a live analysisOptions getter; call refreshAnalysisContext() after project configuration changes without a text edit.

analyzeStatements(source, options?) provides the central statement metadata used by statement hovers and agent tools. Each record includes exact source, occurrence ID, annotation, section/scope, parsed clauses, grammatical words, facts, metrics, diagnostics and explicit relationships. inspectStatement(analysis, idOrZeroBasedPhysicalLine) returns one record with related statements and entities. Unknown or stale IDs return null.

import { analyzeStatements, inspectStatement } from 'typeglish';
const statements = analyzeStatements(source, { glishConfig });
const first = statements.statements[0];
const context = first ? inspectStatement(statements, first.id) : null;

The CLI typeglish statements prompt.tg --json, MCP typeglish_statements, and LSP request typeglish/statementAnalysis expose this same read-only contract. CLI/MCP line selectors are one-based physical lines; core/LSP coordinates are zero-based. The analysis is document-scoped, does not expand imports, and invokes neither a model nor Z3. Semantic readings remain explicitly partial; absent, stale and unavailable evaluation results are distinct. attachStatementEvidence can add results bound to their original statementSnapshot, without re-running core analysis. Oversized documents retain source and statement inventory while enrichment is marked unavailable.

For agent-authored rewrites, prepareRewrite(source, options?) produces compact context bound to that source and configuration. The agent supplies candidate wording, then reviewRewrite(source, candidate, { baseline: preparation.snapshot, mappings? }, options?) checks the binding, reports source and context changes, and compares diagnostics and estimated rendered tokens. Optional mapping groups contain sourceIds, candidateIds and a reason; prepare the candidate with the same options to obtain its occurrence IDs. Mappings declare provenance and do not prove preserved meaning. Unsupported edits remain unverified. Neither operation writes files, calls a model, applies the candidate or runs the authoring pipeline.

npx typeglish annotate prompt.tg              # print proposed source
npx typeglish annotate prompt.tg --refresh    # explicitly refresh existing notes
npx typeglish cleanup prompt.tg --check      # read-only drift check
npx typeglish cleanup prompt.tg --fix        # apply mechanical cleanup
npx typeglish refine prompt.tg              # preview supported statement refinements
npx typeglish refine prompt.tg --fix         # apply the refinement plan
npx typeglish compress prompt.tg --json      # preview statement rewrites and word savings
npx typeglish compress prompt.tg --fix       # apply the compression plan
npx typeglish consolidate prompt.tg --json   # preview covered-policy removals and retained witnesses
npx typeglish consolidate prompt.tg --fix    # apply the consolidation plan
npx typeglish analyze prompt.tg --json       # document report, synchronous tier
npx typeglish statements prompt.tg --json    # shared metadata for all statement occurrences
npx typeglish statements prompt.tg --line 4 --json # statement + related context at physical line 4
npx typeglish prepare-rewrite prompt.tg --json > baseline.json # save context for your agent
npx typeglish review-rewrite prompt.tg --candidate candidate.tg --baseline baseline.json --json

The corresponding MCP tools are typeglish_prepare_rewrite and typeglish_review_rewrite. Preparation returns {file?, preparation}; review returns {file?, review}. Review accepts the baseline snapshot, candidate source, optional candidateSnapshot, and optional mappings. CLI --baseline accepts a saved preparation envelope, core preparation or bare snapshot; --mapping accepts a JSON array. Invalid requests and stale bindings exit 2; a valid review with changes exits 0. MCP marks invalid reviews with isError while retaining the structured report.

All authoring commands leave files unchanged unless --fix is supplied. The report describes one document; compose imports first for a composed prompt. Token counts are estimates and cacheability is potential prefix reuse, not measured provider cache hits. It does not run Z3 or an LLM.

The LSP offers explicit source actions for adding annotations, refreshing annotations, cleanup, refinement and statement compression, plus annotation warnings with individual Refresh annotation quick fixes. Source actions require versioned-edit support; older clients retain legacy quick fixes. The playground supplies controls, worker transport, draft storage and undo.

Develop

npm install
npm run dev          # the playground at http://localhost:5273 (VITE_HOSTED=1 previews the public surface)
npm run sync:brand   # re-vendor the Sandcastle design tokens, components + logo from typeglish.dev
npm run typecheck
npm test             # ~2,300 unit tests cover the language, checker, score, and semantic kernel
npm run check -- prompt.tg [--json]               # compiler errors + warnings, agent-friendly (exit 1 on errors)
npm run score -- prompt.tg [--full] [--min B]     # the TG score + ledger (exit 1 below --min: the CI gate)
npm run tg:test -- prompt.tg [--dry] [--min 0.7]  # run the suite (inline + sibling .test.tg): per-case pass/fail
npm run fmt -- prompt.tg [--write]                # join wrapped fragments, split compound rules
npm run profiles -- prompt.tg [--behavioral --yes] # per-statement attribution (static free; Δ costs, confirmed)
npm run annotate -- prompt.tg [--write|--clean]   # write the profile into //@ margin comments
npm run emit -- promptfoo prompt.tg               # the file's $TEST suite as a promptfoo config
npm run portability -- prompt.tg --models a,b     # cross-model agreement (then --results out.json)
npm run optimize -- prompt.tg --budget 24 [--estimate] [--json]  # GEPA; --estimate quotes cost (free), --json = agent-readable result
npm run semantic -- prompt.tg              # per-line residual/overlap audit (add --reduce, --actions)
npm run semantic:bench                     # regenerate the golden-pair benchmark report

The compiler core has no browser dependencies, so the grammar, the IR, and the solver behave identically in Node, the browser, and Vitest.

Agents in the loop

The compiler talks back to agents at the moment their work SETTLES — the turn boundary — never mid-typing (half-written text is legitimately broken). The mental model everywhere is TypeScript for prompts: the .tg is source in git, the deployed prompt is a build artifact, and the gate between them is mechanical.

  • In Claude Code, install the plugin and the whole loop runs itself:

    /plugin marketplace add Bradenream/TypeGlish
    /plugin install typeglish@typeglish
    • A skill teaches the workflow — author .tg → check → score → build → deploy the artifact verbatim — with the generated language reference as its deep material.
    • A PostToolUse hook re-checks every settled .tg edit and feeds blocking diagnostics straight back to the model as fix-now feedback (advisories ride along as context; clean files stay silent).
    • A PreToolUse deploy gate hashes outgoing prompt payloads (Voiceflow MCP tools by default; configurable via .typeglish/deploy-gate.json) against .typeglish/build-manifest.json: a prompt no passing build produced is denied with the fix in the message, and a verified one still goes through the normal permission flow — the gate never auto-approves. Escape hatches: TYPEGLISH_DEPLOY_GATE=off|ask.
  • In the playground, the Copilot gets a turn-end compiler report: when its edits land, the merged diagnostics are diffed against the turn-start snapshot and reported — as a ⚙ row in the transcript and as compiler truth in the model's history. A turn that introduced errors triggers one automatic fix round (toggleable, never recursive).

  • Any other agent with a shell (Cursor, a CI bot, …) gets the same truth from npx typeglish check|score|build --json — data on stdout, diagnostics on stderr, exit codes as gates, typeglish --explain <code> for what any code means. Wire the same loop into any hook system.

  • Shell-less hosts (claude.ai, any MCP client) get the compiler through ten MCP tools — npx -y typeglish mcp — check / build / score / review / statements / brief-rewrite / prepare-rewrite / review-rewrite / explain / reference, with results byte-identical to the CLI's --json. A host with no filesystem passes source inline; build returns the artifact + its sha256 without persisting.

  • Teaching the language: typeglish reference prints the generated agent reference (docs/agents/TYPEGLISH.md is the same document, committed for AGENTS.md-style consumers), so an agent that has never seen TypeGlish can learn it in one read.

License

TypeGlish is licensed under the PolyForm Noncommercial License 1.0.0: free for personal, research, education, and other noncommercial use. Any commercial use requires a commercial license from Voiceflow, Inc. Versions through 0.7.2 were published under Apache-2.0 and remain available under that license. Third-party attributions (Open English WordNet CC-BY-4.0, Princeton WordNet, and others) are listed in NOTICE.