Skip to main content

Squillify development is paused indefinitely. Read why, and discover what this experiment achieved. Read the story

MicroSkills Reference

Markdown Renderer

markdown.render

ProductionEngine wrapper (Class A)Deterministicstrictfastv2.0.0
File inputNo network

Overview

You send Markdown and we return HTML that is safe to put straight on a page. Three grammars are available: strict CommonMark, GFM with tables, task lists, strikethrough and bare-URL links, and squillify-safe, which adds footnotes and GitHub-style callouts. Everything goes through an allowlist sanitizer, so scripts, event handlers, and dangerous URL schemes never survive, whatever your raw-HTML policy. You also get heading anchors, an optional table of contents, and a manifest of every image the document points at. Math, diagrams, and citations are selected through the closed components object. We render and sanitize — we do not fetch images, follow links, run code, or produce PDFs. Choosing between this and markdown.render_math: this is the one for a whole document, equations included — use components.math.mode and the same typesetting engine runs. Reach for markdown.render_math only when you need the expressions on their own as SVG fragments without the prose, the result written to a file, a malformed expression to fail the call instead of being preserved as source, or more than 100 expressions in one pass. This call is billed once. Parse, emit and sanitize cost 2 credits. Math that actually typesets adds 5 (the same weight as markdown.render_math); diagrams that actually render add 5 (markdown.render_diagrams); citations that actually resolve add 2 (markdown.render_citations). Those extras are included in this parent debit — the specialized skills are not invoked and not billed again. The settled total is 2 through 14 credits and is reported on _meta.usage. Omit components and we still reserve 12 credits up front, because math and diagrams default to auto; set a component's mode to off when you want it out of both the reservation and the work. Accepts file input via file_ref — no need to extract file content first.

Markdown from an agent or an end user is untrusted input, and turning it into HTML safely takes a sanitizer, a fixed grammar, and a stable theme — not a regex.

Reliability

STRICT and byte-deterministic for identical input at a fixed engine version, math included. Validation (not retryable): MARKDOWN_PROFILE_UNSUPPORTED and MARKDOWN_INVALID_ENCODING, which names the byte offset and is worth retrying after re-encoding. Fixed caps: MARKDOWN_COMPLEXITY_LIMIT for node count, nesting depth, or more than 100 expressions, and OUTPUT_LIMIT_EXCEEDED for a result too large to return inline. With math enabled only, the sidecar can answer RENDERER_BUSY, RENDER_TIMEOUT, or INTERNAL_RENDERER_UNAVAILABLE — all retryable, and never downgraded into math-less HTML, because a billed success that quietly dropped your equations would be worse than a failure.

Context footprint

Inline input up to 1048576 characters, or 2097152 bytes through file_ref. HTML is returned inline and is typically several times the size of its source, so a large document is better read from a file_ref than pasted. You are billed 2 credits for Markdown alone, plus 5 if math typesets, 5 if diagrams render, and 2 if citations resolve — one charge on this call, never a second charge for markdown.render_math, markdown.render_diagrams, or markdown.render_citations. Before we read the document we reserve credits from the component modes you sent (12 if you omit components, because math and diagrams default to auto). After the render, _meta.usage.totalUnits is what we actually charged.

When to use it

When Markdown you did not write has to become displayable HTML. This is the default choice for a whole document, math included — use components.math.mode=auto and the expressions are typeset by the same engine markdown.render_math uses.

When you need another document format, server-side highlighting, or anything that reaches out to the network. Also when the job is the equations rather than the document: markdown.render_math is the one that returns expressions on their own as SVG fragments, writes the result to a file, fails the call on a malformed expression instead of preserving it as source, or accepts more than the 100 expressions this skill caps at.

Powered by commonmark-java for parsing, jsoup for sanitization, and MathJax for optional math typesetting.

Scope

Note
Renders Markdown into sanitized HTML under a chosen grammar and theme.

Non-goals

  • Does not fetch, validate, or embed the images and links it reports
  • Does not produce PDF, DOCX, or other document formats
  • Does not execute code blocks or evaluate expressions
  • Does not highlight code server-side — it labels the language for your highlighter
  • Does not repair invalid Markdown

Properties

