Skip to main content

Markdown Capabilities

GFM Extras

Tables, task lists, footnotes, strikethrough, code highlighting, and sanitized raw HTML — the GitHub-Flavored Markdown extensions both pipelines share, plus what only pipeline B supports.

Everything on this page also renders in pipeline A's text primitive (format: "markdown"), except footnotes — those are pipeline-B only. See the Overview for the full comparison table.

Tables

Source:

markdown
| Method | Process | Owner |
| :--- | :---: | ---: |
| Traditional | Code → Test → Docs | Platform |
| Modern | Test → Code → Docs | Product |

Rendered:

MethodProcessOwner
TraditionalCode → Test → DocsPlatform
ModernTest → Code → DocsProduct

A wide table (long cells, many columns) scrolls inside its own container instead of forcing the whole page to scroll horizontally — the wrapper is .aup-markdown-table-wrap / .docs-table-wrap.

Task lists

Source:

markdown
- [x] Write the content pipeline
- [x] Ship GFM support
- [ ] Document every extension in one place

Rendered:

  • Write the content pipeline
  • Ship GFM support
  • Document every extension in one place

Checkboxes render disabled — this is a static reference, not an interactive to-do list; checked state reflects what the author wrote in the source, not a live toggle.

Strikethrough

Source:

markdown
~~This approach is deprecated.~~ Use the new one instead.

Rendered:

This approach is deprecated. Use the new one instead.

Code highlighting

Source:

markdown
```typescript
export function greet(name: string): string {
  return `Hello, ${name}!`;
}
```

Rendered:

typescript
export function greet(name: string): string {
  return `Hello, ${name}!`;
}

Fenced code blocks get a language label and a copy-to-clipboard button (.aup-code-toolbar); the <code> element carries a language-<lang> class for syntax-highlighting CSS to hook into.

Footnotes (pipeline B only)

Source:

markdown
Every request carries a signed capability token.[^cap]

[^cap]: See `docs/architecture/capability-tokens.md` for the token format.

Rendered:

Every request carries a signed capability token.[1]

Footnotes are collected once per document and rendered in a single end-of-document section, numbered by first-reference order (not definition order). An unreferenced definition produces no footnotes section at all — it's silently dropped, matching this pipeline's general degrade-not-break posture for authoring mistakes.

Pipeline A does not support footnotes at all[^1] inside an AUP format: "markdown" text field renders as literal text, not a numbered reference.

Raw HTML (sanitized in both pipelines, different allowlists)

Inline and block-level raw HTML in the markdown source is allowed through an allowlist of safe tags/attributes (content-reader.ts's sanitizeRawHtml) — neither passed through verbatim (a storage-XSS vector) nor silently dropped.

Pipeline A also sanitizes raw HTML, but via a different mechanism. The AUP text primitive's format: "markdown" renderer (renderMarkdown() in providers/runtime/ui/src/web-page/core.ts) pipes marked.parse(raw) through DOMPurify.sanitize(...) — a generic sanitizer with its own (broader, library-default) allowlist, not the fixed, hand-curated tag list this pipeline's sanitizeRawHtml uses. Both pipelines are safe against storage-XSS; the exact set of surviving tags/attributes differs between them, so don't assume a page that renders here renders identically through the AUP text primitive.

Source:

markdown
<div class="callout"><strong>Note:</strong> this box is authored as raw HTML.</div>

<img src="https://example.com/diagram.png" onerror="alert(1)" alt="A diagram">

<script>alert("this never runs")</script>

Rendered:

Note: this box is authored as raw HTML.

A diagram

Only a fixed tag/attribute allowlist survives (div, details/summary, headings, table, a/img with their safe attributes, and a handful of inline tags): the <div>/<img> above render, but onerror is stripped from the <img> (open the source of this page to confirm it's gone from the rendered attribute list) and the whole <script> tag — including its body — disappears without a trace. Each raw-HTML block converts independently: a multi-line tag like <details>…<summary>…</summary>\n\nbody\n</details> with a blank line inside it does NOT nest correctly — the blank line splits it into separate paragraphs, breaking the <details>/<summary> structure. Keep raw HTML blocks to a single line (or accept the broken nesting) rather than assuming multi-line block HTML round-trips the way it would in the source. This is a genuinely new capability (landed the same week as this reference, arc#2537/#2599) — check content-reader.ts's RAW_HTML_ALLOWED_TAGS for the exact current allowlist rather than assuming it matches this list forever.


  1. See docs/architecture/capability-tokens.md for the token format.