Authoring Guide
Glyph JS extends standard Markdown with a component system that turns plain text into interactive, visually rich documents. This guide covers everything you need to know to author Glyph Markdown files, from basic syntax to advanced features like cross-block references and layout modes.
Standard Markdown
Glyph Markdown is a superset of CommonMark. All standard Markdown features work exactly as you would expect.
Headings
# Heading 1## Heading 2### Heading 3#### Heading 4##### Heading 5###### Heading 6Inline formatting
**Bold text** and *italic text* and ~~strikethrough~~.
Inline `code` uses backticks. [Links](https://example.com) and use the standard syntax.Lists
- Unordered item A- Unordered item B - Nested item
1. Ordered item one2. Ordered item two 1. Nested ordered itemBlockquotes
> This is a blockquote.>> It can span multiple paragraphs.Code blocks
Standard fenced code blocks are fully supported with automatic syntax highlighting.
GlyphJS uses highlight.js grammars to tokenize code and
applies --glyph-code-token-* CSS custom properties for theming.
```typescriptconst greeting: string = "Hello, Glyph!";console.log(greeting);```Supported languages include the 42 common languages from highlight.js (JavaScript, TypeScript, Python, Rust, Go, Java, C/C++, SQL, YAML, JSON, etc.) plus an extended set of functional and math/scientific languages:
- Functional: Scala, Haskell, Clojure, Elixir, Erlang, F#, OCaml, Elm, Scheme, SML, Lisp, ReasonML, Hy, Flix, Clean
- Math / scientific: Julia, MATLAB, Mathematica, LaTeX, Scilab, Maxima, Gauss, Stan, Stata, Fortran, Mizar, Coq, Prolog
Unknown or missing languages fall back to plain unstyled text.
Customizing token colors — override the CSS custom properties on any ancestor element:
.my-document { --glyph-code-token-keyword: #d73a49; --glyph-code-token-string: #032f62; --glyph-code-token-comment: #6a737d; --glyph-code-token-number: #005cc5; --glyph-code-token-function: #6f42c1; --glyph-code-token-type: #e36209; --glyph-code-token-builtin: #6f42c1; --glyph-code-token-attr: #005cc5; --glyph-code-token-literal: #005cc5; --glyph-code-token-operator: #d73a49; --glyph-code-token-variable: #e36209; --glyph-code-token-regexp: #032f62; --glyph-code-token-meta: #6a737d;}Images
Images render inside a <figure> element with lazy loading enabled by default.
Thematic breaks
---A horizontal rule separates sections visually.
YAML Frontmatter
Every Glyph Markdown file can begin with a YAML frontmatter block enclosed in
--- fences. Frontmatter controls document-level metadata and layout behavior.
---glyph-id: my-documenttitle: System Architecturelayout: mode: document spacing: relaxed---Supported frontmatter fields
| Field | Type | Description |
|---|---|---|
glyph-id | string | Stable document identifier. Used for cross-document references and deterministic IR output. If omitted, an ID is derived from the file path or content hash. |
title | string | Document title. If omitted, the compiler infers it from the first h1 heading. |
description | string | Short description. If omitted, inferred from the first paragraph. |
authors | string[] | List of author names. |
tags | string[] | Tags for categorization. |
vars | object | Compile-time scalar variables. String values are interpolated wherever {{key}} appears in prose or ui: YAML fields. See Variables & Macros. |
layout | object | Layout configuration (see Layout Modes below). |
Variables & Macros
Glyph Markdown supports a compile-time variable system that eliminates repetition. All substitution happens before the IR is produced — the runtime and the reader see the final values, not the variable syntax.
Scalar variables
Define scalars in the vars: frontmatter key or in a ui:vars block, then
reference them with {{key}} in prose or in the YAML fields of any ui: block:
---vars: company: Acme Corp quarter: Q1 2026---
# {{company}} — {{quarter}} Report
```ui:callouttype: infotitle: "{{quarter}} Update"content: "{{company}} achieved strong results this quarter."```Block variables
Bind a name to an entire ui: component by appending =name to the lang
string. A _ prefix suppresses the initial render:
```ui:callout=_notetype: infocontent: "Internal use only."```
{{note}}
More text.
{{note}}Each {{note}} reference in a standalone paragraph is replaced with a clone of
the block.
Parameterized templates
Templates are suppressed block variables with named parameter slots:
```ui:callout=_kpi(label, value)type: infotitle: "{{label}}"content: "{{value}}"```
{{kpi("Revenue", "$13.1M")}}{{kpi("NPS Score", "72")}}For the full reference — including ui:vars, scalar expansion rules, arity
errors, and diagnostics — see the Variables & Macros guide.
UI Components — the ui: Fenced Block Syntax
Glyph JS introduces interactive components via a special fenced code block
syntax. Any fenced code block whose language identifier starts with ui: is
treated as a Glyph UI block rather than a regular code block.
How it works
```ui:component-name# YAML payload goes herekey: value```The parser:
- Detects any fenced code block whose language starts with
ui:. - Strips the
ui:prefix to determine the component type (e.g.,graph,table,callout). - Parses the body of the block as YAML.
- Extracts the reserved keys
glyph-idandrefs(if present) before passing the remaining data to the component. - Replaces the code node in the AST with a
GlyphUIBlocknode.
The YAML payload is validated against the component’s Zod schema at compile
time by @glyphjs/compiler. The parser itself does not validate schemas — it
handles only syntax.
Reserved YAML keys
Three top-level YAML keys have special meaning and are stripped from the component data before schema validation:
| Key | Purpose |
|---|---|
glyph-id | Assigns a stable, user-defined block ID for cross-block references. |
refs | Declares outgoing references to other blocks (see Cross-block References). |
interactive | When set to true, enables interaction event emission for this block (see Interaction Events). |
All other keys are passed through as the component’s data payload.
Component Catalog
Glyph JS ships eight built-in components. Each is described below with its full YAML schema and an example.
Callout — ui:callout
Highlighted blocks for tips, warnings, errors, and informational notes. Useful for drawing the reader’s attention to important content.
Schema fields:
| Field | Type | Required | Description |
|---|---|---|---|
type | "info" | "warning" | "error" | "tip" | Yes | Visual style of the callout. |
title | string | No | Optional heading displayed above the content. |
content | string | Yes | The callout body. Supports Markdown formatting (re-parsed by the compiler). |
Example:
```ui:callouttype: tiptitle: Use glyph-id for stable referencescontent: | Assigning a `glyph-id` to your blocks ensures that references remain valid even when you reorder content.```Graph — ui:graph
Interactive node-and-edge diagrams. Supports DAGs, flowcharts, mind maps, and force-directed layouts. Rendered with D3 and Dagre.
Schema fields:
| Field | Type | Required | Description |
|---|---|---|---|
type | "dag" | "flowchart" | "mindmap" | "force" | Yes | Graph variant. |
nodes | array | Yes | List of node objects (see below). |
edges | array | Yes | List of edge objects (see below). |
layout | "top-down" | "left-right" | "bottom-up" | "radial" | "force" | No | Layout direction. Defaults vary by graph type. |
Node object:
| Field | Type | Required | Description |
|---|---|---|---|
id | string | Yes | Unique node identifier within this graph. |
label | string | Yes | Display text for the node. |
type | string | No | Semantic type (e.g., "service", "database"). Used for styling. |
style | Record<string, string> | No | CSS-like style overrides. |
group | string | No | Grouping key for clustering nodes visually. |
Edge object:
| Field | Type | Required | Description |
|---|---|---|---|
from | string | Yes | Source node ID. |
to | string | Yes | Target node ID. |
label | string | No | Text displayed on the edge. |
type | string | No | Semantic type (e.g., "depends-on"). |
style | Record<string, string> | No | CSS-like style overrides. |
Example:
```ui:graphglyph-id: architecture-graphtype: dagnodes: - id: api label: API Gateway type: service - id: auth label: Auth Service type: service - id: db label: PostgreSQL type: databaseedges: - from: api to: auth label: authenticates - from: auth to: db label: querieslayout: top-down```Table — ui:table
Sortable, filterable data tables with optional aggregation. Column types enable type-aware sorting and filtering.
Schema fields:
| Field | Type | Required | Description |
|---|---|---|---|
columns | array | Yes | Column definitions (see below). |
rows | array | Yes | Array of row objects. Each row is a key-value record matching column keys. |
aggregation | array | No | Aggregation functions applied to columns (see below). |
Column object:
| Field | Type | Required | Description |
|---|---|---|---|
key | string | Yes | Property name used to look up the value in each row. |
label | string | Yes | Display header for the column. |
sortable | boolean | No | Whether the column supports click-to-sort. |
filterable | boolean | No | Whether the column shows a filter control. |
type | "string" | "number" | "date" | "boolean" | No | Data type hint for sorting and filtering behavior. |
Aggregation object:
| Field | Type | Required | Description |
|---|---|---|---|
column | string | Yes | Column key to aggregate. |
function | "sum" | "avg" | "count" | "min" | "max" | Yes | Aggregation function. |
Example:
```ui:tablecolumns: - key: name label: Name sortable: true filterable: true type: string - key: role label: Role type: string - key: experience label: Years of Experience sortable: true type: numberrows: - name: Alice role: Engineer experience: 8 - name: Bob role: Designer experience: 5 - name: Carol role: Manager experience: 12aggregation: - column: experience function: avg```Chart — ui:chart
Line, bar, area, and OHLC (financial) charts. Rendered with D3.
Schema fields:
| Field | Type | Required | Description |
|---|---|---|---|
type | "line" | "bar" | "area" | "ohlc" | Yes | Chart variant. |
series | array | Yes | Data series (see below). |
xAxis | object | No | X-axis configuration: key (data field) and optional label. |
yAxis | object | No | Y-axis configuration: key (data field) and optional label. |
legend | boolean | No | Whether to show the legend. |
Series object:
| Field | Type | Required | Description |
|---|---|---|---|
name | string | Yes | Series display name. |
data | array | Yes | Array of data-point records. Each record maps string keys to number or string values. |
Example:
```ui:charttype: lineseries: - name: Revenue data: - { month: Jan, value: 4200 } - { month: Feb, value: 5100 } - { month: Mar, value: 4800 } - name: Expenses data: - { month: Jan, value: 3100 } - { month: Feb, value: 3400 } - { month: Mar, value: 3200 }xAxis: key: month label: MonthyAxis: key: value label: USDlegend: true```Relation — ui:relation
Entity-relationship diagrams for modeling data structures and their connections.
Similar to ui:graph but requires cardinality on relationships and treats nodes
as entities with typed attributes.
Schema fields:
| Field | Type | Required | Description |
|---|---|---|---|
entities | array | Yes | Entity definitions (see below). |
relationships | array | Yes | Relationship definitions (see below). |
layout | "top-down" | "left-right" | No | Layout direction. |
Entity object:
| Field | Type | Required | Description |
|---|---|---|---|
id | string | Yes | Unique entity identifier. |
label | string | Yes | Display name. |
attributes | array | No | List of attribute objects with name (string), type (string), and optional primaryKey (boolean). |
Relationship object:
| Field | Type | Required | Description |
|---|---|---|---|
from | string | Yes | Source entity ID. |
to | string | Yes | Target entity ID. |
label | string | No | Relationship label. |
cardinality | "1:1" | "1:N" | "N:1" | "N:M" | Yes | Cardinality constraint. |
Example:
```ui:relationentities: - id: user label: User attributes: - name: id type: uuid primaryKey: true - name: email type: string - name: name type: string - id: post label: Post attributes: - name: id type: uuid primaryKey: true - name: title type: string - name: body type: text - id: comment label: Comment attributes: - name: id type: uuid primaryKey: true - name: text type: textrelationships: - from: user to: post label: authors cardinality: "1:N" - from: post to: comment label: has cardinality: "1:N" - from: user to: comment label: writes cardinality: "1:N"layout: top-down```Timeline — ui:timeline
Chronological event sequences rendered as a visual timeline. Useful for project milestones, incident reports, or system evolution histories.
Schema fields:
| Field | Type | Required | Description |
|---|---|---|---|
events | array | Yes | Event objects (see below). |
orientation | "vertical" | "horizontal" | No | Timeline orientation. Defaults to vertical. |
Event object:
| Field | Type | Required | Description |
|---|---|---|---|
date | string | Yes | Date or datetime string (e.g., "2026-01-15" or "2026-01-15T09:00:00Z"). |
title | string | Yes | Event heading. |
description | string | No | Detailed description of the event. |
type | string | No | Semantic type for styling (e.g., "milestone", "incident", "release"). |
Example:
```ui:timelineevents: - date: "2026-01-15" title: Project kickoff description: Initial planning and team formation. type: milestone - date: "2026-02-01" title: Alpha release description: Core parser and compiler shipped. type: release - date: "2026-03-01" title: Beta release description: Runtime and all built-in components ready. type: release - date: "2026-04-01" title: v1.0 stable description: Full test suite, documentation, and playground. type: milestoneorientation: vertical```Tabs — ui:tabs
Tabbed content containers. Each tab holds Markdown content that the compiler re-parses, so you can use full Markdown formatting inside tabs.
Schema fields:
| Field | Type | Required | Description |
|---|---|---|---|
tabs | array | Yes | Tab objects (see below). |
Tab object:
| Field | Type | Required | Description |
|---|---|---|---|
label | string | Yes | Tab heading displayed in the tab bar. |
content | string | Yes | Markdown string. Parsed recursively by the compiler to produce child blocks. |
Example:
```ui:tabstabs: - label: Overview content: | This is the **overview** tab with standard Markdown.
It can contain multiple paragraphs, lists, and inline formatting. - label: Installation content: | Install via your package manager:
```bash pnpm add @glyphjs/runtime @glyphjs/components ``` - label: Configuration content: | Edit `glyph.config.ts` to set up your theme and register components.
- Choose a layout mode - Configure your color scheme```Steps — ui:steps
Sequential step-by-step guides with progress indication. Each step has a title, an optional status, and Markdown content.
Schema fields:
| Field | Type | Required | Description |
|---|---|---|---|
steps | array | Yes | Step objects (see below). |
Step object:
| Field | Type | Required | Description |
|---|---|---|---|
title | string | Yes | Step heading. |
status | "pending" | "active" | "completed" | No | Visual progress indicator. |
content | string | Yes | Markdown string. Parsed recursively by the compiler. |
Example:
```ui:stepssteps: - title: Install dependencies status: completed content: | Run `pnpm install` to install all packages. - title: Configure the project status: active content: | Edit `glyph.config.ts` to set up your theme and register the built-in components. - title: Build and deploy status: pending content: | Run `pnpm build` and deploy the output to your hosting provider.```Cross-block References
References create navigable links between blocks, enabling explorable, interconnected documents. For example, a table can link to a graph, allowing users to click through from a data row to the relevant node in a diagram.
Assigning a block ID with glyph-id
To reference a block, it needs a stable identifier. Add the glyph-id key to
any ui: block’s YAML payload:
```ui:graphglyph-id: architecture-graphtype: dagnodes: - id: api label: API Gateway - id: db label: Databaseedges: - from: api to: db```The compiler strips glyph-id from the component data before schema validation.
If no glyph-id is provided, the compiler generates a deterministic,
content-addressed ID automatically.
Rules for glyph-id:
- Must be unique within the document.
- Use lowercase kebab-case by convention (e.g.,
team-table,deploy-steps). - The compiler validates uniqueness and reports a diagnostic if duplicates are found.
Declaring references with refs
The refs array declares outgoing references from one block to another. Each
ref must specify a target — the glyph-id of the destination block.
```ui:tableglyph-id: team-tablecolumns: - key: name label: Name - key: role label: Rolerows: - name: Alice role: Engineer - name: Bob role: Designerrefs: - target: architecture-graph type: data-source label: "See architecture diagram"```Reference fields:
| Field | Type | Required | Description |
|---|---|---|---|
target | string | Yes | The glyph-id of the target block. |
type | string | No | Semantic type: "navigates-to", "details", "depends-on", "data-source", or a custom type prefixed with custom:. |
label | string | No | Human-readable label displayed on the reference link. |
sourceAnchor | string | No | Sub-element within the source block (e.g., a specific node ID or row key). |
targetAnchor | string | No | Sub-element within the target block. |
bidirectional | boolean | No | If true, the reference is navigable in both directions. Defaults to false. |
Inline Markdown references (future)
The syntax [text](#glyph:block-id) is reserved for inline cross-block
navigation within standard Markdown paragraphs. The compiler will resolve these
into Reference objects. This feature is planned for a future release.
Unresolved references
If a refs entry points to a glyph-id that does not exist in the document,
the compiler emits a warning diagnostic and marks the reference as unresolved.
The IR is still produced — unresolved references do not block compilation.
Layout Modes
Layout modes control how the document’s blocks are arranged on screen. Set the
mode in your YAML frontmatter under the layout key.
Document mode (default)
Single-column, reading-optimized layout with a configurable maximum width. Blocks flow top-to-bottom in source order. This is the default when no layout is specified.
---layout: mode: document maxWidth: "960px" spacing: normal---Dashboard mode
A CSS grid layout with configurable columns. Blocks are placed into a grid, and
you can control per-block placement using blockLayout overrides keyed by
glyph-id.
---layout: mode: dashboard columns: 3 spacing: compact blockLayout: architecture-graph: gridColumn: "1 / 3" span: 2 team-table: gridColumn: "3"---This places the architecture-graph block across the first two columns and the
team-table in the third column.
Presentation mode
Full-viewport, one-block-at-a-time display — similar to a slide deck. Each top-level block occupies the full screen, and the user navigates between them.
---layout: mode: presentation spacing: relaxed---Layout properties reference
| Property | Type | Description |
|---|---|---|
mode | "document" | "dashboard" | "presentation" | Layout strategy. |
columns | number | Number of grid columns (dashboard mode). |
maxWidth | string | CSS max-width value (document mode). |
spacing | "compact" | "normal" | "relaxed" | Vertical spacing between blocks. |
blockLayout | Record<string, BlockLayoutOverride> | Per-block layout overrides keyed by block glyph-id. |
BlockLayoutOverride fields:
| Field | Type | Description |
|---|---|---|
gridColumn | string | CSS grid-column value. |
gridRow | string | CSS grid-row value. |
span | number | Number of columns the block should span. |
Interaction Events
Glyph JS components can emit interaction events when users interact with them — clicking chart data points, sorting tables, answering quiz questions, expanding file tree nodes, and more. This enables host applications to react to user behavior, log analytics, or feed interactions back into an LLM conversation.
Enabling interaction events
Add the reserved interactive: true key to any ui: block’s YAML payload:
```ui:chartinteractive: truetype: barseries: - name: Revenue data: - { month: Jan, value: 4200 } - { month: Feb, value: 5100 }xAxis: key: monthyAxis: key: value```The interactive key is stripped before schema validation, just like glyph-id
and refs. When interactive is true, the runtime injects an onInteraction
callback into the component’s props.
Supported events by component
| Component | Event kind | Trigger |
|---|---|---|
ui:quiz | quiz-submit | User submits an answer. |
ui:table | table-sort | User clicks a sortable column header. |
ui:table | table-filter | User changes a column filter. |
ui:tabs | tab-select | User switches tabs. |
ui:accordion | accordion-toggle | User expands or collapses a section. |
ui:filetree | filetree-select | User clicks a file or directory. |
ui:graph | graph-node-click | User clicks a graph node. |
ui:chart | chart-select | User clicks a data point or bar. |
ui:comparison | comparison-select | User clicks an option column header. |
Consuming events in host applications
Register an onInteraction callback when creating the runtime:
import { createGlyphRuntime, debounceInteractions } from '@glyphjs/runtime';
const runtime = createGlyphRuntime({ ir: compiledDocument, components: builtinComponents, onInteraction: debounceInteractions((event) => { console.log(event.kind, event.payload); // Send to analytics, update app state, or feed back to an LLM }, 300),});The debounceInteractions helper debounces events per-stream (keyed by
blockId + kind), so rapid interactions like repeated sorting do not flood
your callback.
Event structure
Every interaction event includes:
| Field | Type | Description |
|---|---|---|
kind | string | Discriminant identifying the event type (e.g., "chart-select"). |
timestamp | string | ISO 8601 timestamp of the interaction. |
documentId | string | The Glyph IR document ID (injected by the runtime). |
blockId | string | The block’s unique ID. |
blockType | string | The block’s component type (e.g., "ui:chart"). |
payload | object | Event-specific data (varies by kind). |
All event types are exported from @glyphjs/types for use in TypeScript
applications.
Best Practices
Write for both humans and machines
Glyph Markdown is designed to be authored by LLMs and read by humans. Keep your YAML payloads clean and well-structured so that both audiences can understand the document at a glance.
Use glyph-id on any block you might reference
Even if you do not need cross-block references today, assigning a glyph-id
makes your block IDs stable and human-readable. Content-addressed IDs change
when you edit the block’s content.
Keep YAML payloads focused
Each ui: block should represent a single, self-contained visualization. If you
find yourself putting too much data into a single block, consider splitting it
into multiple blocks and linking them with refs.
Leverage standard Markdown for narrative
Use headings, paragraphs, lists, and blockquotes around your ui: blocks to
provide narrative context. A graph without an explanation is hard to interpret; a
paragraph without a visualization can be hard to grasp. Combine both for maximum
clarity.
Use frontmatter for document metadata
Always include at least a title in your frontmatter. This ensures the compiler
produces clean metadata even when the document structure changes.
---title: Quarterly Reviewlayout: mode: document spacing: normal---Validate early with the compiler
Run @glyphjs/compiler during development. It validates every ui: block’s
YAML payload against its Zod schema and reports errors with precise line and
column numbers. Fix validation errors before sharing your document.
Use dashboard mode for data-dense documents
When your document contains multiple tables, charts, and graphs, switch to
dashboard mode with a multi-column grid. Assign glyph-id values and use
blockLayout to control placement.
Common Patterns
Narrative with embedded visualization
The most common pattern: prose before and after a ui: block providing context.
# System Architecture
The platform follows a three-tier architecture with an API gateway,authentication service, and database layer.
```ui:graphtype: dagnodes: - id: api label: API Gateway - id: auth label: Auth Service - id: db label: PostgreSQLedges: - from: api to: auth - from: auth to: dblayout: top-down```
All incoming requests pass through the API Gateway, which delegatesauthentication before any data access occurs.Linked table and graph
A table and a graph that reference each other, allowing navigation between the two views of the same data.
```ui:graphglyph-id: service-maptype: flowchartnodes: - id: web label: Web App - id: api label: API - id: worker label: Workeredges: - from: web to: api - from: api to: workerlayout: left-right```
```ui:tableglyph-id: service-detailscolumns: - key: service label: Service - key: status label: Status - key: uptime label: Uptime type: numberrows: - service: Web App status: healthy uptime: 99.9 - service: API status: healthy uptime: 99.7 - service: Worker status: degraded uptime: 97.2refs: - target: service-map type: navigates-to label: "View service map"```Step-by-step tutorial
Use ui:steps combined with ui:callout blocks for structured tutorials.
# Getting Started
```ui:stepssteps: - title: Install the packages status: completed content: | Run the following command:
```bash pnpm add @glyphjs/runtime @glyphjs/components ``` - title: Create your first document status: active content: | Create a file called `hello.md` and add a heading and a `ui:callout` block. - title: Compile and render status: pending content: | Use the compiler to produce IR, then pass it to the runtime.```
```ui:callouttype: infotitle: What is next?content: | Once you have the basics working, explore the Component Catalog to see all available visualizations.```Dashboard layout with multiple visualizations
Combine frontmatter layout configuration with glyph-id and blockLayout to
create a data dashboard.
---title: Q1 Metrics Dashboardlayout: mode: dashboard columns: 2 spacing: compact blockLayout: revenue-chart: gridColumn: "1 / 3" team-stats: gridColumn: "1" milestone-timeline: gridColumn: "2"---
# Q1 Metrics
```ui:chartglyph-id: revenue-charttype: barseries: - name: Revenue data: - { month: Jan, value: 42000 } - { month: Feb, value: 51000 } - { month: Mar, value: 48000 }xAxis: key: monthyAxis: key: value label: USD```
```ui:tableglyph-id: team-statscolumns: - key: team label: Team - key: headcount label: Headcount type: numberrows: - team: Engineering headcount: 12 - team: Design headcount: 4 - team: Product headcount: 3```
```ui:timelineglyph-id: milestone-timelineevents: - date: "2026-01-15" title: Planning complete type: milestone - date: "2026-02-01" title: Alpha shipped type: release - date: "2026-03-15" title: Beta shipped type: releaseorientation: vertical```Interactive document with LLM feedback loop
Use interactive: true to enable interaction events, then feed those events
back into an LLM conversation for adaptive responses.
---title: Architecture Reviewglyph-id: arch-review---
# Architecture Review
```ui:graphglyph-id: system-graphinteractive: truetype: dagnodes: - id: api label: API Gateway group: backend - id: auth label: Auth Service group: backend - id: cache label: Redis Cache group: infra - id: db label: PostgreSQL group: infraedges: - from: api to: auth label: authenticates - from: api to: cache label: caches - from: auth to: db label: querieslayout: top-down```
Click any node above to learn more about that service.
```ui:tableglyph-id: service-metricsinteractive: truecolumns: - key: service label: Service sortable: true - key: latency label: P99 Latency (ms) sortable: true type: number - key: uptime label: Uptime % sortable: true type: numberrows: - service: API Gateway latency: 45 uptime: 99.9 - service: Auth Service latency: 120 uptime: 99.7 - service: Redis Cache latency: 2 uptime: 99.99 - service: PostgreSQL latency: 15 uptime: 99.8```In the host application, wire onInteraction to your LLM API:
import { createGlyphRuntime, debounceInteractions } from '@glyphjs/runtime';
const runtime = createGlyphRuntime({ ir: compiledDocument, components: builtinComponents, onInteraction: debounceInteractions(async (event) => { // Feed the interaction into the LLM conversation const response = await fetch('/api/chat', { method: 'POST', body: JSON.stringify({ role: 'user', content: `The user interacted with the document: ${JSON.stringify(event)}`, }), }); // The LLM can respond with new Glyph Markdown to render const { markdown } = await response.json(); if (markdown) { // Re-compile and update the runtime with the LLM's response const newIr = compile(markdown); runtime.update(newIr); } }, 500),});This pattern enables documents that respond to user exploration — clicking a graph node could prompt the LLM to generate a detailed breakdown of that service, sorting a table could trigger a summary of the sorted data.
Error Handling
The Glyph compiler uses a collect-all-errors strategy. Your document always produces valid IR output, even when errors are present.
| Error type | Behavior |
|---|---|
| YAML parse error | The block is preserved with its raw source text. A diagnostic is attached to the block. |
| Schema validation error | The block is preserved with the original data. Zod error paths are included in the diagnostic. |
| Unresolved reference | A warning diagnostic is emitted. The reference is kept with unresolved: true. |
| Unknown component type | An info diagnostic is emitted. The block is preserved as-is and renders a fallback placeholder. |
UNDEFINED_VARIABLE | A warning is emitted; the literal {{key}} text is preserved in the output. |
CIRCULAR_VARIABLE_REF | An error is emitted; expansion stops and the literal is preserved. |
UNDEFINED_BLOCK_VAR | A warning is emitted; the standalone {{name}} paragraph is kept as-is. |
TEMPLATE_ARITY_MISMATCH | An error is emitted; the invocation paragraph is kept as-is. |
Check the diagnostics array on the CompilationResult to find and fix issues.
Each diagnostic includes severity (error, warning, or info), a message,
and the source position in your Markdown file.