# Roadmap overview Original 12-step plan: `archive/glyph-strategy.md`. Revisions to steps 4–9 are logged in the per-step docs in this folder. Where this file and `archive/glyph-strategy.md` disagree, this file wins. For the live day-by-day implementation record, see `docs/implementation-plan.md`. > This file is the **build roadmap** — the 12 steps that produced the toolchain. For the **release roadmap** — the 0.1.x feature releases layered on top, with the next target marked — see [`releases.md`](releases.md). ## Phase 1 — Make it programmable | # | Step | Status | Source of truth | |---|------|--------|-----------------| | 1 | Manifesto (≤2000 words, four pillars, three before/after examples) | ✅ Done | `docs/manifesto.md` | | 2 | Lock syntax with examples (30–50 small programs) | ⚠️ Partial — ~14 programs (4 hard-case examples, 9 `examples/corpus/` programs, and the dogfood fridge app), all parsing, emitting, and passing `tsc --strict`. The remaining ~16–36 grow out of step 6 dogfooding apps (Q2 folded it in). | `archive/SESSION_1.md`, `examples/` | | 3 | Formal grammar + tree-sitter parser | ⚠️ Written as reference spec, not verified — the production parser is the hand-written Rust Pratt parser in `glyph-compiler/crates/glyph-parser/` (per Q5 hybrid). The tree-sitter grammar in `archive/` survives as an editor-tooling source. | `docs/language/grammar-status.md` | | 4 | Transpiler to TypeScript (originally 4–6 weeks; revised 6–8) | ✅ **Done — Phase 1 complete (weeks 1–8).** Full pipeline (lex → parse → resolve → typecheck → emit) behind `glyph build [--check] [--test]`, `glyph run`, `glyph fmt`, `glyph --explain`. AST→TS visitor emits every declaration/statement/expression form, lowers `match`/`?`/JSX, emits Q8 descriptors (now recursive), bundles a runtime + generated `tsconfig`; `--check` runs `tsc --strict`. Hand-written TS stdlib wrappers; compile-time `@example`/`@doc @run`/property tests; stable diagnostic codes + `--explain`; negative suite + proptest fuzzing + CI. All four examples, the nine `examples/corpus/` programs, and the dogfood app pass `tsc --strict`. | `docs/roadmap/04-transpiler.md`, `docs/implementation-plan.md` | | 5 | Typechecker (originally 4–6 weeks → revised ~9 weeks) | ✅ **Done at v1 scope (substep 5a).** Match exhaustiveness (user + prelude `Result`/`Option`, nested-constructor, array-length, `bool`); the full `?` rule (no `From` in v1); call/`await` synthesis; match-arm payload typing; local `let` inference; generic instantiation; primitive return-type mismatch; **D25 `owned` single-consumption**; **Q8 descriptors for records + tagged unions**. Dogfooding then added **member-access (E0210) and call-argument (E0211) checking** and **`mut`-on-`const` (E0212)**. Deferred to v1.1 (forward-compatible, non-blocking): a fuller unifier; mapped types / `infer_shape` (5b); flow-narrowing (5c); generic-record/union deep validation; the remaining `owned` consume forms; number/string value-match. | `docs/roadmap/05-typechecker.md`, `docs/implementation-plan.md` | | 6 | Dogfood (originally 2 weeks → revised to 4–6 weeks, sequential apps) | 🟨 **Core complete; soft exit pending.** The fridge shopping-list app (`examples/apps/fridge.glyph`) was built, used across its whole command surface, and extended (merge-on-add, summary), over three rounds: build+use, extend+round-2 findings, and an adversarial review with round-3 fixes. The 20-item gap list (`docs/dogfooding-gaps.md`) is driven to **zero open bugs** — the critical/high tier fixed, the medium/low tier fixed or resolved as documented v1.1 deferrals. Remaining (soft) exit: sustained personal use and the optional app #2; re-lock the syntax corpus before step 7 if dogfooding produced spec changes (it did not). | `docs/roadmap/06-dogfooding.md`, `docs/dogfooding-gaps.md` | ## Phase 2 — Make it usable | # | Step | Status | Source of truth | |---|------|--------|-----------------| | 7 | Ship the LSP (4 weeks → revised 5–6 weeks) | ✅ **v1 complete.** New `glyph-lsp` crate (tower-lsp + tokio), launched via `glyph lsp` over stdio. All eight v1 deliverables ship and are verified end to end over JSON-RPC: **diagnostics** (parse/resolve/typecheck errors with stable codes + help, UTF-16 ranges), **hover** types, **go-to-definition** (within-file + cross-module via D15 full-path imports), **completion** (keywords/decls/prelude), **format-on-save**, **document + workspace symbols** (Q12), the **canonical agent view** (Q32 core: `glyph fmt` layout + stable `Lddd` line numbers + per-declaration FNV-1a fingerprints, via `glyph canonical` and the `glyph/canonicalView` request), and the **gated structured edit** (Q29: `glyph/applyEdit` applies LSP `TextEdit`s only if the result type-checks clean, else rejects with the would-be errors — the abandoned `edit{}@verify{}` syntax re-derived as a protocol op). A **VS Code extension** (`editors/vscode/`) makes it installable. v1.1 tails: rename, find-references, Q32 SSA renaming + position mapper, and Q29 test-suite gating. | `docs/roadmap/07-lsp.md` | | 8 | Formatter and package story (2 weeks) | 🟦 Planned, `glyph.json` rejected in favor of `"glyph"` key in `package.json` | `docs/roadmap/08-09-packaging.md` | | 9 | Installer and playground (2 weeks) | ✅ **Done.** Installer = the npm CLI distribution (step 8). Playground = `playground/` — a zero-backend web playground where the compiler runs in the browser as WebAssembly (`crates/glyph-wasm` exposes `compile(source) -> { ts, diagnostics }`, built to wasm32 + wasm-bindgen). Three panes: live Glyph editor, the emitted TypeScript, and a diff-stability demo (an agent's one-line Glyph edit → a one-line TS diff). `build.sh` regenerates the wasm; `.github/workflows/playground.yml` deploys it to GitHub Pages. Verified end to end (the real web artifact compiles in Node; all assets serve with correct MIME). | `playground/`, `docs/roadmap/08-09-packaging.md` | | 10 | Docs and book outline (4 weeks) | 🟨 **User-facing docs shipped:** `docs/guide/` (five-minute tour, getting-started, Glyph-for-TypeScript-developers delta sheet, 30-minute todo-CLI tutorial — every snippet compiles) plus `docs/book-outline.md`. Remaining: the complete prose reference (the spec covers it for now) and writing the book itself. | `docs/guide/`, `docs/book-outline.md` | | 11 | Killer demo (6–8 weeks) | 🟨 **Evidence shipped (honest, reproducible).** `benchmarks/verifiability/` — paired programs where Glyph rejects a bug `tsc --strict` accepts (non-exhaustive match, unsafe cast), asserted by `check.sh`. Density: Glyph ~26% fewer tokens than equivalent TypeScript across the 3 measured functions. Diff stability is demonstrated live in the playground. Synthesized in `benchmarks/FINDINGS.md`. **Deliberately not claimed:** a measured agent-productivity speedup (it is framed as the hypothesis these structural metrics support, pending a real agent study). | `benchmarks/FINDINGS.md` | | 12 | Launch + first 100 users | 🟨 **Materials drafted; execution is manual.** `docs/launch/`: Show HN post, announcement, v0.1 release notes, and a first-100-users onboarding plan (co-designer framing). Every claim traces to `FINDINGS.md`. Remaining (human): enable GitHub Pages, post, and run outreach. | `docs/launch/` | ## Timeline honesty The original strategy says **6–9 months focused work, 12–18 months calendar** for v0.1. Two revisions stretch the critical path before that estimate has accounted for them: - Step 5: 4–6 weeks → **~13 weeks** (+7–9 weeks) - Step 6: 2 weeks → **4–6 weeks** (+2–4 weeks) The honest revised range is **9–12 months focused work, 15–24 months calendar**, *assuming* steps 7–12 don't undergo similar expansion when their turns come. They probably will. Plan accordingly. ## The trap at every step Scope creep. At step 5, effect types. At step 7, a custom protocol instead of LSP. At step 11, rewriting the compiler. The discipline that ships a language is saying "v0.2" to every good idea not on this list. ## Self-hosting **Non-goal for v1.0** (promoted from a year-three deferral in session 2). The compiler is Rust until v1.0 ships and there are users. ## Current status (where the work actually is) **Phase 1 is complete and step 6 (dogfooding) is core-complete.** The compiler works end to end (`glyph build`/`run`/`fmt`/`--test`/`--explain`), the fridge dogfood app has been built, used, extended, and hardened across three rounds, and the gap list it produced is closed (no open bugs; remaining items are forward-compatible v1.1 deferrals — see `docs/dogfooding-gaps.md`). **Next is Phase 2 (steps 7–12), none of which is started:** the LSP / editor support (7), the npm package story (8 — the `glyph fmt` half is done), the installer + web playground (9), docs + book (10), the killer demo (11), and launch / first users (12). An early, scrappy exposure to an outside engineering group pulls a thin slice of steps 7/9/10/12 forward (a quickstart, a TS-developer tour, and basic editor highlighting) ahead of building them properly — useful for signal, but those prerequisites do not yet exist. The historical day-by-day record below is retained for traceability. ## What's blocking forward motion right now The two original blockers are **resolved** as of the 2026-05-26 brainstorm sessions: 1. **`infer_shape` v1 or v2** → **v1.1** (Q1). `01_validator.glyph` was rewritten with an explicit output type parameter; substep 5b is no longer mandatory for v1. 2. **Compiler architecture: salsa-style incremental queries or not** → **Q5 hybrid**. The typechecker + name resolver are salsa-backed; AST→TS emission stays a dumb visitor. Both shipped as of day 12 (full per-decl invalidation, automatic cross-file diagnostics). Current near-term work (per `docs/implementation-plan.md`): the typechecker's substep 5a is complete for the v1 scope — the Week-2 and Week-3 task lists are fully done (exhaustiveness incl. `bool`, the full `?` operand/`E` rule, `owned` with the `?` checkpoint, local `let` inference, the D15 barrel-file diagnostic, and Q8 descriptors for records and tagged unions). **Week-4 TS emission**: the core AST→TS visitor ships and `glyph build` writes a `.ts` per clean module. Tagged-union declarations emit (discriminated unions + constructors), and `match` over a tagged union lowers to a `switch` on `tag` in both statement position (direct) and value position (IIFE). The emitter is now type-aware (it receives the resolved module + type map), which let bare no-payload variant arms (`Idle`) lower as `case` labels, a bare-identifier arm the scrutinee type does not confirm as a variant lower as a binding catch-all (a `default` that binds the scrutinee to the name, which stays runtime-correct because a `tag` switch's `default` catches exactly the unlisted variants), the `?` operator unwraps a `Result` at statement position (`let x = E?`, a bare `E?`, or `let x = await E?` — the parser binds a trailing `?` to the whole `await` per D18), and value (literal) matches switch on the scrutinee, array matches (`[]`, `["add", ...rest]`, `[a, b]`) lower to a length-and-element `if`-chain that binds elements by index and `...rest` by slice, statement-position block-body match arms emit their statements into the case, non-generic record types emit a Q8 runtime descriptor (an `is` type guard plus a `parse` entry point that validates an `unknown` into a `Result`, with the `Ok`/`Err` shape inlined so no `std/result` import is needed), `is TypeName` match patterns lower to an `if`-chain that consumes the guard (so the Q8 descriptor is both emitted and used), and generic tagged unions emit (type-parameterized constructors, ``-widened no-payload consts), a `match` that is the whole body of an arm lowers as a nested statement `switch` inheriting the arm's termination (not a value IIFE), so its inner arms may `return` or use block bodies, and a non-`void` function or block implicitly returns its tail expression (a bare tail expression becomes `return expr`, a tail `match` returns each arm's value, a tail `E?` returns its unwrapped `Ok` payload), which `tsc --strict` requires (a dropped tail value falls off the end, TS2355). With those in place example 04 emits end-to-end with no diagnostics. `await` placement on a method chain is now correct (Glyph async is colorless, so the await-spine walk emits `(await load(p)).map_err(f)`, awaiting the head async call rather than the whole chain), and a nested `?` (mid-chain `await x?.foo()`, a `?` in an argument/template/operand) hoists out of its expression to a preceding `Result` unwrap and is replaced by a read of the `Ok` payload (the whole-value `?` goes through the same path). The two-binding `for K, V in it` lowers by the iterand type: a record (a plain object) uses `Object.entries(it)` (string keys), a statically-typed array uses `it.entries()` (numeric index), defaulting to the record form when the type is unknown. A nested constructor pattern (`Err(NetworkError({ status }))`) is rewritten so each outer variant with nested arms dispatches its payload through an inner `match`. A `component` (D19) emits as a React function component and JSX (D6) lowers to `React.createElement`, with the directives lowered structurally (``/`` → ternary, `` → `.map`, ``/`` → a switch-returning IIFE binding `x` to the same-named payload field). Lambdas now also implicitly return their tail and infer un-annotated parameters. An adversarial review of the emitted output then found and fixed two runtime-correctness bugs: a mid-chain `?` under an `await` now awaits the head async call before the unwrap (`const __r = (await load(p)); if (__r.tag === "Err") return __r; ... __r.value`) rather than binding a pending Promise, and the two-binding `for` over an array uses a numeric `.entries()` index. **With these, all four `examples/*.glyph` emit TypeScript via `glyph build` with no diagnostics** — the "emit" half of the Phase 1 Week 4 gate is met. For the `tsc --strict --noEmit` half, the runtime prelude and stdlib type surface now exist (`glyph-compiler/runtime/` + `examples/.types/` for the examples' external imports); the `Result` combinators are unblocked by the `?` operator re-wrapping its propagated error, record descriptors emit a `T.schema` member, and the React stub types JSX event handlers. The emitter also narrows `is`-match scrutinees so the output type-checks (it checks a plain-identifier scrutinee directly, and emits an `is Record` check as a type-predicate IIFE), and casts a generic function's return value to its declared return type when that type references one of the function's type parameters (the v1 stand-in for infer_shape, Q1: `object_schema` returns a `Record` as `Out` via `return { ... } as Schema`). **All four hard-case examples and all nine `examples/corpus/` programs now pass `tsc --strict` against the runtime — the Phase 1 Week 4 emission gate is fully met.** A fuller unifier (which also unblocks exhaustiveness for generic module-local unions) remains on the typechecker side. **Week 5 is complete:** the v1 stdlib ships as hand-written TypeScript wrappers (the Q41 v1 FFI path; a Glyph-source stdlib needs FFI/v2 + union methods); `glyph run examples/04_cli_tool.glyph add "buy milk"` runs end to end via `tsx`; and `glyph fmt` reprints the AST in one canonical, round-tripping, comment-preserving layout (the `glyph-formatter` crate; the lexer now recovers comments and the formatter interleaves them by position). **Week 6 is complete:** `glyph build --test` runs `@example` equalities (D23), `@doc @run` doc blocks (D26, via triple-quoted-string lexing + an `assert` built-in), and property tests (`std/test.property` over a `std/stream` generator, Q11) — all by reusing the emitter + `tsx` (one source of semantics), failing the build on any failure. **Week 7 is complete:** every diagnostic carries a stable code (parser `E000x`, resolver `E01xx`, typechecker `E02xx`, emitter `E03xx`), an actionable `help` line, and an optional `note`; `glyph --explain ` prints a long-form fix, and `docs/error-codes.md` catalogues them (Q6 Elm-quality bar). **Week 8 is complete:** an 18-case negative-example suite (`tests/negative/`, each asserting an exact error code), proptest fuzzing of the parser/lexer (totality) and the exhaustiveness checker, GitHub Actions CI (tests + `tsc --strict` on the examples), and an approximate token-count metric in the benchmark track. **Phase 1 (the Rust compiler) is complete** — the toolchain works end to end (`glyph build`/`run`/`fmt`/`build --test`/`--explain`). **Step 6 (dogfood) is now core-complete** (see the Current-status section above and `docs/dogfooding-gaps.md`); the next milestone is Phase 2, starting with step 7 (LSP). Active open questions are tracked in `docs/open-questions.md`.