This page summarises the specification. The normative text is spec/gistui-format.md in the repository; section numbers below refer to it.
Text and lines
Sections 4 and 5.
- A program is UTF-8 text. A byte-order mark is ignored. Lines end with LF, CRLF or CR.
- Each line is classified: a statement, a table row, a comment (
#), a fence, or prose. - A prose line (anything else) is ignored and reported as
prose-ignored. It never breaks a program. - There are two modes. In document mode the whole text is a program. In inline mode the text is chat with programs in
gistuicode fences. #gistui 1on the first line is the version pragma. It is optional.- A statement normally ends at its line end. An open bracket continues it onto the next line.
Grammar
Section 6.
program = { line NL }
stmt = ID "=" ( expr | table )
stateDecl = "$" ID "=" expr
patch = ID "." ID "=" expr
append = ID "+=" expr
table = row { NL row } row = "|" cell { "|" cell }
expr = lambda | cond
lambda = ( ID | "(" [ID {"," ID}] ")" ) "=>" expr
cond = or [ "?" expr ":" expr ]
primary = call | builtin | STRING | NUMBER | "true" | "false" | "null"
| "$" ID | ID | "[" [args] "]" | "{" [pairs] "}" | "(" expr ")"
call = COMP "(" [args] ")" builtin = "@" ID "(" [args] ")"
arg = ID (":"|"=") expr | expr
STRING = JSON string COMP = [A-Z]\w* ID = [a-z_]\w*Recovery
Sections 7 and 8.
Text that is not strict is still read, by numbered rules. A processor must apply them and must report each application. This is what makes two implementations agree on imperfect input.
| Example | Rule (in short) | Diagnostic |
|---|---|---|
| A call still open at the line end | Closed there | lenient-syntax |
| A string still open at the line end | Ended there | unterminated-string |
'text' |
A string | lenient-syntax |
key=value, "key": value |
A named argument | lenient-syntax |
Card(a b) |
The missing comma is supplied | lenient-syntax |
card(…) |
The component Card |
lenient-syntax |
// note |
A comment | lenient-syntax |
.5, +3, 05 |
The numbers 0.5, 3, 5 | lenient-syntax |
| An unexpected character | Skipped; the statement is kept | parse-failed, fixed |
| Nothing recoverable | The statement is dropped | parse-failed |
A generator must write strict text and must not rely on recovery. Recovery is for the processor.
Catalogs
Section 9.
A catalog lists components. For each: its name, its positional arguments in order, whether it takes children (and of which types), its props with their types, its aliases, and an optional table mapping.
Prop types: string (optionally format: "url"), number, boolean, enum, node, nodes, data, array, object, action, state, any.
Bare words are resolved by the catalog, in this order:
key:WORDwhere the prop is an enum: an enum value.- A word that is a statement id: a reference. A defined statement always wins.
- A word that is a boolean prop of the enclosing component: a flag.
- A word that is a value of exactly one enum prop of the enclosing component: that prop.
- Anything else: a reference that may be defined later.
Misspelled names use the closest-name rule: a name within a small edit distance of exactly one catalog name is taken as that name, and reported.
A catalog has a JSON manifest form (schemas/catalog.schema.json), so tools in any language can read it.
The tree
Section 13.
Processing gives an abstract tree: a set of nodes, each with an id, a type, props, children and dynamic entries for runtime expressions.
- Node ids are stable. A statement’s node has the statement’s id; an inline component gets a derived id such as
kpis/1. A renderer can key on them. - Special types:
#textfor a string child,#pendingfor a reference not defined yet,#unknownfor a component nothing matches,#exprfor a runtime expression in child position. - The tree has a JSON form (
schemas/tree.schema.json), which the conformance suite compares.
Edits
Section 14. Replace (id = …), patch (id.prop = …), append (id += …) and delete (id = null). Described for users in Edits and multi-turn.
End of stream and validity
Sections 15 to 17.
At the end, open brackets are closed, references to nothing are dropped, cycles are broken, and unused statements are reported.
Chunking invariance: a processor must give the same final tree and diagnostics however the input is divided, from one piece to one character at a time.
A program has two validity flags:
- strict: no diagnostic at all. This is what a generator should produce.
- lenient: every problem was repaired by a rule of the format.
Runtime
Sections 18 to 20.
- Values: null, booleans, numbers, text, lists, objects, component references.
- State:
$namevariables with declared defaults; a host may supply initial values. - Operators and built-ins: a fixed set (see State and expressions). No user-defined functions.
- Queries (
@query) call a tool from the query set, re-run when their arguments change, and have a default value. - Mutations (
@mutation) call a tool from the mutation set, and only through@runin an action list. - Action lists run steps in order and stop at the first failure.
Envelopes
Sections 20.3 and 26.4.
Two JSON objects cross the boundary between a renderer and its host.
The action envelope is what a renderer reports when a person acts (schemas/action.schema.json). Its type is one of send, submit, open, emit, select, change, error. The form submit is described in Actions and forms.
The capability object is what a host tells a generator it may write (schemas/capabilities.schema.json):
{
"gistui": "1.0",
"profiles": ["core", "interactive", "tools"],
"mode": "document",
"edit": false,
"catalog": { "id": "https://gistui.com/catalogs/default", "version": "1.0.0" },
"tools": [
{ "name": "get_sales", "kind": "query", "args": "{range:str}", "description": "Sales by month" },
{ "name": "update_goal", "kind": "mutation", "args": "{goal:num}" }
]
}A generator must not write state or actions for a host without the interactive profile, nor queries or mutations without tools.
Limits
Section 21. The values are part of 1.0, because they decide which diagnostics a program gets.
| Processor limit | Value |
|---|---|
| Nesting depth in one statement | 100 |
| Binary operators in one chain | 500 |
| Nodes owned by one statement | 5,000 |
| Nodes in one program | 50,000 |
| Values in one data statement | 200,000 |
| Component instances in the tree | 50,000 |
| Depth of the tree | 400 |
| Runtime limit | Value |
|---|---|
| Evaluation steps in one pass | 500,000 |
Items of one @each |
5,000 |
| Generated nodes | 20,000 |
Length of text made by + or @join |
1,000,000 |
| Queries with a refresh timer | 20 |
| Refresh interval | at least 5 s |
| Tool calls | 60 in any 10 s |
No input may make a processor or runtime fail with an unhandled error, exhaust the stack, or hang.
Security
Section 23.
- Threat model: the program is written by a model that may have been steered by hostile content. The host, the catalog and the renderer are trusted; the program is not.
- No code execution. Expressions are interpreted. There is no way to reach the host environment.
- URL schemes. Links and
@openallow http, https, mailto and tel. - URLs that load by themselves (images, video, backgrounds) follow a host policy: an allow-list of hosts, and a rule that a URL assembled from data is not loaded unless its host is listed. This closes the path where an image request carries private data out.
- Markdown is rendered without raw HTML.
- Tools. Queries must be read-only. Mutations run only from a person’s action.
- Messages from the UI must be distinguishable from typed text when they go back to a model.
- Deception. A renderer should keep generated UI visually inside its container.
The user-facing guide is Security.
Accessibility and internationalisation
Sections 24 and 25. A renderer must expose roles, names and states for interactive components, support keyboard use, manage focus for dialogs, and honour reduced motion. Text direction follows the content; number and date formatting follows the host locale.
Versioning
Section 26.
- The version is
1.0. A processor that sees an unknown major version in the pragma reportsunsupported-versionand continues. - A host must accept diagnostic codes it does not know and treat them by severity.
- Media type:
text/vnd.gistui(not registered yet). File extension:.gistui. Inline mode istext/markdownwithgistuifences. - Catalogs have ids and versions of their own.