Skip to content

Latest commit

 

History

136 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

TEL, the Typed Element Language

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

Features

  • 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.

Quick tour

Pragma

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 #.

Compounds and atoms

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

Hosting other languages

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)"
        ---

Document streams

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.

Schemas

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

Validators

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

Patterns

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}

Binary form (BinTEL)

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.

BASE-256

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.

Where to go next

  • 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 canonical tels self-bootstrap.

About

Typed Element Language

Resources

Stars

2 stars

Watchers

2 watching

Forks

Contributors

Languages