Document (dev.stxt.website): Frequently asked questions — STXT Metadata: Author: Joan Costa Mombiela Revision: Claude Fable 5 Last modif: 2026-08-30 Description: Frequently asked questions about STXT: what the name means, how it differs from XML, YAML, JSON and Markdown, how validation works and how to get started. Header: Frequently asked questions Subheader: The language Subsubheader: What does the name STXT mean? Content >> The first version of the language was called **STxT** (*Semantic Text*); that is where the name and the "s-text" pronunciation come from. @STXT@ is its evolution: it keeps the original spirit and motivation, but has been transformed so much since then — the same idea, executed from another perspective — that it can be considered almost another language. References to *STxT* that may still be found refer to the old language; @STXT@, written like this, is always the current one. To avoid confusion — and because it can be misleading — the term *Semantic Text* has also been retired: the name is simply @STXT@. Subsubheader: Is it a language or a format? Content >> Both words are correct: they look at the same thing from different angles. "Language" puts the focus on the grammar and on the person writing: syntax rules, a specification, something that is learned and written by hand. "Format" puts the focus on the role that syntax plays when a system stores or exchanges something with it. They are not exclusive categories — XML literally stands for *Extensible Markup **Language*** and nobody hesitates to say "a file in XML format" — but two ways of looking. @STXT@ **is a language**: that is how it defines itself, and the whole Human-First design follows from that starting point — a grammar meant to be written by hand, five normative specifications, schemas, tools. And it **acts as a format** wherever a system employs it: as the source format of a CMS, as a configuration format, as an interchange format between agents. The first word says what it is; the second, the role it plays in each case. Subsubheader: Is it a data format or a document format? Content >> Both, because the line between them is artificial: an email has fields and a body, a contract has clauses and metadata, a configuration has values and long comments. @STXT@ is a tree of named nodes; each node carries either a value and children, or a block of text. That describes a data record as well as a twenty-page document. The [use cases](use-cases-corporate-docs) walk through that range. Subsubheader: What sets it apart from other formats? Content >> @STXT@ is designed for people, and the characteristics that define it follow from that principle: * **Simplicity on three planes.** The rules to know fit in one page; a conforming parser is a line-by-line pass with a stack and is written in days, without libraries. The cost of parsing is linear, in a single pass, with no backtracking or references. * **Indentation is the structure.** One tab or four spaces per level; the level of a line is decided from that line alone. No braces, brackets, mandatory quotes or closing tags. * **Free text is literal.** Everything indented under a `>>` node is text as written, with no escapes and no quotes; `:`, `#` and `>>` have no meaning inside it. * **No escape characters.** Any character is allowed in a value or a block; in exchange, node names do have restrictions. * **Parsing safety by design.** No entities, references, anchors, file inclusion or code execution; ASCII namespaces, no ambiguous identifiers. See [STXT-SPEC §15](stxt-core-ref#s15). * **Separate, optional and closed validation.** The parser needs no schemas; but there is an optional, simple schema system, adequate for most cases. The reasoning behind each of these decisions is in [Design principles](design-principles). Subsubheader: Which file extension and media type are used? Content >> Extension `.stxt`; media type `text/stxt` (IANA registration planned, not yet registered), with `text/plain` as a compatible alternative. UTF-8 without BOM (a parser also accepts the BOM), `LF` line endings (`CRLF` is accepted). See [STXT-SPEC §3](stxt-core-ref#s3) and [§13](stxt-core-ref#s13). Subsubheader: Can you show us a real use? Content >> The one you are reading: this very portal. Every page of `stxt.dev` — the tutorial, the use cases, the five specifications, this FAQ — is written in @STXT@, and a static site generator turns them into the HTML in front of you. There are two ways to check: the `.stxt` link in the header opens the source of the current page, and appending `.stxt` to any page's address returns its code as is — for example, [faq.stxt](faq.stxt) is the source of this very page. The generator is public too: [stxt-cms](https://github.com/stxt-lang/stxt-cms). How a CMS exploits @STXT@ as its source format is developed in [CMS and publishing](use-cases-cms). Subheader: Why not...? Subsubheader: Why not XML, YAML or TOML? Content >> None of these formats is a mistake; each optimizes for something else. The table compares, criterion by criterion, the design decisions of @STXT@ with those of the formats that usually come up in the same conversation: | | @STXT@ | XML | YAML | TOML | |---|---|---|---|---| | **Human-First** | Designed to be written by hand; the rules fit in one page | Verbose: closing tags, attributes, escapes | Readable, but with subtle rules: optional quotes, values that change type | Clear for flat configuration; nesting goes in `[a.b.c]` headers | | **Schemas and validation** | Built into the language, optional and closed | Three schema languages —DTD, XSD and RELAX NG—, each an ecosystem of its own | None; validated with tools from other ecosystems | None | | **Ease of parsing** | Linear, in a single pass; a conforming parser is written in days | Requires an industrial parser | Huge specification; parsers disagree with each other | Approachable, with laborious edges: dates, tables, strings | | **Attack surface** | No entities, references, anchors or code execution ([STXT-SPEC §15](stxt-core-ref#s15)) | External entities (XXE) and entity expansion | Expandable anchors and tags that instantiate objects | Small | | **Free text** | Literal `>>` blocks: any character, no escapes | Escape `<` and `&`, or CDATA | Block scalars with subtle indentation and chomping rules | Multi-line strings between triple quotes | The comparison with each format is developed on its own page: [STXT vs XML](stxt-vs-xml), [STXT vs YAML](stxt-vs-yaml) and [STXT vs TOML](stxt-vs-toml). Subsubheader: Why not Markdown? Content >> Markdown is not an alternative to @STXT@: **it is its complement**. They cover different domains —Markdown gives **format** to prose: bold, links, lists within the text; @STXT@ gives **structure** to the document: nodes, hierarchy, validation— and that is why they work together. In fact, `MARKDOWN` is the only embedded format the schemas define: a node declared with that type marks its text as formatted prose, to be interpreted as CommonMark, and its raw form remains readable. See [STXT-SCHEMA-SPEC §9.7](stxt-schema-ref#s9-7); the division of work between the two is developed in [STXT vs Markdown](stxt-vs-markdown). Code >> Article: Style guide Summary >> A MARKDOWN block admits **bold**, [links](https://stxt.dev) or lists; the structure of the document comes from the nodes around it. Subsubheader: Why not JSON? Content >> Because JSON is not meant to be written by hand: it is a serialization format for machines. Everything goes between quotes, braces and commas; line breaks are written `\n`; there are no comments, and a long text ends up on a single line full of escapes. None of that is a flaw —JSON promises nothing else—, but it rules it out as a Human-First format. The [STXT vs JSON](stxt-vs-json) page develops the comparison — and the reverse path: the canonical JSON tree every @STXT@ tool can emit. Subsubheader: Why are there no lists? Content >> Because everything is a list. The children of a node are an ordered sequence, and the same name may be repeated as many times as needed; the tree preserves the order of appearance. An @STXT@ document is already a list of root nodes, and every inline node is a list of children. That is why no separate syntax is needed to express one. A list of elements of the same kind is written as a container node with the same child repeated: Code >> Authors: Author: María Pérez Author: Juan García Author: Ana López Content >> With a schema, the child's cardinality (`Min`/`Max`, or `(+)` and `(*)` in a template) fixes how many times it may appear. And since the children of any node may have different names, a heterogeneous sequence —chapters and annexes interleaved, for instance— needs nothing more than writing them in order. It is a consequence of having few forms and none redundant; see [Design principles](design-principles) and [STXT-SPEC §8.5](stxt-core-ref#s8-5). Subsubheader: Why are there no escape characters? Content >> Because they are not needed. @STXT@ syntax has meaning at only two points of a line: the node name and the separator (`:` or `>>`) that follows it. Everything after the separator is the value, and everything indented under a `>>` is literal text; in neither of them is there anything to escape, because the parser looks for nothing there. A value may contain `:`, a block may contain `#` or `>>`, and a backslash is a backslash. Code >> Path: C:\Users\ana\docs Note >> The symbols :, # and >> mean nothing here. Content >> The price is paid in node names. Technically it was enough to exclude from them the characters that delimit the syntax —`:`, `>` and the parentheses—, but following the Human-First principle they are limited to letters, digits and the separators `-`, `_` and space (`INVALID_NODE_NAME` otherwise): this way a symbol inside a name does not suggest a meaning that does not exist in @STXT@. See [Design principles](design-principles) and [STXT-SPEC §4.2](stxt-core-ref#s4-2). Subsubheader: Why can a text block not have children? Content >> Not because of a technical limitation —it could be done— but by design: allowing it would go against the Human-First principle on three fronts. * **Visual noise.** To know where the text ends and the children begin, an end-of-block marker would be needed, and a document would no longer read like an outline of notes. * **More complexity in the parser.** Today a line under a `>>` is text, with no further analysis; with possible children, every line would require a decision. * **Mixed meaning.** A node that needs both children and a text block is describing two different things, and that points to two nodes. That is why a node is one of two things, and not both at once: an inline node, with a value and children, or a block, with text. And the way to write it is the same in every case: the block is one more child of an inline node, next to whatever siblings it needs. Code >> Chapter: Introduction Author: María Pérez Summary >> Basic concepts: monoliths, microservices and design criteria. Content >> The chapter presents... Content >> This way `Chapter` carries the structure —title, author, summary, content— and each block carries only text. With a schema, `Summary` and `Content` are declared of type `TEXT` (or `MARKDOWN`), and a type with content validation admits no children. See [STXT-SPEC §6](stxt-core-ref#s6) and [STXT-SCHEMA-SPEC §9.1](stxt-schema-ref#s9-1). Subheader: Writing documents Subsubheader: Tabs or spaces? Content >> Both are valid and equivalent: **one tab is one level, four spaces are one level**. Mixing them in the indentation of a single line is not valid (error `INDENTATION_MIXED`), nor is any other width (two spaces are not half a level: they are an error). Different lines of a document may use different styles; `stxt format --tabs` or `--spaces` unify the style of a file. The fixed width is deliberate: the level of a line is computed from that line alone, and the hierarchy looks the same in every editor. A visually more compact indentation is obtained with tabs and the editor's tab width. See [STXT-SPEC §8.1](stxt-core-ref#s8-1). Subsubheader: Do case, accents and spaces matter in names? Content >> Names are compared by their **canonical name**: lower case, and every run of spaces, hyphens and underscores reduced to a single hyphen. Accents and non-Latin letters are kept. So: * `Date of birth`, `date_of_birth` and `Date-Of-Birth` are the same node. * `Título` and `título` are the same node; `Titulo` is another one. * `Caña` and `cana`, or `Peña` and `pena`, are different nodes. **Namespaces** are stricter: ASCII `[a-z0-9]` and dots only, at least `a.b`, and they are lower-cased. See [STXT-SPEC §4.3](stxt-core-ref#s4-3) and [§7](stxt-core-ref#s7). Subsubheader: How is a value with a colon or a hash inside written? Content >> Without any marker. In an inline node the value is everything after the **first** `:`, so `Time: 10:30` has the value `10:30`, and `#` only opens a comment when it is the first non-blank character of the line. Inside a `>>` block everything is literal text. Code >> Meeting: 10:30 in room 2 # this is part of the value Notes >> # this is text too, not a comment Key: value >> not a node either Subsubheader: Can a document have several root nodes? Content >> Yes. A file may contain several level-0 nodes, each with its own tree, and the tools return them in order. That allows *streaming* parsing of large files: each root is emitted complete as soon as the next one begins. Namespaces are not inherited sideways between roots: each declares its own. See [STXT-SPEC §8.5](stxt-core-ref#s8-5). Subsubheader: Can a document use several namespaces? Content >> Yes. Any node may declare its own namespace, and its descendants inherit it from it onwards; each namespace is validated against its own definition. This way a common vocabulary is defined once and incorporated from others: in the definition that incorporates it, the external child is declared with its namespace and its cardinality only. Code >> Book (com.acme.book): Title: Modern Software Architecture Review (com.acme.reviews): Reviewer: Ana López Score: 9 Content >> And the templates of the two namespaces: Code >> Template (@stxt.template): com.acme.book Structure >> Book: Title: (1) Review (com.acme.reviews): (*) Template (@stxt.template): com.acme.reviews Structure >> Review: Reviewer: (1) Score: (1) NUMBER Content >> `Reviewer` and `Score` belong to `com.acme.reviews` without writing it: they inherit it from `Review`, and each namespace is validated against its template; the [tutorial](tutorial#s14) develops the full example. See [STXT-SPEC §7.2](stxt-core-ref#s7-2) and [STXT-SCHEMA-SPEC §8](stxt-schema-ref#s8). Subsubheader: What about comments? Content >> A line whose first non-blank character is `#` is a comment. It is not part of the tree and does not move the hierarchy, but its indentation is validated like a node's: homogeneous style, multiples of 4 if spaces, and at most one level deeper than the last node. Blank lines are exempt. Inside a `>>` block, a `#` line indented deeper than the node is text of the block; one indented less or equal is a comment and closes the block. See [STXT-SPEC §9](stxt-core-ref#s9). Subsubheader: What happens to comments when formatting? Content >> They are kept. `stxt format` (and *Format Document* in the VS Code extension) rewrites only the lines that open a node; comments, blank lines and the content of blocks stay as they are, except for trailing whitespace. Discarding comments requires an explicit flag, `--clean`, which re-serializes the tree and removes everything the tree does not describe. No tool in the ecosystem rewrites a file without an explicit request (`--write`). Subheader: Schemas and templates Subsubheader: Are schemas mandatory? Content >> No. A document without a namespace is only parsed. If it has a namespace, the validating tool looks its definition up through the resolution chain (the ancestor `.stxt/` directories, the user one, the system one) and, if none covers that namespace, flags it with `SCHEMA_NOT_FOUND`: the document is not wrong, but it could not be validated, and that is reported rather than omitted, also when the chain is empty. Whether a document is validated is decided by the tool, not by the presence of other installed definitions: in the CLI, `--warn-schema` turns it into a warning and `--no-schema` disables validation; in VS Code, the `stxt.schemaValidation` setting; in the playground, the *Schema validation* switch. Subsubheader: Schema or template? Content >> Two syntaxes for the same model, and **every template is equivalent to a schema**. The template (`@stxt.template`) is written like the document it describes, with the cardinality and the type in parentheses, and it is the recommended form for manual writing: Code >> Template (@stxt.template): com.example.docs Structure >> Email (com.example.docs): From: EMAIL To: (+) EMAIL Subject: (?) Body: (1) TEXT Content >> The schema (`@stxt.schema`) is the explicit form, with `Node`, `Children`, `Child`, `Min`/`Max` and `Type`; it is the form that is generated and the one the tools process. See [STXT-TEMPLATE-SPEC](stxt-template-ref) and [STXT-SCHEMA-SPEC](stxt-schema-ref). Subsubheader: How does a tool find schemas and templates? Content >> It depends on the tool, because definition resolution is not part of the base language: it is one more optional layer, like schemas and templates themselves. An application without a file system resolves it its own way —the playground, for instance, associates documents and grammars by namespace within the workspace—. For when files and projects are involved, [STXT-DISCOVERY-SPEC](stxt-discovery-ref) defines a common resolution, which a tool may or may not implement; it is the one the CLI, the VS Code extension and the three libraries follow. Subsubheader: Where are schemas and templates placed? Content >> In the tools that follow [STXT-DISCOVERY-SPEC](stxt-discovery-ref), in a directory called **`.stxt/`** in the project: every `.stxt` file inside it is loaded, recursively, regardless of file names and subdirectories. The resolution chain of a document is every `.stxt/` of its ancestor directories, then `~/.stxt`, and finally `/etc/stxt` (on Windows, `%USERPROFILE%\.stxt` and `%ProgramData%\stxt`). The closest level wins, namespace by namespace. The `STXT_PATH` variable replaces the whole chain with a list of directories, for instance in CI. `stxt install file.stxt` puts a definition in place and `stxt schemas` shows which definition applies in a directory and where it comes from. The full walkthrough, with an example, is in [The working environment](working-environment); the norm, in [STXT-DISCOVERY-SPEC](stxt-discovery-ref). Subsubheader: What if Titel is written instead of Title? Content >> The validator rejects it (`CHILD_NOT_DECLARED`). The content model is **closed**: a node only admits the children its definition declares, and if it declares none, it admits none. That is the purpose of validation: fail explicitly instead of accepting silently. See [STXT-SCHEMA-SPEC §6](stxt-schema-ref#s6). Subsubheader: Is the order of children validated? Content >> No. What is validated is how many times each child appears, not in which position: two documents with the same children in a different order validate the same. The order is preserved in the tree, so an application that gives it meaning obtains it from the tree, not from the validator. There are no regular expressions, default values or conditional rules between fields either: they are declared non-goals. See [STXT-SCHEMA-SPEC §11](stxt-schema-ref#s11). Subsubheader: How is a schema evolved without breaking documents? Content >> By extending the definition without invalidating what is already written: every document that validated keeps validating if the change allows more cases, not fewer. No new version is needed to: * Add an **optional** node: with cardinality `(?)`, `(*)` or any other with a minimum of zero. * Relax a cardinality: lower a minimum or raise a maximum, such as going from `(2,5)` to `(1,5)` or to `(2,6)`. One nuance: compatibility is relative to the extended definition. A document that uses the addition does not validate against an earlier copy, so if the consumers of the namespace do not update the definition at the same time, extensions are worth versioning too; with a single definition —the `.stxt/` of the repository itself—, there is no need. It is a decision about the use case, not the change. What breaks is the opposite —adding a mandatory node, removing one, narrowing a cardinality—, because the model is closed. For those changes the recommended practice is to **version the namespace** (`com.example.docs.v1` → `com.example.docs.v2`): each version has its definition and each document declares the one it uses. Subheader: Tools Subsubheader: How is validation run in CI? Content >> With the command line, without a permanent installation: Listing >> npx @stxt-lang/cli validate --recursive docs/ npx @stxt-lang/cli format --check --recursive docs/ Content >> The exit code is `1` if any document fails and `2` if the call itself is wrong, so the CI job fails on its own. `--format json` produces machine-readable output. If the CI environment must not depend on the contents of `~/.stxt` or `/etc/stxt`, `STXT_PATH=./.stxt` pins the resolution chain. Details on the [Tools](tools) page; the [configuration files](use-cases-config-files) use case shows the same check guarding a deployment. Subsubheader: Is there a canonical representation of an STXT document? Content >> Every valid document has a **canonical tree** in JSON, defined in [STXT-TREE-SPEC](stxt-tree-ref): an array of roots with `name`, `canonicalName`, `namespace`, and `value` plus `children` (inline) or `lines` (block). `stxt describe file.stxt` prints it, and the three libraries expose it from their API. It includes no positions and no comments: it is the logical content, the same in every implementation. Subsubheader: Which languages have a parser? Content >> Three are maintained from this portal: TypeScript/JavaScript (`@stxt-lang/core`), Java (`dev.stxt:stxt-core`) and Python (`stxt`), with the same scope, the same specification date and the same conformance corpus. The VS Code extension, the CLI and the playground are built on the first one. The complete list is on the [Tools](tools) page; to try it without installing anything, [play.stxt.dev](https://play.stxt.dev). Subsubheader: What stability is promised? Content >> That a document valid today stays valid forever. The specifications carry no version number: each one carries a **date** (that of its current text) and a **status**, which only moves forward: *Genesis* (under construction), *Aurora* (usable; an incompatible change is possible, rare, and always announced), *Zenith* (what is valid stays valid forever; things are only added) and *Twilight* (closed). The syntax and the canonical tree —STXT-SPEC and STXT-TREE-SPEC— are in Zenith; schemas, templates and discovery are in Aurora. Error codes are never renamed, and each library's API is frozen within its own 1.x line. Message text and convenience facades are not frozen. Conformance is declared against the specification date (`SPEC_VERSION`), not the package version. The full statement is in [Stability and versions](stability). Subsubheader: Where do I ask, or give feedback? Content >> In the [discussions](https://github.com/orgs/stxt-lang/discussions) of the `stxt-lang` organization on GitHub: questions, ideas, ambiguities in the specifications, and anything you have built with STXT. Every change to the language starts there. Bugs in a specific tool go to the issues of its repository, listed on the [Tools](tools) page.