v0.1.123 · early preview →

Ask the compiler what your change breaks.

Glyph compiles to TypeScript you can read, so you adopt it one file at a time and keep node, npm and everything you already deploy. What it adds is a compiler that answers questions about your program instead of leaving an agent to rediscover them with grep. Add a case to a union and it names every match that will fail, and every match that will keep compiling while silently swallowing it.

$ npm install -g @glyphlang/glyph
module welcome import std/result { Result, Ok, Err } pub type Role =  | Admin  | Member  | Guest pub type User = {  email: string,  role: Role,} pub fn welcome(user: User) -> Result<string, string> {  return match user.role {    Admin => Ok("Welcome back, admin"),    Member => Ok("Hello, ${user.email}"),    Guest => Err("guests cannot sign in"),  }}
Passes tsc --strict Compiles to readable TS Written in Rust Exhaustiveness enforced

One change, on a real application

examples/apps/csvql is a CSV query engine in this repository, eleven files, with a Value union at its centre. Here is what happens when you add a case to it.

before touching anything: glyph_variants { name: "Value" }
10 match sites across 4 files
 8 will fail compilation
 2 contain a catch-all and will silently absorb it

FAILS   value.glyph:18    value::render
FAILS   value.glyph:32    value::key
FAILS   bind.glyph:148    bind::literal_kind
ABSORBS exec.glyph:130    exec::total
ABSORBS render.glyph:128  render::literal_text
...
then add the case for real, and run glyph check
8 errors, E0200 non-exhaustive match.
The same eight.

The two catch-all sites report nothing at all.

The prediction was exact, eight of eight. The interesting number is the other one. exec::total and render::literal_text keep compiling and route the new case wherever their catch-all points. No build, no test and no type error will ever mention them. An agent that fixes the eight failures and stops has a green tree and two live bugs, and this is the part a language server cannot tell it.

Seven bugs that pass tsc --strict

Every claim on this site has a pair of files behind it: a .ts that type-checks clean under tsc --strict, and the same program in Glyph that does not compile, with the error code named. A build gate re-runs all of them and fails if either half stops behaving, so a guarantee that quietly disappears takes the build with it.

scripts/check_catches.py
catches: 7/7 verified both ways (greppability: 1, verifiability: 6).

See the seven cases →

If you know TypeScript, you know most of this

Glyph reads almost identically. You don't learn a new language, just a handful of deltas. Each one trades a footgun for a guarantee. Here are the ones in the sample above.

match an exhaustive switch: the compiler makes you handle every case. There is no if/else; match is the only conditional, so a case can't be silently forgotten.
Result<T, E> errors as return values, not thrown exceptions. You handle one with match, or propagate it with the ? operator.
fn f() -> T a function; the -> is its return type. A type X = {...} is a record, and a type X = A | B is a tagged union.
mut x = e reassignment is explicit and greppable. A plain let binding never changes under you; you write mut to change one.

"Agents" here means AI coding assistants (Claude, Copilot, Cursor). Glyph helps them most, but the guarantees are plain engineering wins whether or not you use one, and if you already run strict TypeScript with zod and eslint, here's what a language buys over that →

The tax you already pay

If you build with AI agents on a TypeScript codebase, you know the daily cost. Glyph is TypeScript with these footguns removed.

Glyph removes each one, by construction.

Why Glyph wins

In order of what matters most. The first two are the wedge, the problems you feel every day. The last two are the polish that makes it pleasant.

Questions engineers actually ask

Real questions, straight answers: what works today, and what's next. Read them as one guided walk-through.

Write less. Break nothing.

Try the Playground →