IdempotentRetry safeStreaming supportedFile input supportedRequires external service

Capabilities

document-processingformatting

Cost & billing

Flat rate per invocation

MetercallsBillable onsuccessCost per call2 credits

File handling

Accepts file_refProduces file_refMax input2 MBMax file size2 MB

File limits

Constraints this skill applies to your input and generated files. The “Limited by” column shows the static source of each cap; none of these can be raised by upgrading your plan.

LimitValueLimited by
Maximum size per input file2 MiBSkill maximum

How we handle your data

Sensitive output possible
What this means

This skill may receive sensitive content and may return submitted, transformed, extracted, or reformatted content.

Squillify guarantees
  • Runs inside Squillify using a self-contained open-source component
  • This skill runs inside Squillify.
  • Payloads are not sent to an external service by this skill.
  • Self contained open source component
  • Squillify does not permanently store submitted payloads.
  • Telemetry records metadata only, not submitted content.
  • Submitted payloads are not used for training.
  • Submitted payloads are not reviewed by humans.
  • This skill does not target sensitive data.
  • The response may contain submitted or transformed content.
Your responsibility

Squillify does not determine whether submitted content is sensitive. Your application is responsible for deciding what data it is allowed to submit. Your application is responsible for securing the response.

Read the Microskill Data Handling Policy

Input schema

