STXT Discovery

Status:
Aurora
last modified:
2026-09-10

1. Introduction

This document is STXT-DISCOVERY-SPEC; the other specifications cite it by that name.

This document defines STXT Discovery: the mechanism by which a tool locates, on the file system, the @stxt.schema and @stxt.template documents applicable to an STXT document.

The STXT-SCHEMA-SPEC and STXT-TEMPLATE-SPEC specifications define how definitions are written and how they validate; they deliberately do not state where they are located. This specification covers that omission with a single goal: that the same document validates against the same definitions in every tool, whether an editor, a command line or a continuous integration process. If every tool searched for definitions its own way, the outcome of validating would depend on who validates.

Resolution is identical for schemas and templates: both are discovered by the same procedure and compete for the same namespaces.

1.1 Date and status of this specification

This specification carries its own date and its own status in the Last modif and Status fields of its Metadata, independent of the other STXT specifications' and with the meaning fixed by STXT-SPEC §1.1. It is in Aurora. It depends on STXT-SPEC and STXT-SCHEMA-SPEC.

2. Terminology

The keywords "MUST", "MUST NOT", "SHOULD", "SHOULD NOT", and "MAY" must be interpreted according to RFC 2119 and RFC 8174: they carry that meaning only when they appear in uppercase, as here.

Terms such as node, namespace, schema and template retain their meaning in STXT-SPEC, STXT-SCHEMA-SPEC and STXT-TEMPLATE-SPEC.

Additional definitions:

  • Definition: a @stxt.schema or @stxt.template document, associated with a target namespace.
  • Resolution directory: a directory named .stxt whose contents are definitions.
  • Level: each of the resolution directories applicable to a document, ordered by precedence.
  • Resolution chain: the ordered list of levels applicable to a specific document.

3. The .stxt directory

A resolution directory is a directory named exactly .stxt.

  • A tool MUST load all files with the .stxt extension under the directory, recursively.
  • Subdirectories carry no meaning: they are organization only. .stxt/web/a.stxt and .stxt/a.stxt belong to the same level.
  • Every file under a resolution directory MUST be a definition: a document whose root node belongs to @stxt.schema or @stxt.template. Any other content is a resolution error (section 8).
  • The recursive walk SHOULD be guarded against pathological structures the same way the ascent is (section 4.1): a tool MAY limit the descent depth and SHOULD NOT follow symbolic links: neither descend through a link to a directory (so as not to enter loops or walk unrelated trees) nor load as a definition a link to a file (so as not to read files from outside the .stxt/, section 10). A subdirectory that cannot be listed contributes no files; it does not stop the resolution of the rest of the level.

4. The resolution chain

For a given document, the resolution chain is built in this order, from highest to lowest precedence:

  1. Project level: the .stxt directories found by walking up from the document's directory to the root of the file system, from nearest to farthest.
  2. User level: the .stxt directory in the user's home folder.
  3. System level: the machine-wide definitions directory.

4.1 Project level

Starting from the directory containing the document, the tool MUST examine that directory and each of its ancestors, in ascending order, and add to the chain every .stxt directory that exists.

  • The search MUST NOT stop at the first directory found: in a monorepo, the subproject's .stxt and the repository root's .stxt both take part, and the subproject's one has higher precedence for being nearer.
  • The search ends at the root of the file system. A tool MAY impose an ascent limit (for example, 32 levels) as a safeguard against pathological paths (section 10).
  • The .stxt entry of an ancestor MUST be a real directory: if it is a symbolic link, the tool MUST NOT follow it and that ancestor contributes no level, even when the link points to a directory. The ancestors of a document are written by whoever created the project, who is not always the validating party (a cloned repository) and a .stxt linked to the home folder or to the root would take the resolution into a foreign tree (section 10). It is the same rule that applies inside the directory (section 3). The user and system levels (section 4.2) and the STXT_PATH entries (section 6), chosen by the user, may be links.
  • A document with no location on the file system (standard input, an unsaved buffer) has no project level: its chain starts at the user level.

4.2 User level and system level

Level Linux, macOS and other Unix Windows
User $HOME/.stxt %USERPROFILE%\.stxt
System /etc/stxt %ProgramData%\stxt
  • The user level allows personal definitions shared across projects.
  • The system level allows an organization to distribute definitions to every account on a machine.
  • If any of the directories does not exist, that level contributes no definitions; it is not an error.
  • Both directories are chosen by the user or by the machine's administrator, not by the author of a project. They MAY therefore be symbolic links and a tool MUST follow them: $HOME/.stxt linked to a personal configuration repository is an intended use. A linked $HOME/.stxt does not take part as a project level of a document located under the home folder (section 4.1), but it does as the user level. Inside them section 3 applies: the links they contain are not followed.

5. Precedence

Once every level of the chain is loaded, precedence applies per target namespace, not per whole directory:

  • For each namespace, the active definition is the one from the nearest level that defines it. Definitions of the same namespace at farther levels are ignored.
  • Different namespaces MAY resolve from different levels: the project's template from its .stxt, and a personal definition from $HOME/.stxt, in the same validation.
  • Within a single level, two definitions for the same namespace are an error (section 8), whether they are two schemas, two templates, or a schema and a template. Across different levels there is no conflict: the nearest one wins, whatever its kind.

For the scope of this specification, this rule pins down the schema-versus-template prioritization criterion that STXT-TEMPLATE-SPEC leaves open to the implementation: the effective semantic source of a namespace is its active definition.

