LiteXML Authoring
Use this skill when an article needs Haklex-specific rich nodes, or when the user asks to convert LiteXML to Lexical JSON / Markdown / HTML via the litexml CLI.
The skill is split into a thin index (this file) plus per-topic references. Load the matching reference when you start the actual work — the index is intentionally short so the format decision table and node selection map fit in one read.
References
| File |
When to load |
references/cli.md |
Running the litexml binary — every flag, every input/output mode, every runtime caveat. |
references/nodes-structural.md |
Authoring with structural tags (<p>, headings, lists, tables, links) and inline formatting (<b>, <em>, <code>, …). |
references/nodes-extensions.md |
Authoring with Haklex extension tags (media, code, math, callouts, containers, footnotes, chat, poll, …). |
references/authoring-recipes.md |
CDATA usage, block IDs, nested-content rules, similar-node disambiguation, validation, adding new nodes. |
packages/rich-editor/docs/markdown-flavor-litexml.md is the canonical tag contract — read it before changing any tag name or attribute schema.
Format decision
| Content requirement |
Use |
| Plain prose, headings, simple links, lists, quotes, tables, code fences |
Markdown |
| Any Haklex extension tag is required |
LiteXML — for the whole fragment, including surrounding prose |
| A block needs stable identity for later edits |
LiteXML with id="..." (maps to $.blockId) |
| Fresh poll/chat content |
LiteXML without IDs — the reader mints them |
Once a fragment contains any LiteXML tag, all surrounding prose in that fragment must also be LiteXML. Markdown is not parsed inside a LiteXML fragment.
Hard rule — no Markdown tokens inside LiteXML. **bold**, *italic*, `code`, # heading, - item, [text](url) inside any <p>/<li>/<h*> are emitted as literal characters. Use <b>, <i>, <code>, <h2>, <ul><li><p>, <a href> instead. Before returning a LiteXML fragment, scan it for **, `, and line-leading #/-/1. and convert them.
<!-- wrong -->
<p>Run **npm install** then see `README.md`</p>
<!-- right -->
<p>Run <b>npm install</b> then see <code>README.md</code></p>
CLI quick start
# inside the haklex monorepo
pnpm --silent litexml input.xml --format json --compact # → SerializedEditorState
pnpm --silent litexml input.xml --format markdown # → Markdown
pnpm --silent litexml input.xml --format html --open # → HTML preview, browser
# outside the monorepo
npx --yes -p @haklex/rich-litexml-cli litexml input.xml --format json
Full flag reference, output forms, theme/variant/lang options, error modes, validation pipelines: references/cli.md.
Node selection map
Detailed When / Avoid when / params / body rules for each tag live in nodes-structural.md and nodes-extensions.md. Use this table only to decide which reference to open.
| Need |
Tag |
Reference |
| Paragraph, heading, list, table, link, inline format |
<p> / <h*> / <ul> / <ol> / <table> / <a> / <b> / <code> / … |
structural |
Quote (with optional attribution) |
<blockquote> |
structural |
| Single image / multi-image / video / embed / link card |
<img> / <gallery> / <video> / <embed> / <link-card> |
extensions |
| Downloadable file attachment |
<attachment> |
extensions |
| Code (single / multi-file) |
<codeblock> / <code-snippet> |
extensions |
| Diagram (Mermaid / opaque) |
<mermaid> / <excalidraw> |
extensions |
| Math (inline / block) |
<math> / <math display="block"> |
extensions |
| Callout (semantic / page-wide) |
<alert> / <banner> |
extensions |
| Collapsible / nested doc / multi-column |
<details> / <nested-doc> / <grid><cell> |
extensions |
| Inline annotation |
<spoiler> / <ruby> / <mention> / <tag> / <comment> |
extensions |
| Footnote |
<footnote> + <footnote-section> |
extensions |
| Chat / poll |
<chat> / <poll> |
extensions |
| Remote interactive component (host catalog only) |
<dynamic> |
extensions |
| Internal review marker |
<agent-diff> |
extensions |
Cross-cutting rules
- Canonical lowercase tag names. Do not emit legacy aliases (
<linkcard>, <codesnippet>, <nesteddoc>, <code-block>).
- Quote every attribute value.
- Escape XML-sensitive text (
&, <, >, "). Use CDATA for opaque JSON, drawing snapshots, and multi-line code bodies.
<alert>, <banner>, <nested-doc>, <grid><cell> hold a fresh nested editor state — wrap their body in block tags (<p>, <h*>, …), not bare text.
- A fragment that mixes any extension tag with prose must be wholly LiteXML; Markdown syntax is not parsed inside.
<dynamic> URLs must come from the host project's component catalog — never invent one. See the extensions reference for the full catalog rule.
Details, gotchas, and the full disambiguation matrix: references/authoring-recipes.md.
Validation
After producing or editing LiteXML, round-trip to compact JSON to confirm the registry parses every tag:
pnpm --silent litexml '<doc><p>Hello</p></doc>' --format json --compact
If the command succeeds but a downstream editor cannot materialize a node, the runtime is missing that Haklex node class — re-check the consumer's nodes registration, not the CLI.
1---2name: litexml-authoring3description: Use when writing Haklex articles with Markdown plus LiteXML, choosing the appropriate Haklex node for content, authoring LiteXML fragments, or converting a LightXML/LiteXML string or file into Lexical SerializedEditorState JSON, Markdown, or Static Render HTML via the `litexml` CLI.4---56# LiteXML Authoring78Use this skill when an article needs Haklex-specific rich nodes, or when the user asks to convert LiteXML to Lexical JSON / Markdown / HTML via the `litexml` CLI.910The skill is split into a thin index (this file) plus per-topic references. Load the matching reference when you start the actual work — the index is intentionally short so the format decision table and node selection map fit in one read.1112## References1314| File | When to load |15| ---------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------- |16| [`references/cli.md`](./references/cli.md) | Running the `litexml` binary — every flag, every input/output mode, every runtime caveat. |17| [`references/nodes-structural.md`](./references/nodes-structural.md) | Authoring with structural tags (`<p>`, headings, lists, tables, links) and inline formatting (`<b>`, `<em>`, `<code>`, …). |18| [`references/nodes-extensions.md`](./references/nodes-extensions.md) | Authoring with Haklex extension tags (media, code, math, callouts, containers, footnotes, chat, poll, …). |19| [`references/authoring-recipes.md`](./references/authoring-recipes.md) | CDATA usage, block IDs, nested-content rules, similar-node disambiguation, validation, adding new nodes. |2021`packages/rich-editor/docs/markdown-flavor-litexml.md` is the canonical tag contract — read it before changing any tag name or attribute schema.2223## Format decision2425| Content requirement | Use |26| ----------------------------------------------------------------------- | ----------------------------------------------------------------- |27| Plain prose, headings, simple links, lists, quotes, tables, code fences | **Markdown** |28| Any Haklex extension tag is required | **LiteXML** — for the whole fragment, including surrounding prose |29| A block needs stable identity for later edits | LiteXML with `id="..."` (maps to `$.blockId`) |30| Fresh poll/chat content | LiteXML without IDs — the reader mints them |3132Once a fragment contains any LiteXML tag, **all** surrounding prose in that fragment must also be LiteXML. Markdown is not parsed inside a LiteXML fragment.3334**Hard rule — no Markdown tokens inside LiteXML.** `**bold**`, `*italic*`, `` `code` ``, `# heading`, `- item`, `[text](url)` inside any `<p>`/`<li>`/`<h*>` are emitted as literal characters. Use `<b>`, `<i>`, `<code>`, `<h2>`, `<ul><li><p>`, `<a href>` instead. Before returning a LiteXML fragment, scan it for `**`, `` ` ``, and line-leading `#`/`-`/`1.` and convert them.3536```xml37<!-- wrong -->38<p>Run **npm install** then see `README.md`</p>39<!-- right -->40<p>Run <b>npm install</b> then see <code>README.md</code></p>41```4243## CLI quick start4445```bash46# inside the haklex monorepo47pnpm --silent litexml input.xml --format json --compact # → SerializedEditorState48pnpm --silent litexml input.xml --format markdown # → Markdown49pnpm --silent litexml input.xml --format html --open # → HTML preview, browser5051# outside the monorepo52npx --yes -p @haklex/rich-litexml-cli litexml input.xml --format json53```5455Full flag reference, output forms, theme/variant/lang options, error modes, validation pipelines: [`references/cli.md`](./references/cli.md).5657## Node selection map5859Detailed `When` / `Avoid when` / params / body rules for each tag live in [`nodes-structural.md`](./references/nodes-structural.md) and [`nodes-extensions.md`](./references/nodes-extensions.md). Use this table only to decide which reference to open.6061| Need | Tag | Reference |62| ------------------------------------------------------ | --------------------------------------------------------------------------- | ---------- |63| Paragraph, heading, list, table, link, inline format | `<p>` / `<h*>` / `<ul>` / `<ol>` / `<table>` / `<a>` / `<b>` / `<code>` / … | structural |64| Quote (with optional `attribution`) | `<blockquote>` | structural |65| Single image / multi-image / video / embed / link card | `<img>` / `<gallery>` / `<video>` / `<embed>` / `<link-card>` | extensions |66| Downloadable file attachment | `<attachment>` | extensions |67| Code (single / multi-file) | `<codeblock>` / `<code-snippet>` | extensions |68| Diagram (Mermaid / opaque) | `<mermaid>` / `<excalidraw>` | extensions |69| Math (inline / block) | `<math>` / `<math display="block">` | extensions |70| Callout (semantic / page-wide) | `<alert>` / `<banner>` | extensions |71| Collapsible / nested doc / multi-column | `<details>` / `<nested-doc>` / `<grid><cell>` | extensions |72| Inline annotation | `<spoiler>` / `<ruby>` / `<mention>` / `<tag>` / `<comment>` | extensions |73| Footnote | `<footnote>` + `<footnote-section>` | extensions |74| Chat / poll | `<chat>` / `<poll>` | extensions |75| Remote interactive component (host catalog only) | `<dynamic>` | extensions |76| Internal review marker | `<agent-diff>` | extensions |7778## Cross-cutting rules7980- Canonical lowercase tag names. Do **not** emit legacy aliases (`<linkcard>`, `<codesnippet>`, `<nesteddoc>`, `<code-block>`).81- Quote every attribute value.82- Escape XML-sensitive text (`&`, `<`, `>`, `"`). Use CDATA for opaque JSON, drawing snapshots, and multi-line code bodies.83- `<alert>`, `<banner>`, `<nested-doc>`, `<grid><cell>` hold a **fresh nested editor state** — wrap their body in block tags (`<p>`, `<h*>`, …), not bare text.84- A fragment that mixes any extension tag with prose must be wholly LiteXML; Markdown syntax is not parsed inside.85- `<dynamic>` URLs must come from the host project's component catalog — never invent one. See the extensions reference for the full catalog rule.8687Details, gotchas, and the full disambiguation matrix: [`references/authoring-recipes.md`](./references/authoring-recipes.md).8889## Validation9091After producing or editing LiteXML, round-trip to compact JSON to confirm the registry parses every tag:9293```bash94pnpm --silent litexml '<doc><p>Hello</p></doc>' --format json --compact95```9697If the command succeeds but a downstream editor cannot materialize a node, the runtime is missing that Haklex node class — re-check the consumer's `nodes` registration, not the CLI.