TEL is a tree-structured data format designed to be edited by humans, agents, and processors alike.
Structure is carried by indentation and a single sigil character (# by default); everything else
is content. The result is a notation that reads like the data it represents, with no escaping rules
to learn and no punctuation to balance.
tel 1.0
project alpha
description Demo of TEL features
contributor Alice
contributor Bob # was Robert
- Minimal markup. Indentation and a configurable sigil are all that distinguish structure from content; everything else is data.
- Hosts other languages without escaping. A scalar value may be carried as an indented block (a source atom) or as a delimited payload (a literal atom) — JSON, XML, Markdown, shell scripts, and the like embed verbatim.
- Schemas and types. A schema names records, sums, scalars, and validators. Definition names are
PascalCase (
Contact,PhoneNumber); field and variant keywords are kebab-case. Documents are checked against their schema during parsing. - User-extensible validation. A schema attaches named validators to scalars and structs; the parser calls back to the application to run them.
- Layered schemas with safe evolution. A base schema may be refined by ordered layers; every permitted layer operation produces a subtype of the base, so older readers can still consume newer documents.
- Concise binary wire format. Every well-typed TEL document has an unambiguous BinTEL encoding (typically ~2× smaller than the text) for hashing, transmission, or storage.
- BASE-256 textual carrier. When the wire format must travel in a text channel, BASE-256 encodes one byte as one Unicode letter — half the length of hex, copy-paste-safe, no escaping required.
- Faithful round-trips. Programmatic edits preserve comments, blank lines, atom form, and tabulation alignment wherever they aren't directly changed.
A TEL document may begin with a pragma identifying the version, optional schema, and optional sigil:
tel 1.0
tel 1.0 example.org/contact:1.2.0 %
tel 1.0 example.org/contact +postal ḅHrïЖqẍḱăLḅHrïЖqẍḱăLḅHrïЖqẍḱăLḅHrïЖqẍ
The schema is identified by a LIRA reference (domain/name, optionally with a :version or
:tag selector), optional +layer selections, and/or a bare BASE-256 schema signature. The
sigil overrides the default #.
An ordinary line — one that is not the pragma, an interpreter directive, a document separator, a comment, a tabulation, or part of a source or literal atom — is a compound: a keyword followed by zero or more inline atoms, and optionally child blocks at one greater indent.
contact alice
email alice@example.org
phone work +44 20 7946 0958
phone home +44 117 496 0123
A source atom is an indented block whose payload is captured verbatim, with the block's own indentation stripped. A literal atom uses an arbitrary delimiter line and preserves every byte of its payload — including trailing spaces, leading whitespace, and the sigil character. Because nothing is stripped, the payload begins at column zero; the closing delimiter line mirrors the opening one exactly, indentation included.
fixture sample-payload
description
A JSON document carried inside TEL,
with no escaping or fence wrapping.
json
{ "name": "Fido", "kind": "dog" }
shell
---
#!/usr/bin/env bash
echo "Greetings from $(hostname)"
---
A single source can hold a sequence of independent documents, one after another, like
newline-delimited JSON. A line consisting of exactly two sigil characters — ## by default — is a
document separator: it ends the current document and begins the next on the following line. Each
document is independent, with its own pragma, sigil, and margin.
tel 1.0
greeting hello
##
tel 1.0
greeting world
A conforming processor must offer two ways to read such a source, neither of them a default. Single-document parsing reads one document and stops at the first separator; everything after it is left untouched. That makes a TEL document a convenient header for some other, possibly non-TEL, content:
tel 1.0
title Release notes
format markdown
##
# Everything below the separator is opaque to the TEL parser —
# it could be Markdown, CSV, or a binary blob.
The streaming form instead yields every document in order. A separator inside a literal atom's payload is preserved verbatim (it does not split the document); a trailing separator does not produce an empty final document.
A schema is itself a TEL document describing the shape of conforming documents. Three kinds of named
Definition coexist in one namespace: record (a product type), scalar (a leaf value with
validators), and select (a sum type — a named alternation of variants). At a member position,
field declares a single-keyword slot and select references a named sum. Cardinality defaults to
"exactly one"; optional loosens it to "zero or one" and repeatable to "one or more", so the two
together give "zero or more". Layers
may tighten these defaults in later versions but never loosen them.
tel 1.0
name contact
record PhoneNumber
field country-code String
field number String
select Status
variant active Flag
variant archived Flag
document
field name String
field email String optional
field phone PhoneNumber optional repeatable
select Status optional
A document under this schema:
tel 1.0 example.org/contact
name alice
email alice@example.org
phone
country-code 44
number 2079460958
active
Each scalar Definition must declare at least one validator or pattern — an unconstrained
scalar names the built-in String instead — and may declare several, applied in AND-conjunction. A record or
sum may carry its own validators for cross-field or cross-variant constraints. Validator names live
in a single shared namespace and are resolved at parse time by a host-language callback. Four
built-in validators are guaranteed by every conforming parser: identifier (kebab-case),
type-name (PascalCase), sigil (a single sigil character), and string (unconstrained).
scalar Hostname
validate non-empty
validate dns-label
record Event
field start-date String
field end-date String
validate start-precedes-end
A scalar may instead (or additionally) be constrained by RE2 patterns, matched against the
entire value; repeated pattern lines intersect. Because RE2 patterns are true regular languages,
pattern containment is decidable: a layer may replace a scalar's patterns with a provably
narrower set, and the compatibility rules check the refinement rather than trusting it.
scalar ProductCode
pattern [A-Z]{2}-[0-9]{4}
layer regional
scalar ProductCode
pattern (EU|UK)-[0-9]{4}
Every well-typed TEL document has a deterministic BinTEL encoding (see
spec/bintel.md). BinTEL is type-tag-free — the schema supplies all typing, so
the byte stream encodes only keyword indices and scalar values. A BinTEL document begins with the
four bytes B2 C4 B5 BB, which render as the Greek letters βτελ in BASE-256 textual form,
followed by the document's length.
That length makes each document self-framing, so BinTEL has the same two reading modes as TEL source: read one document and hand the caller everything after it, or read a stream by recursing on that continuation. Because the length is read before anything else, a reader can delimit, count, skip or forward documents while resolving no schema at all.
The BLAKE3-256 hash of a BinTEL document root is the document's value hash: a stable, schema-aware identifier suitable for content addressing. Composed schemas (base + layers) are identified by a palimpsest of component hashes, encoded as a single BASE-256 token on the pragma line.
spec/base256.md describes a binary-to-text encoding that maps every byte to one
Unicode letter (or ASCII digit) drawn from a fixed 256-character alphabet. A BASE-256-encoded string
is one word under Unicode word-segmentation (double-click selects the whole token), contains no
whitespace or punctuation, and decodes losslessly via a single modulo operation.
spec/tel.md— the full TEL specification (25 sections, formal type system, error taxonomy, machine operations, round-trip properties).spec/bintel.md— the BinTEL wire format.spec/telp.md— TELP, the path language for addressing elements of a document's semantic model by keyword and key value.spec/palimpsest.md— the palimpsest construction used in composed schema signatures.spec/base256.md— the BASE-256 textual encoding.demo/— worked schemas and documents covering inline/source/literal atoms, layered schemas, struct validators, and the canonicaltelsself-bootstrap.