Hello, here's the Markpub.at Markdown Lexicon

This is a quick intro to the at.markpub.markdown lexicon object for ATProto, intended to have a well-formatted way to put Markdown on your PDS.

This set of Lexicons is intended to give the most flexibility to put Markdown into any larger document like Standard.Site. It gives you options to use YAML, to upload your Markdown as a Blob in storage on your PDS, or specify formatting using supplied facets, or any facets you choose.

The goal is not for this to be an independent record, but rather to be inside other records that support passing an object to describe your text.

This Lexicon is not yet published but still taking feedback, you can do so via GitHub. The current update was published at Feb 28 2026 (8:15PM EST).

The lexicons supply all the tools to make it as clear as possible how to render your Markdown, but also extremely simple to do the basics to get your Markdown into the ATmosphere. Here's an example of the most minimal version of the object, to place in your Standard.Site document or elsewhere:

{
  "$type": "at.markpub.markdown",
  "text": {
    "$type": "at.markpub.text",
    "rawMarkdown": "# Hello World\nThis is a sample markdown text.",
    "flavor": "commonmark",
    "renderingRules": "markdown-it"
  }
}

Scroll down to see the and more detailed

Used with Standard.Site

{
    "$type": "site.standard.document",
    "publishedAt": "2024-06-08T10:00:00.000Z",
    "site": "at://did:plc:t5xmf33p5kqgkbznx22p7d7g/site.standard.publication/3mbrgnnqzrr2q",
    "path": "/essays/hello-world/",
    "title": "Hello World!",
    "description": "Markdown is less simple than it seems.",
    "coverImage": {
        "$type": "blob",
        "ref": {
            "$link": "bafkreig2247wcpqjkqy2ukjh4gjyqhpl32kg3pva4x55npjmuh4joeware"
        },
        "mimeType": "image/jpeg",
        "size": 347901
      },
    "textContent": "Hello World\nThis is a sample markdown text.",
    "content": {
        "$type": "at.markpub.markdown",
        "flavor": "gfm",
        "renderingRules": "markdown-it",
        "extensions": [
            "LaTeX",
            "YAML"
        ],
        "text": {
            "$type": "at.markpub.text",
            "rawMarkdown": "# Hello World\nThis is a sample markdown text.",
            "facets": {
            "index": {
                "byteStart": 0,
                "byteEnd": 13
            },
            "features": [
                {
                "$type": "at.markpub.facets.baseFormatting#header",
                "level": 1
                },
                {
                "$type": "at.markpub.facets.baseFormatting#idify"
                }
            ]
            },
            "lenses": [
            {
                "$type": "at.markpub.lens",
                "outputDescription": "This lens outputs bold or strong styling on web text.",
                "facets": [
                "at.markpub.facet#strong",
                "pub.leaflet.richtext.facet#bold"
                ],
                "outputCode": "function renderWithLens(text, facets) { /* code to render text with facets */ }",
                "outputTargetHTML": "<strong></strong>"
            }
            ]
        }
    },
    "bskyPostRef": {
        "$type": "com.atproto.repo.strongRef",
        "uri": "at://did:plc:t5xmf33p5kqgkbznx22p7d7g/app.bsky.feed.post/3kulbtuuixs27",
        "cid": "bafyreigh7yods3ndrmqeq55cjisda6wi34swt7s6kkduwcotkgq5g5y2oe"
    },
    "tags": ["IndieWeb", "Tech", "The Long Next"],
    "updatedAt":"2024-06-08T10:30:00.000Z"

}

Give feedback on Github or on Bluesky!

Lexicons:


at.markpub.markdown

{ "lexicon": 1, "id": "at.markpub.markdown", "defs": { "main": { "type": "object", "properties": { "text": { "description": "An object that includes the text in markdown. May include anything that is valid markdown syntax for your flavor. Make sure it is properly escaped if necessary.", "type": "ref", "ref": "at.markpub.text" }, "flavor": { "description": "Markdown may be rendered in many flavors. The most common are CommonMark and Github Flavored Markdown (GFM). Generally your markdown is one of those two and if you don't know then it is likely CommonMark. At this time the lexicon only recognizes these two flavors. Submit a PR if you think one should be added.", "type": "string", "knownValues": [ "gfm", "commonmark" ], "default": "commonmark" }, "renderingRules": { "description": "Using this field is highly suggested. Different rendering systems for Markdown may introduce slight or significant changes to the resulting HTML. This setting allows you to specify your renderer so systems can understand the rules you expect. Keep in mind that no consuming entity is obligated to honor this preference. While rendering views may infer rules established by different Markdown renderers with this field, they can and should use the rendering system of their choice. Do **not** use rendering systems you don't know. Some examples might be `marked`, `pandoc`, `markdown-it` `mdxt`, etc. Generally, this lexicon assumes that you are pulling the Markdown from an existing site that includes an existing rendering process. The processor used for that process to build your site's pages is the one you should include here. If you don't know then just leave this field out.", "type": "string" }, "extensions": { "description": "The Markdown community expects certain extensions to mainline Markdown flavors. This setting allows you to note to a renderer what extensions might be expected. The most common is LaTeX. Rendering systems may choose to render these extensions in a variety of ways or present them raw. It is not required that you include YAML in the markdown text itself, if you choose to include a YAML metadata block, note it in this field.", "type": "array", "items": { "type": "string" } }, "frontMatter": { "description": "If your markdown includes a front matter block, you can include it here as separate text. This is optional but may be more convenient for some systems to have it separate. It is expected that if you include this field that the front matter block is not included in the raw markdown text field.", "type": "string" } }, "required": [ "text", "flavor" ] } } }

