The built-in vocabulary archive
Normative. The kinds a manifest names without an import — Telo.Application,
Telo.Library, Telo.Definition, Telo.Abstract, Telo.Import, Telo.NeedType,
Telo.JsonSchema, Telo.Function, the sinks, the capability roles, the public-address need
types — and the shapes they share are the built-in vocabulary. Its source is the data under
sdk/builtins/ (sdk/builtins/README.md); this document specifies the form one telo release
renders it in, publishes it in and prints it in. The Node reference is
scripts/render-builtin-vocabulary.mjs (rendering), readBuiltinVocabulary (reading) and
selectBuiltins (slicing), both in the analyzer.
1. The document
A YAML stream. The first document is the root; every later document is one built-in kind.
- The root is
kind: Telo.Builtinswithmetadata:name: Telo— the vocabulary is the module everyTelo.<Kind>names;version— the telo release whose vocabulary this is:Xfor a release,X+unreleasedfor a build of a tree whose release is still pending;description— search text;license: MIT.
- The root carries four sections, each a map keyed by name:
$defs— every shared schema fragment, unexpanded. A fragment refers to another as$ref: telo://manifest#/$defs/<Name>. No key starts withtelo:(that prefix is the analyzer's for a fragment it hoists into a schema).valueTypes— every value type, keyed by itsname(Telo.Url), each entry its data file verbatim (sdk/value-types/).zoneAttributes— every zone attribute, keyed by itsname(noSuspend), verbatim (sdk/zone-attributes/).formats— every Telo string format, keyed by itsname(css-selector,language-tag,message-pattern), verbatim (sdk/formats/).
- Every later document is a built-in in its authored form:
kindisTelo.Abstract,Telo.DefinitionorTelo.NeedType, and no document carriescontrollers:— the root's kind says once that the runtime implements every kind in the archive. A fragment reference stays a reference; the two lists derived from the capability roster (thecapability:enum and thethrows:allowlist) are written out, so the archive states which capabilities are legal. - Closure. Every
telo://manifest#/$defs/<Name>the archive holds names an entry of$defs; everyx-telo-type— and every type argument naming one — an entry ofvalueTypes; every zone attribute an entry ofzoneAttributes; everyformat:that is no JSON Schema format an entry offormats. A reader of one release's archive needs no other source. - Neither the
x-telo-*annotation vocabulary nor the CEL function catalog is in the archive: an annotation's meaning is its reader's behaviour, and no definition names a function.
2. Layout
The archive is rendered by one fixed emitter, so its bytes are a function of the vocabulary and the version alone. Every reader that slices it relies on this layout:
- UTF-8, LF line endings, a trailing newline, no tabs, anchors, tags or comments.
- Documents are joined by a line holding exactly
---; the root comes first, then one document per built-in in the lexical order of their entry files. - Block style with a two-space indent. A map's keys keep their source order; the keys of each
root section are in lexical order. An empty map or list is written
{}/[]. - Every document starts with a
kind:line, then ametadata:line whose first key isname:. - A string, and a key, is written plain when it starts with a letter,
_or$, continues with letters, digits and_ $ . / -, and is not one oftrue false null yes no on off y n ~in any case; otherwise it is written as a JSON string. No value spans more than one line. - A root section is a line at column 0 ending in
:; each of its entries is a line at column 2 ending in:, followed by the entry's body, every line of it indented further. A section with no entry is written<section>: {}.
3. Refusals
Telo.Builtins is read, never declared, run or imported. It is registered nowhere, so each
way of using it as a module is refused:
| Use | telo check | Node kernel | Rust kernel |
|---|---|---|---|
A file whose first document is Telo.Builtins, as the entry | one UNDEFINED_KIND at its kind: line, and nothing else from that file | ERR_MANIFEST_VALIDATION_FAILED carrying it | ERR_MANIFEST_VALIDATION_FAILED |
| A document of that kind in a module file | UNDEFINED_KIND | ERR_MANIFEST_VALIDATION_FAILED carrying it | — |
| An import whose target is an archive | INVALID_IMPORT_TARGET at the imports: entry | ERR_INVALID_IMPORT_TARGET carrying it | ERR_INVALID_IMPORT_TARGET |
The entry's and the document's message is "Telo.Builtins is the published built-in vocabulary
of a telo release; it is read, never declared, run or imported." The import's is "'imports: entry
and write them as Telo.<Kind>."<X> being the archive's metadata.version ("a telo
release" when it declares none).
4. telo builtins [<name>…]
Both CLIs print the archive of the telo they are, through their output seam, and never render
it: the Node CLI prints the bytes @telorun/analyzer exports as BUILTIN_VOCABULARY_ARCHIVE,
and the Rust CLI embeds the same file at build, refusing to build without it.
- With no name, the archive is written byte for byte.
- Each name selects one entry. A kind or need type is selected by its name with or without
Telo.(Application,Telo.Application) and prints its whole document. A fragment (Step), a value type (Telo.Url), a zone attribute (atomic) or a format (css-selector) prints its section's line followed by the entry's line and body. No name selects two entries; the renderer refuses an archive in which one would. - Several names print their entries in argument order, joined by a line holding
---. - A name that selects nothing writes nothing to stdout, writes "No built-in is named
'
'[, ' followed by one line per class listing every name of it, and exits 1.'…]. The names are:" - Under the Node CLI's
-o jsonthe same bytes are written as one JSON string. - There is no version flag. Another release's vocabulary is
telo module manifest oci://ghcr.io/telorun/telo@<X>;--jsonreports it withruntime: nullandapplication: null.
5. Publication
Every telo release X at or above the first that ships the archive is published as
oci://ghcr.io/telorun/telo@X.
@telorun/analyzer@Xcarries the archive atsrc/builtin-vocabulary/builtins.yaml, withsdk/LICENSEbeside it asLICENSE; the package refuses to pack unless the archive's version is exactlyX.telo publishaccepts aTelo.Builtinsroot as a manifest-only artifact: it runs no module analysis and refuses (manifest_invalid) an archivereadBuiltinVocabularyreports a problem with, one already carrying alayers:index, one whose version is a build of an unreleased tree, and one with noLICENSEbeside it. Its only other layer iscommon, holding thatLICENSE.- The published
telo.yamlis the archive's bytes with alayers:block appended at the end of the root document, nothing else changed: removing that block gives back the archive in@telorun/analyzer@Xbyte for byte. The pin gate applies, so a second push ofXwith different bytes is refused. - The publish workflow reconciles on every push to main: for each released
Xwhose tag is missing, it publishes the directory taken out of@telorun/analyzer@X's tarball with the checkout's CLI. There is no backfill below the first release that ships the archive.