The working environment
How to organise an STXT project, where to place its grammar and how to validate from the editor, from the command line and in continuous integration.
It follows the example of the tutorial, the record of a book. It uses the
stxt command line (npm install -g @stxt-lang/cli, or npx @stxt-lang/cli without
installing), Visual Studio Code with the stxt-lang.stxt extension and the
playground; all three are described in Tools.
The project and the .stxt/ directory
An STXT project is a directory with .stxt documents and a directory called
.stxt/ with its grammars (schemas and templates). To validate a document, a tool
looks for .stxt/ in the document's directory and in all of its ancestors, then in
~/.stxt and in /etc/stxt. That list is the document's resolution chain, and
it is the same in the editor, on the command line and in the libraries.
For the example, a books project:
books/
├── .stxt/ the project's grammars
└── docs/
└── book.stxt the documents
Inside .stxt/ every .stxt file is loaded, recursively. Neither file names nor
subdirectories have any meaning. Each file must be a definition (@stxt.schema or
@stxt.template); any other content is a resolution error. See
STXT-DISCOVERY-SPEC §3 and §4.
Writing the grammar
The book template is like the one from the tutorial, with a mandatory ISBN and at
least one chapter. It can be written straight into .stxt/ under any name, or
installed with stxt install, which checks that it validates against its meta-schema
and writes it, in canonical form, as .stxt/@stxt.template/<namespace>.stxt. That
layout is a CLI convention; the language does not impose it.
Template (@stxt.template): com.acme.book
Structure >>
Book:
Title: (1)
Authors: (1)
Author: (+)
ISBN: (1)
Publisher: (?)
Published: (?) DATE
Summary: (?) TEXT
Chapter: (+)
Content: (?) TEXT
Description >>
Book: Template for publisher book recordsstxt install book-template.stxt
Installed com.acme.book (@stxt.template) to /home/ana/books/.stxt/@stxt.template/com.acme.book.stxt
stxt schemas shows the resolution chain of a directory and, for each namespace, the
active definition and its file:
stxt schemas docs
Resolution chain for /home/ana/books/docs:
/home/ana/books/.stxt
Namespaces:
com.acme.book <- /home/ana/books/.stxt/@stxt.template/com.acme.book.stxt
If the project lives inside another one that also has a .stxt/, the chain includes
both directories, and for each namespace the one closest to the document wins.
Writing and validating the document
The document, in docs/book.stxt, with the template's namespace:
Book (com.acme.book):
Title: Modern Software Architecture
Authors:
Author: María Pérez
Author: Juan García
ISBN: 978-84-123456-7-8
Published: 2025-10-01
Summary: A practical introduction to the architecture of modern systems.
Chapter: Introduction
Content >>
Basic concepts and goals of the book.stxt validate docs/book.stxt
It prints nothing and exits with code 0. With Published changed to free text and
without the ISBN line:
Book (com.acme.book):
Title: Modern Software Architecture
Authors:
Author: María Pérez
Author: Juan García
Published: October 1st, 2025
Summary: A practical introduction to the architecture of modern systems.
Chapter: Introduction
Content >>
Basic concepts and goals of the book.
# ERROR: the date is not YYYY-MM-DD and ISBN, which is mandatory, is missingstxt validate docs/book.stxt
/home/ana/books/docs/book.stxt:6: [INVALID_VALUE] Published: Invalid date (October 1st, 2025) (error)
/home/ana/books/docs/book.stxt:1: [TOO_FEW_CHILDREN] 0 nodes of 'com.acme.book:isbn' and min is 1 (error)
2 error(s), 0 warning(s)
Each finding is file:line: [CODE] message (severity). The code is stable and the
same in the CLI, the extension and the three libraries. A cardinality error is
reported on the line of the parent (Book, line 1).
The exit code is 1 if the documents have errors and 2 if the command was misused.
Options of validate:
--warn-schema: grammar errors are reported as warnings and do not fail; syntax errors still do.--no-schema: syntax only, without looking for or applying any grammar.--format json: the same findings as a JSON array.--recursive(-r): validates whole directories; any.stxt/it finds is skipped, because those are not documents.
The rest is in the command-line reference.
The same from VS Code
With the books/ folder open and the extension installed
(code --install-extension stxt-lang.stxt) there is nothing to configure. The
extension follows the same resolution chain as the CLI, also above the workspace
root, and emits the same codes. With docs/book.stxt open:
- Syntax errors show as errors and grammar errors as warnings, with the same code and message as on the command line.
- Completion (
Ctrl+Space): insideBookit proposes only the children the template allows; in anENUM, its values. - Hover over a node name: the description given by the template, its type and, if it
is an
ENUM, its values. - Go to definition (
F12) onPublishedopens.stxt/@stxt.template/com.acme.book.stxtat the linePublished: (?) DATE. - Format document: it reindents and normalises without losing comments or blank lines.
When the template is edited, the extension resolves again and revalidates the open
documents. A namespace that no grammar in the chain defines is flagged with
SCHEMA_NOT_FOUND as a warning. The stxt.schemaValidation setting disables
validation against grammars, like --no-schema in the CLI.
More than one level: user and system
The project's .stxt/ is the first level of the chain; there are two more:
| Level | Where | stxt install ... |
What for |
|---|---|---|---|
| Project | .stxt/ of the document and its ancestors |
--local |
The project's grammars, versioned with it |
| User | ~/.stxt (%USERPROFILE%\.stxt) |
--user |
Personal definitions, shared by all the user's projects |
| System | /etc/stxt (%ProgramData%\stxt) |
--system |
Definitions an organisation distributes to a whole machine |
Precedence is per namespace: for each one the closest level that defines it wins, and
the other levels contribute the namespaces that one does not define. A project can
carry its com.acme.book while the user keeps an org.ana.notes template in
~/.stxt, and both apply in the same validation.
Two definitions of the same namespace at the same level are not allowed. If the book
template is copied to .stxt/other/copy.stxt, the namespace is left without an
active definition until one of the two is removed:
stxt schemas docs
Resolution chain for /home/ana/books/docs:
/home/ana/books/.stxt
No namespaces resolved.
Errors:
DISCOVERY_DUPLICATE_NAMESPACE /home/ana/books/.stxt/other/copy.stxt: Duplicate definition for namespace 'com.acme.book' at level /home/ana/books/.stxt: already defined in /home/ana/books/.stxt/@stxt.template/com.acme.book.stxt
stxt validate reports that same error (line 0, naming the offending file) and
fails. See STXT-DISCOVERY-SPEC §5 and
§8.
Continuous integration and STXT_PATH
The STXT_PATH environment variable replaces the whole resolution chain with a list
of directories (separated by :, or ; on Windows), in order of precedence; the
entries do not have to be called .stxt. In a CI job it keeps the result from
depending on the ~/.stxt or the /etc/stxt of the machine:
STXT_PATH=./.stxt npx @stxt-lang/cli validate --recursive docs/
npx @stxt-lang/cli format --check --recursive docs/
format --check writes nothing: it lists the files that would change and fails if
there is any, like gofmt -l or prettier --check. Reformatting requires --write.
A STXT_PATH that is defined but empty leaves the chain empty: validate fails with
SCHEMA_NOT_FOUND on every document with a namespace, except with --no-schema. An
entry that does not exist contributes nothing and is not an error. See
STXT-DISCOVERY-SPEC §6.
Without installing anything: the playground
In the playground there is no file system and no directory chain: documents and grammars are associated by namespace within the workspace. Every template or schema in the workspace takes part in validation, and two grammars with the same namespace are an error, as in a level of the chain.
The Open in the playground button of the document on this page loads it together
with its template: when the date is altered or the ISBN removed, the problems panel
shows the same codes as the CLI. Completion, hover and the tabs/spaces switch work as
in the extension, and Share copies a URL that contains the whole workspace.