at.markpub.text

{ "lexicon": 1, "id": "at.markpub.text", "defs": { "main": { "type": "object", "properties": { "rawMarkdown": { "description": "The raw text in markdown. May include anything that is valid markdown syntax for your flavor. Make sure it is properly escaped if necessary.", "type": "string" }, "textBlob": { "description": "Text may be blob-ified as raw Markdown and stored on a PDS, pass it here by reference. If you use this property it is assumed that it overrides the \"rawMarkdown\" property. It is a PDS address for a markdown text file. You still must provide some value, even if it is a preview for \"rawMarkdown\" in this field.", "type": "blob", "maxSize": 1000000, "accept": [ "text/*" ] }, "facets": { "description": "Facets here represent rendered versions of Markdown strings. A bold Markdown string `**bold**` might be represented by a richtext facet of #bold, in which case it is suggested to be presented without the Markdown markup as `<strong>bold</strong>`. Facets select their character ranges based on position in the Markdown text but should be rendered without the related characters. For example: `### Header` will be selected using a character range that includes the hashes like (0,9) but will be rendered without the hashes like `<h3>Header</h3>`. It is recommended that processors to not transform in-place for this reason. The goal of having an open union for facets is that constructing systems may choose to use the facets they prefer from across the ecosystem, either here or in other places like `pub.leaflet.richtext.facet`", "type": "array", "items": { "type": "union", "closed": "false", "refs": [] } }, "lenses": { "description": "Lenses are lexicons that define translatable facets for rendering layers with limited facets. `pub.leaflet.richtext.facet#bold` and `at.markpub.facets.baseFormatting#strong` expect the same output. A lens would then include a union with both those facets and a renderer that understands either of them could translate between the two.", "type": "array", "items": { "type": "union", "closed": "false", "refs": [] } } }, "required": [ "rawMarkdown" ] } } }

at.markpub.facets.baseFormatting

{ "lexicon": 1, "id": "at.markpub.facets.baseFormatting", "defs": { "main": { "type": "object", "properties": { "index": { "description": "", "type": "ref", "ref": "#byteSlice" }, "features": { "description": "", "type": "array", "items": { "type": "union", "refs": [ "#strong", "#header", "#idify" ] } }, "byteSlice": { "description": "Specifies the sub-string range a facet feature applies to. Start index is inclusive, end index is exclusive. Indices are zero-indexed, counting bytes of the UTF-8 encoded text. NOTE: some languages, like Javascript, use UTF-16 or Unicode codepoints for string slice indexing; in these languages, convert to byte arrays before working with facets. Byte slices can overlap.", "type": "object", "properties": { "byteStart": { "type": "integer" }, "byteEnd": { "type": "integer" }, "required": [ "byteStart", "byteEnd" ] } }, "strong": { "description": "Facet feature for a `<strong>` HTML tag. For the byteSlice provided it should surround the underlying text.", "type": "object", "properties": { "required": [] } }, "header": { "description": "Facet feature for a `<h1>` HTML tag. The integer is the level you want to use, as in h1, h2, h3, etc... For the byteSlice provided it should surround the underlying text.", "type": "object", "properties": { "level": { "type": "integer" }, "required": [ "level" ] } }, "idify": { "description": "Facet feature instructs parsers to stringify the underlying text and include it as an id property on an HTML element. If this overlaps with an existing HTML tag generated by another facet, it is assumed that it will be applied to that tag. If there is no matching tag, use `<span></span>`. It is expected spaces are turned into hyphens. For example, a header facet with an idify feature might produce `<h1 id=\"header-text\">Header Text</h1>`.", "type": "object", "properties": { "required": [] } } }, "required": [ "index", "features", "byteSlice", "strong", "header", "idify" ] } } }

at.markpub.facets.baseBlocks