FieldTypeRequiredDescription
markdownstringNoThe Markdown to render, up to 1048576 characters. Omit it only when you send file_ref — one of the two is required, and sending neither is a validation error. If you send both, file_ref wins and _meta._input_conflict_resolved says so.
file_refstringNoA stored Markdown file (squillify://files/f-...) we read instead of inline text, up to 2097152 bytes. Omit it to render the markdown field instead — one of the two is required. The file must be valid UTF-8: we do not guess at broken bytes, we tell you which offset is wrong.
profilestringNoWhich grammar to apply: commonmark (strict, raw HTML escaped), gfm (adds tables, task lists, strikethrough, bare-URL autolinks), or squillify-safe (adds footnotes, callouts, front matter). Defaults to squillify-safe.
outputFormatstringNohtml_fragment (default) returns an article element you drop into your own page; html_document returns a complete page with the stylesheet in its head.
htmlPolicystringNoWhat to do with HTML written inside the Markdown: escape shows it as text, drop removes it and keeps the text, sanitize keeps what survives the allowlist. Defaults to the profile's own policy — escape for commonmark and gfm, sanitize for squillify-safe.
themestringNosquillify (default, styled from the Squillify Design System), none (structural classes only, bring your own CSS), light, dark, or auto (neutral light with a CSS-only dark override).
includeCssbooleanNoWhether html_document embeds the stylesheet in its head. Defaults to true. A fragment never carries a style element, so this has no effect there — _meta.cssIncluded always reports what actually happened.
baseUristringNoAn http or https URL that relative links and images resolve against. Resolution is pure string arithmetic: we never open a connection or look up a host. Omit it to leave relative URLs exactly as written.
optionsobjectNoOptional flags, all booleans: generateHeadingIds (default true), generateToc (false), footnotes (true), callouts (true), codeLineNumbers (false), codeCopyMetadata (true), openExternalLinksInNewTab (false). An option the profile has no extension for is ignored rather than refused. Unknown keys are rejected.
componentsobjectNoClosed component configuration for math, diagrams, and citations. Each entry has mode auto or off. Math and diagrams default to auto; citations default to off so ordinary document rendering never requires bibliography metadata. A component that actually runs adds its standalone credit weight to this call (5 for math, 5 for diagrams, 2 for citations) and is not billed as a second skill. Set citations.mode to auto and provide components.citations.bibliography to resolve citation syntax; citations.errorPolicy uses report (default) or fail, matching markdown.render_citations. Unknown components, options, and modes are rejected.
limitsobjectNoOptional: timeoutMs (default 8000, clamped to 30000) for math typesetting, and maxDiagnostics (default 200, clamped to 2000). Unknown keys are rejected.

Output schema

FieldTypeRequiredDescription
htmlstringYesThe rendered HTML: an article element for html_fragment, a complete page for html_document. Every id it contains is prefixed md- so two renders can share a page.
mimeTypestringYesAlways text/html; charset=utf-8.
tocarrayYesOne entry per heading in document order: level (1-6), text (the heading as plain text) and id (the anchor exactly as it appears in the html, prefix included). Empty when generateHeadingIds is off.
assetsarrayYesEvery image the document points at, in document order, without repeats: type (always "image"), url (after baseUri resolution), alt (null when the document gave none) and external (true when it sits off your baseUri origin). We list them; we never fetch them.
diagnosticsarrayYesAnything worth telling you about the document, each with code, severity, message, optional source range, and optional suggestion. Shared validation findings come first in ruleset, source-position, severity, code order; render-execution findings such as MARKDOWN_MATH_RENDER_SKIPPED follow deterministically. Severity describes the source finding, not the call outcome: a successful render may contain error diagnostics when the selected grammar recovered deterministically.
errorsintegerYesNumber of error diagnostics before maxDiagnostics truncates the returned array. This is a source-quality count, not an execution-status flag; use the top-level success or failure result to determine whether rendering completed.
warningsintegerYesNumber of warning diagnostics before maxDiagnostics truncates the returned array.
securityobjectYesWhat the sanitizer took out: htmlPolicy (the policy applied), removedElements, removedAttributes and blockedUrls. All zero on a document that contained nothing unsafe.
_metaobjectYesprofile and profileVersion, parser and parserVersion, sanitizerVersion, theme and themeVersion, cssIncluded (whether a stylesheet was actually embedded), inputChars, inputBytes, nodeCount, mathExpressions, truncated (whether diagnostics were cut at maxDiagnostics), usage (the settled markdown-composite-v1 credit allocation: base 2 plus each component that ran), and, only when it applies, _input_conflict_resolved. No timing field: two identical requests must return identical bytes.

API contract

POST /v1/execute
curl
curl -sS -X POST "$BASE/v1/execute" -H "Authorization: Bearer $KEY" -H 'Content-Type: application/json' -d '{"skillKey":"markdown.render","input":{"markdown":"# Formula\n\n$E=mc^2$","components":{"math":{"mode":"auto"},"diagrams":{"mode":"off"},"citations":{"mode":"off"}}}}'
Integrations
TypeScript SDK
import { Squillify } from "@squillify/sdk";

const sq = new Squillify({ apiKey: process.env.SQUILLIFY_API_KEY });

const { output } = await sq.execute("markdown.render", {"markdown":"# Hello\n\nWorld"});

Errors

CodeHTTPRetryableDescription
VALIDATION_ERROR400NoThe request payload failed schema validation.
UNAUTHORIZED401NoMissing or invalid API key.
SKILL_NOT_ACCESSIBLE403NoThe API key is not granted access to this skill.
SKILL_NOT_AVAILABLE_FOR_PLAN403NoThis skill is not included in your current plan.
PLAN_ELIGIBILITY_UNAVAILABLE503YesPlan eligibility could not be decided. Retry after backoff.
SKILL_NOT_FOUND404NoThe requested skill or version does not exist.
TENANT_RATE_LIMITED429YesRequest rate limit exceeded. Retry after backoff.
QUOTA_EXCEEDED429YesPlan quota exhausted. Retryable once the quota period resets.
EXECUTION_TIMEOUT504YesExecution exceeded the allowed time budget.
MARKDOWN_PROFILE_UNSUPPORTED400NoThe request payload failed this skill's input validation.
MARKDOWN_INVALID_ENCODING400NoThe request payload failed this skill's input validation.
MARKDOWN_COMPLEXITY_LIMIT429NoA size, quota, rate, or time limit was exceeded.
RENDERER_BUSY429YesA size, quota, rate, or time limit was exceeded.
RENDER_TIMEOUT503YesA dependency required by this skill is unavailable.
INTERNAL_RENDERER_UNAVAILABLE503YesA dependency required by this skill is unavailable.

Other limits

LimitValue
Recommended inline bytes32 KiB

Limitations

  • Does not fetch, validate, or embed the images and links it reports
  • Does not produce PDF, DOCX, or other document formats
  • Does not execute code blocks or evaluate expressions
  • Does not highlight code server-side — it labels the language for your highlighter
  • Does not repair invalid Markdown
  • Converting Markdown to PDF or Word
  • Highlighting code on the server
  • Downloading or checking the images a document references
  • Producing the typeset expressions on their own, or writing them to a file — that is markdown.render_math

How to call

POST /v1/execute (requires authentication)

Request bodyjson
{
  "skillKey": "markdown.render",
  "input": {
    "markdown": "# Hello\n\nWorld"
  }
}

Examples

A heading and a paragraph, with the anchor the renderer generated

Inputjson
{
  "markdown": "# Hello\n\nWorld"
}
Expected outputjson
{
  "warnings": 0,
  "html": "<article class=\"sqfy-markdown sqfy-markdown-v2 sqfy-theme-squillify\">\n <h1 id=\"md-hello\">Hello</h1>\n <p>World</p>\n</article>",
  "errors": 0,
  "toc": [
    {
      "text": "Hello",
      "id": "md-hello",
      "level": 1
    }
  ],
  "mimeType": "text/html; charset=utf-8",
  "diagnostics": [],
  "security": {
    "htmlPolicy": "sanitize",
    "removedElements": 0,
    "removedAttributes": 0,
    "blockedUrls": 0
  },
  "_meta": {
    "sanitizerVersion": "1.18.3",
    "themeVersion": "sqfy-markdown-v2",
    "inputChars": 14,
    "mathExpressions": 0,
    "parserVersion": "0.24.0",
    "truncated": false,
    "parser": "commonmark",
    "cssIncluded": false,
    "inputBytes": 14,
    "diagrams": 0,
    "usage": {
      "pricingModel": "markdown-composite-v1",
      "totalUnits": 2,
      "baseUnits": 2,
      "components": {}
    },
    "profile": "squillify-safe",
    "theme": "squillify",
    "citations": 0,
    "nodeCount": 4,
    "profileVersion": "1"
  },
  "assets": []
}

Relative links and images resolved against a base, and the image listed

Inputjson
{
  "markdown": "See the [guide](docs/guide.md) and ![chart](chart.png).",
  "baseUri": "https://example.com/site/"
}
Expected outputjson
{
  "warnings": 0,
  "html": "<article class=\"sqfy-markdown sqfy-markdown-v2 sqfy-theme-squillify\">\n <p>See the <a href=\"https://example.com/site/docs/guide.md\">guide</a> and <img src=\"https://example.com/site/chart.png\" alt=\"chart\">.</p>\n</article>",
  "errors": 0,
  "toc": [],
  "mimeType": "text/html; charset=utf-8",
  "diagnostics": [],
  "security": {
    "htmlPolicy": "sanitize",
    "removedElements": 0,
    "removedAttributes": 0,
    "blockedUrls": 0
  },
  "_meta": {
    "sanitizerVersion": "1.18.3",
    "themeVersion": "sqfy-markdown-v2",
    "inputChars": 55,
    "mathExpressions": 0,
    "parserVersion": "0.24.0",
    "truncated": false,
    "parser": "commonmark",
    "cssIncluded": false,
    "inputBytes": 55,
    "diagrams": 0,
    "usage": {
      "pricingModel": "markdown-composite-v1",
      "totalUnits": 2,
      "baseUnits": 2,
      "components": {}
    },
    "profile": "squillify-safe",
    "theme": "squillify",
    "citations": 0,
    "nodeCount": 8,
    "profileVersion": "1"
  },
  "assets": [
    {
      "url": "https://example.com/site/chart.png",
      "alt": "chart",
      "type": "image",
      "external": false
    }
  ]
}
  • Publish agent-written or user-written Markdown on a page without trusting it
  • Render documentation with anchors and a table of contents
  • Render technical documentation that mixes prose and equations, via components.math.mode=auto
  • Preview a stored Markdown file exactly as it will appear

Avoid for

  • Converting Markdown to PDF or Word
  • Highlighting code on the server
  • Downloading or checking the images a document references
  • Producing the typeset expressions on their own, or writing them to a file — that is markdown.render_math

Composable with

Safety & privacy

  • Runs without calling any external service.
  • Your payloads are never stored permanently.
  • Telemetry captures metadata only — never your payload contents.
  • We never train models on your payloads.
  • No human reviews your payloads.

Tags

formattinghtmlmarkdown