LexLab builds tiny, deterministic lexical engines. The runtime, lexcore, packs spelling suggestions, ranked synonyms and similar words, structured dictionary queries, a rule-driven word-mutation engine, similarity scoring and natural-input parsing into a few hundred kilobytes of WebAssembly plus one data pack. No network, no server, and the same answer every time on every machine. LexLab is the local studio that assembles, prunes, trains, measures and ships those packs.
Everything is a module with a measured cost. A pack is a set of features you chose. The lexicon is mandatory and everything else is a menu, and every feature documents what it does, what degrades gracefully when you leave it out, and exactly how many bytes and microseconds it costs. Deterministic machinery (finite-state automata, a synset graph, regex rules) generates and validates candidates; small learned artifacts (crystals, a scorer model, a suggest ranker) only order them, and each is bound to the pack it was trained on by hash. When two designs tie, the smaller one wins.
bun run check # the full gate: format, lints, tests, T0 (budgets are tests)
bun run lab # the studio, at http://localhost:5177
bun run build:core # build the en-GB core pack from its preset
bun run t1 pipelines/presets/full.json # the standard evaluation tierYou need Bun 1.4 or newer, stable Rust with the wasm32-unknown-unknown target, and wasm-pack. Raw source data (SCOWL, Open English WordNet, wordfreq, and friends) lives in sources/downloads/, pinned by sha256 in sources/registry.json; see docs/sources.md. The Playground needs the wasm packages, which bun run t0 builds.
| pack | words | wire (zstd) | contents |
|---|---|---|---|
en-GB-nano |
47,563 | 202 KB | lexicon + fuzzy search |
en-GB-moderate |
47,563 | 203 KB | nano + word flags + leet-speak mutation rules |
en-GB-core |
47,563 | 652 KB | nano + the synset graph (ranked synonyms, similar words), structured queries, spelling variants |
en-GB-intent |
47,563 | 666 KB | core + the datetime, quantity and command grammars |
en-GB-full |
261,318 | 1.99 MB | core + frequencies, inflections, flags, hypernym/hyponym/similar/also relations, mutation rules, pronunciation, TLD data, hypervectors, and a 796-byte learned ranker for suggest |
en-US-full |
261,318 | 1.62 MB | the same, for American English |
The wasm builds are nano 181 KB, core 221 KB and full 311 KB. Every build opens any pack and says, with a structured Unsupported error, when a call needs a feature the pack or the build does not carry.
Measured on en-GB-full: spelling suggestions put the right word first 92 % of the time on the Wikipedia misspelling corpus (77 % with the hand-written rank), every golden synonym pair is reachable, and warm calls run in microseconds. The current numbers and the reports behind them live in docs/status.md and eval/reports/.
| path | what it is |
|---|---|
crates/lexcore |
the engine: feature-gated, no I/O, never panics across its boundary |
crates/lexpack |
the builder: source parsers, filters, the pack writer, and a CLI (build, sizes, graph-stats) |
crates/lexwasm |
wasm bindings and TypeScript glue, one build per profile, plus mutate.ts (in browsers the mutation rules run on the host's own regex engine, validated against the wasm lexicon in one batched call) |
crates/lexffi |
the C ABI |
lab/ |
the studio: twelve screens on a Bun server, no framework |
eval/ |
thresholds, the T0/T1/T2 harnesses, the corpora, and the frozen JavaScript rule tables with the conformance oracle that keeps the Rust port at 100 % agreement |
pipelines/ |
pack presets, rule sources and workflows the builder consumes |
scripts/ |
the T0/T1/T2/conformance/check entry points and the wasm build |
sources/ |
the download registry (sha256-pinned raw data, licenses) |
fixtures/ |
the tiny committed pack, corpus fixtures and the two plugin fixtures |
models/, crystals/, labels/ |
trained artifacts (scorer models, rankers, crystals) and their label sets |
docs/ |
the contracts and the map, indexed below |
Start with docs/north-star.md, then docs/architecture.md for the map.
| page | what it holds |
|---|---|
| north-star.md | what LexLab is and why it exists |
| architecture.md | the map: every layer, and which file owns each behaviour |
| status.md | the current measured numbers, and conditions to know |
| api.md | CONTRACT — the engine's calls and their Unsupported guarantees |
| pack-format.md | CONTRACT — the pack's byte layout, segment by segment |
| hdc-vectors.md | CONTRACT — hypervectors and crystals |
| scorer.md | CONTRACT — scorer-model formats |
| plugin-spec.md | CONTRACT — studio plugins |
| studio.md | the studio shell and every screen |
| teach.md | the Teach flow: the three things a pack can learn |
| sources.md | raw data sources: pinning, restaging, licenses |
| style.md | the style guide for code and docs |
../lexlab-master-spec.md |
the master implementation brief the project was built from |
eval/thresholds.json is the contract for the measurement tiers, and eval/reports/ holds the reports behind every number quoted anywhere.
Budgets are tests. A pack or binary over its size or latency budget fails T0, and the remedy is to shrink or drop, never to shrug. Builds are byte-reproducible: same inputs, same hash, on any machine. Nothing is measured optimistically: every number in the studio is either measured and labelled with its source, counted from the real word list, or visibly an estimate.