10 · The real comparison

Why not just strict TypeScript + zod + eslint + ts-pattern?

Because every one of those guarantees is opt-in, and an agent can route around each of them in one line. Glyph's strictness isn't a config file the agent can edit — it's the language. The enforcement point moves from "did we remember to lint this file" to "does it compile."

First, the honest concession

A well-configured TypeScript setup gets you a long way, and if your team runs all of it in CI you've already closed most of the gaps Glyph targets. Credit where it's due — this is the real alternative, so here's the honest mapping:

what tooled TypeScript already gives you
no `any`            → noImplicitAny + @typescript-eslint/no-explicit-any
exhaustive match    → ts-pattern .exhaustive() (compile-time, today)
errors as values    → neverthrow / Effect
runtime validation  → zod at every boundary
must-handle errors  → an eslint rule
deterministic diffs → Biome / Prettier

If you have all that wired up and enforced, you're most of the way there. So the question isn't "does TypeScript lack these ideas" — it's "what does bundling them into a language, non-optionally, actually buy." Three things.

01 Non-optional beats opt-in

Your eslint config only protects code the agent routes through it — and the agent can write as unknown as User, @ts-ignore, // eslint-disable-next-line, or simply forget the .exhaustive(), and it still compiles and merges. Every one of those escape hatches is a config the agent can edit. Glyph has no such hatch to reach for: there is no as, no ignore pragma, no way to get a typed value out of unknown without a check the compiler can see.

TypeScript — the hatches exist handler.ts
const user = body as unknown as User;
// @ts-ignore
doThing(user.mispelled);
// eslint-disable-next-line
return anything as any;
Glyph — nothing to disable handler.glyph
return match User.parse(body) {
  Ok(user) => use(user),
  Err(_) => fallback(),
}
// no `as`, no ignore pragma,
// no lint to switch off.

The strictness the agent cannot config-disable is a categorically different enforcement point than the strictness it can. That's the whole bet.

02 The type is the validator — no second artifact

zod inverts your source of truth: you write the schema, derive the type from it, and then keep the type, the schema, and any serializer in sync by hand. Keeping those aligned is exactly where an agent introduces drift — it renames a field in the type and not the schema, and both still compile. In Glyph the type is the validator: declaring type User = {...} generates User.parse alongside it. One artifact, nothing to keep in sync, nothing to forget.

03 Greppable mutation

In TypeScript a state change can hide behind =, .push(), Object.assign, a setter, or a spread — there's no single token to search for, and no lint rule fully fixes it. In Glyph shared state lives in a store and every change is a literal .set(/.update(; grep 'mut ' finds every local mutation. That's a property you can't buy for stock TypeScript at any price.

The failure-mode diff

Same task, an agent adds a variant to a union and forgets to handle it in one of three places:

tooled TS
// ts-pattern .exhaustive() catches it —
// IF every site used ts-pattern and
// nobody wrote a plain switch or
// a default: case. One that didn't
// compiles green and returns undefined.
Glyph
[E0200] non-exhaustive match on
`Feed`: missing variant `Archived`
// every unhandled match, everywhere,
// fails the build. No opt-in, no
// escape, no forgotten default.

Where tooled TypeScript is still ahead (the honest edge)

This cuts both ways, and pretending otherwise would be exactly the dishonesty this page is trying to avoid:

So the honest summary: if you've fully wired tooled TypeScript and your agents stay inside it, you've got most of this. Glyph's argument is that "stay inside it" is the load-bearing phrase — and it's the phrase an agent breaks. Non-optionality, one-artifact validation, and greppable mutation are the parts you genuinely cannot get by adding more opt-in tools.

Where it stands

Shipping today

No any/as, exhaustive match (E0200/E0218), discarded-Result warning (E0217), type-generated validators, and greppable mutation — all non-optional, none an eslint rule you can disable.