5.1 Complete example

/home/ana/
├── .stxt/                       (user level)
│   └── notes.stxt               defines org.ana.notes
└── projects/monorepo/
    ├── .stxt/                   (project level, 2nd)
    │   ├── common.stxt          defines com.acme.common
    │   └── web-old.stxt         defines com.acme.web
    └── web/
        ├── .stxt/               (project level, 1st)
        │   └── web.stxt         defines com.acme.web
        └── index.stxt           document to validate

The resolution chain of index.stxt is, in order: web/.stxtmonorepo/.stxt/home/ana/.stxt/etc/stxt.

Result per namespace:

  • com.acme.webweb/.stxt/web.stxt (the nearest level wins; web-old.stxt is ignored).
  • com.acme.commonmonorepo/.stxt/common.stxt.
  • org.ana.notes/home/ana/.stxt/notes.stxt.

6. The STXT_PATH environment variable

If the STXT_PATH environment variable is defined, it completely replaces the resolution chain of section 4: no project, user or system level is searched.

  • Its value is a list of directories separated by the platform's path separator (: on Unix, ; on Windows).
  • Each directory in the list is one level; the order of the list is the order of precedence (the first one has the highest priority).
  • Entries point directly to definition directories: they do not need to be named .stxt.
  • A nonexistent entry is ignored; it is not an error.
  • An entry MAY be a symbolic link, and it is followed: whoever defines STXT_PATH chooses its directories (section 10). Inside it section 3 applies.
  • An empty entry (the one left by a leading, trailing or doubled separator, as in :/opt/defs) is ignored as well: it does not stand for the working directory.
  • An STXT_PATH that is defined but empty leaves the chain empty: no namespace has an active definition, and validating a document with a namespace fails with SCHEMA_NOT_FOUND (STXT-SCHEMA-SPEC §13). An empty chain is not a "syntax only" mode: that mode, when a tool offers it, is requested explicitly.

STXT_PATH exists for environments in which the implicit search is not appropriate: continuous integration, the tools' own tests, or environments with a restricted file system.

7. Per-document resolution

The resolution chain is defined per document: it is a function of the document's location and the environment, not of the tool or of the set of documents being processed.

A tool that processes several documents at once (an editor with several open files, a command line with several arguments) MAY share loads and caches as an optimization, but the result MUST be identical to resolving each document separately. In particular, if two documents from different projects see different definitions for the same namespace, each one MUST be validated with its own.

A tool MAY offer explicit mechanisms to designate definitions (a command-line option, editor configuration). What is designated explicitly MUST take precedence over what this specification discovers.

8. Resolution errors

A tool MUST report as a resolution error:

  1. Two definitions for the same target namespace at the same level.
  2. A file under a resolution directory that does not parse as STXT.
  3. A file whose root node belongs neither to @stxt.schema nor to @stxt.template.
  4. A definition that does not validate against its meta-schema (STXT-SCHEMA-SPEC, STXT-TEMPLATE-SPEC).

Rules:

  • Upon a resolution error, the tool MAY continue loading the remaining definitions, but MUST report the error.
  • Upon error 1, the tool MUST NOT silently pick one of the conflicting definitions: the affected namespace has no active definition while the conflict exists.
  • A document declaring a namespace for which the chain contributes no definition is not a resolution error: the document parses, and validating it produces SCHEMA_NOT_FOUND (section 6, STXT-SCHEMA-SPEC §13). A tool SHOULD distinguish that case from a namespace with resolution errors.

9. Conformance

  • Definition discovery is part of the schema/template layer, optional like the layer itself (STXT-SPEC §17.3): a conforming core parser is not required to implement it.
  • A tool that implements file-system discovery MUST follow this specification in full: implementing only part of the chain produces exactly the disagreement between tools that this specification exists to avoid.
  • This specification does not define when definitions are reloaded (file watching, caches, invalidation): that is each tool's decision, as long as the observable result honors sections 4 to 8.

10. Security Considerations

  • The upward search and the user and system levels load files from directories the validating party does not necessarily control (the ancestors of a shared path, /etc/stxt). A definition only validates: it does not execute code or alter the document. The impact of a hostile definition is limited to changing the validation outcome.
  • Even so, a tool SHOULD be able to show which directories it loaded and where the active definition of each namespace came from, and MAY offer trust restrictions analogous to those of other tools with upward searches (for example, limiting the search to a configured root directory).
  • Both the ascent limit of section 4.1 and the limit on the recursive descent within a resolution directory (section 3) protect against pathological directory structures: circular symbolic links or virtual file systems. A tool SHOULD bound the descent depth and SHOULD NOT follow symbolic links when descending, neither directory nor file links, so that a resolution directory loads only the definitions it really contains, not files an outside link points to: since the levels of the chain include directories the validating party does not control, following a file link would allow reading a file from outside the .stxt/ (and leaking its content through a resolution error). A directory that cannot be listed contributes no definitions and does not stop the resolution of the rest.
  • For the same reason, the .stxt of an ancestor that is a symbolic link forms no level (section 4.1): the ancestors are the part of the chain written by whoever created the project, not by the validating party, and a .stxt linked to the home folder or to the root in a cloned repository would be enough for the tool to walk that whole tree, parsing every file as a definition and leaking the line that fails to parse. The user and system levels and the STXT_PATH entries are followed when they are links (section 4.2, section 6): the user chooses them, and linking $HOME/.stxt to a personal configuration repository is an intended use.