{ "lexicon": 1, "id": "at.markpub.facets.baseBlocks", "defs": { "main": { "type": "object", "properties": { "byteSlice": { "description": "Specifies the sub-string range a facet feature applies to. Start index is inclusive, end index is exclusive. Indices are zero-indexed, counting bytes of the UTF-8 encoded text. NOTE: some languages, like Javascript, use UTF-16 or Unicode codepoints for string slice indexing; in these languages, convert to byte arrays before working with facets. Byte slices can overlap.", "type": "object", "properties": { "byteStart": { "type": "integer" }, "byteEnd": { "type": "integer" }, "required": [ "byteStart", "byteEnd" ] } }, "horizontalRule": { "description": "Place an `<hr>` element at the provided byte index.", "type": "object", "properties": { "required": [] } }, "yaml-front-matter": { "description": "Identify a block of front matter at the top of the Markdown block. It is expected that this has a byteStart and byteEnd.", "type": "object", "properties": { "required": [] } }, "raw": { "description": "Place raw text at the provided byte index. This is a powerful escape hatch for anything that can't be achieved with the other facet features, but use it with caution as it can easily break things if used incorrectly. Do not expect systems to render it.", "type": "object", "properties": { "required": [] } } }, "required": [ "byteSlice", "horizontalRule", "yaml-front-matter", "raw" ] } } }

at.markpub.lens

{ "lexicon": 1, "id": "at.markpub.lens", "defs": { "main": { "type": "object", "properties": { "outputDescription": { "description": "A human-readable description of what the output of this lens is intended to be. This is optional but can be helpful for documentation purposes and for anyone trying to understand how to use the lens.", "type": "string" }, "facets": { "description": "A list of facet types that this lens can translate bidirectionally between. For example, if you include `pub.leaflet.richtext.facet#bold` and `at.markpub.facet#strong` then this lens can be used to translate between those two facet types and any renderer that understands either of those facet types can use this lens to render the facets it understands.", "type": "array", "items": { "type": "union", "closed": "false", "refs": [] } }, "outputCode": { "description": "You may include code here intended to process a string with the provided facets. This is optional and not expected to be used by most lenses, but it can be helpful for testing or for providing examples of how a renderer might use the lens.", "type": "string" }, "outputTargetHTML": { "description": "", "type": "string" } }, "required": [ "facets" ] } } }

Examples

Example for at.markpub.markdown

{
  "$type": "at.markpub.markdown",
  "flavor": "gfm",
  "renderingRules": "markdown-it",
  "extensions": [
    "LaTeX",
    "YAML"
  ],
  "frontMatter": "---\ntitle: Hello World\nauthor: Aram Zucker-Scharff\n---",
  "text": {
    "$type": "at.markpub.text",
    "rawMarkdown": "# Hello World\nThis is a sample markdown text.",
    "facets": {
      "index": {
        "byteStart": 0,
        "byteEnd": 13
      },
      "features": [
        {
          "$type": "at.markpub.facets.baseFormatting#header",
          "level": 1
        },
        {
          "$type": "at.markpub.facets.baseFormatting#idify"
        }
      ]
    },
    "lenses": [
      {
        "$type": "at.markpub.lens",
        "outputDescription": "This lens outputs bold or strong styling on web text.",
        "facets": [
          "at.markpub.facets.baseFormatting#strong",
          "pub.leaflet.richtext.facet#bold"
        ],
        "outputCode": "function renderWithLens(text, facets) { /* code to render text with facets */ }",
        "outputTargetHTML": "<strong></strong>"
      }
    ]
  }
}

Example for at.markpub.text

{
  "$type": "at.markpub.text",
  "rawMarkdown": "# Hello World\nThis is a sample markdown text.",
  "facets": {
    "index": {
      "byteStart": 0,
      "byteEnd": 13
    },
    "features": [
      {
        "$type": "at.markpub.facets.baseFormatting#header",
        "level": 1
      },
      {
        "$type": "at.markpub.facets.baseFormatting#idify"
      }
    ]
  },
  "lenses": [
    {
      "$type": "at.markpub.lens",
      "outputDescription": "This lens outputs bold or strong styling on web text.",
      "facets": [
        "at.markpub.facets.baseFormatting#strong",
        "pub.leaflet.richtext.facet#bold"
      ],
      "outputCode": "function renderWithLens(text, facets) { /* code to render text with facets */ }",
      "outputTargetHTML": "<strong></strong>"
    }
  ]
}

Example for at.markpub.lens

{
  "$type": "at.markpub.lens",
  "outputDescription": "This lens outputs bold or strong styling on web text.",
  "facets": [
    "at.markpub.facets.baseFormatting#strong",
    "pub.leaflet.richtext.facet#bold"
  ],
  "outputCode": "function renderWithLens(text, facets) { /* code to render text with facets */ }",
  "outputTargetHTML": "<strong></strong>"
}