Lexical Structure
This page restructures §2 of the specification as a reference for implementers. Osmol's lexical layer is small on purpose, but it is opinionated: the token set itself encodes the language's physics of knowledge, and one class of tokens exists only to die loudly.
Source form
Osmol source is UTF-8. Comments run from -- to end of line:
hold eta(dinner) = 19:40 ±5m, decays 20:00 -- uncertainty and decay, inline
Identifiers are lowercase kebab-case or dotted paths:
banh-mi-house
atlas.budget
status(atlas.review)
There is no uppercase convention to learn because there are no types to name, no classes to export, and no constants to shout. A twin's vocabulary is facts about a life, and facts are lowercase.
Literal forms
The literal forms are chosen so that time, uncertainty, and decay (the physics of knowledge) are first-class tokens rather than library calls. A value in Osmol is a datum with a shelf life, an error bar, and a resolution.
| Form | Examples | Meaning |
|---|---|---|
| Instant | 19:40, fri, 2026-08-01, +45m | A point in time; +45m is relative to now |
| Period | day, week, 30m | A duration, used by every and budgets |
| Time range | 22:00-07:00 | An interval, used by quiet |
| Quantity with unit | 12km, 3 seats | Numbers carry their units |
| Uncertainty suffix | ±5m, ±0.2 | An explicit error bar on a value |
| Confidence suffix | @0.8 | Assertion confidence; defaults to @1.0 |
| Granularity grain | coarse(30m), coarse(city), coarse(week) | A resolution on the granularity lattice |
A holding like hold eta(dinner) = 19:40 ±5m @0.9, decays 20:00 is therefore expressible without a single library import: the instant, its uncertainty, its confidence, and its expiry are all lexical.
Strings
Strings are double-quoted and legal only inside express. This is Axiom V doing lexical work: prose is a controlled substance. Everywhere else in the language, values must be typed literals a machine can reason about: an eta is an instant, not a sentence about an instant. Free text exists in exactly one construct, the human lane, where it crosses the mesh verbatim and provenance-stamped. A string outside express is not a style violation; it does not tokenize.
Reserved words
The reserved words, exactly as spec §2 lists them:
twin, hold, seek, owe, decide, among, express, to, membrane, attention,
bond, trust, assume, yield, role, stake, on, toward, by, else, when,
decays, until, every, interrupts, quiet, threshold, escalate, sync,
drop, exact, coarse, category, existence, deny, family, team, others, all
Thirty-nine words. This is the entire keyword surface of the language, and none of them is a verb of transmission.
Tombstone words
A second reserved list exists for one purpose only, producing a compile error:
send, notify, broadcast, blast, cc, bcc, forward, reply
These eight words are reserved solely to fire error[O-000]: there is no send. They have no production in the grammar, no semantics, and no future. They exist so that the old world's verbs die loudly rather than quietly. A newcomer who types send gets the whole philosophy of the language in one diagnostic instead of a confusing unexpected identifier.
Implementers: the tombstone check should be the fastest error your toolchain can produce. The engineering dissertation places it at the lexer, before parsing exists.
Implementation note: how v0.1 tokenizes
The reference interpreter (osmol.py, normative for v0.1 behavior) does not run a general tokenizer. It works line by line: each line is stripped of comments, then matched against a table of regular expressions (the RX table), one pattern per declaration form. A line that matches no pattern is an unrecognized declaration, and that is a hard error. There is no "unknown statement, skipping" in this language.
Two ordering rules in osmol.py are worth carrying into any implementation:
- Tombstones are checked before anything else. Every line passes
tombstone_checkbefore any declaration pattern is tried, sosenddies with O-000 even inside an otherwise unparseable line. - Strings are stripped first. The tombstone check removes double-quoted spans before scanning for tombstone words, because strings are payload:
express to raj: "I will reply tomorrow"is legal. The human lane may say anything; only the grammar is forbidden the old verbs.
The line-oriented approach is a documented v0.1 pragma, not the language's final word. The Rust core specifies a handwritten lexer with proper spans (dissertation, Chapter 2). But the two rules above are semantics, not implementation detail: keep them.
Related
- The Formal Grammar: the EBNF these tokens feed
- What Cannot Be Written: the load-bearing absences
- O-000, Tombstone Verb: the diagnostic the tombstone list exists for
- Granularity: the lattice behind
coarse(...)grains