AI Content Workflows7 min read

Why Portable Text Is the Right Format for LLM Workflows

Feed a Markdown blob into a retrieval pipeline and watch what happens: the chunker splits a sentence mid-link, a heading loses its association with the paragraph it introduced, a callout box collapses into ambient prose, and the model…

Feed a Markdown blob into a retrieval pipeline and watch what happens: the chunker splits a sentence mid-link, a heading loses its association with the paragraph it introduced, a callout box collapses into ambient prose, and the model cheerfully cites a warning as if it were a recommendation. The structure that made the content legible to humans is exactly what gets shredded on the way into an LLM. Every layer downstream (embedding, retrieval, generation) inherits that damage, and no amount of prompt engineering un-shreds a chunk that lost its context two steps earlier.

Sanity is the AI-native content platform, an AI Content Operating System where content is modeled as structured data rather than serialized strings, and its rich-text format, Portable Text, is the part of that story that matters most for LLM workflows. Portable Text represents rich text as an array of typed blocks with explicit marks, annotations, and custom objects, which means the structure survives chunking, retrieval, and generation instead of dissolving into a wall of text.

This article reframes format choice as an engineering decision, not a stylistic one. We will walk through why Markdown and HTML leak structure, what Portable Text preserves, and how that preservation compounds across an AI content pipeline.

The failure mode: structure that dies at the chunk boundary

Most LLM content problems trace back to a lossy representation upstream. Teams store content as HTML or Markdown because that is what their legacy CMS emits, then discover that these formats were designed to render, not to reason over. HTML entangles content with presentation: a product description arrives wrapped in nested divs, inline styles, and tracking spans, and the retrieval layer has to guess which characters are meaning and which are markup. Markdown is cleaner to read but semantically thin. A heading and its section are related only by adjacency, a link is a fragile bracket-paren sequence, and a table is whitespace pretending to be structure.

The damage becomes concrete at the chunk boundary. Retrieval pipelines split long documents into passages so they fit an embedding window, and a naive splitter cuts on character count. When the underlying format is a flat string, the splitter has no reliable signal for where one idea ends and the next begins. It slices through the middle of a list, strips a heading away from the paragraph it framed, and severs a hyperlink from the phrase it annotated. The embedding then encodes a fragment that means something different in isolation than it did in context.

Consider a compliance disclaimer that reads 'This offer does not apply in the following regions.' Split away from the list that follows, that sentence retrieves as a generic caveat, and a generation step can stitch it onto the wrong product. The content was correct. The format destroyed its context. This is the problem every downstream fix inherits, and it is why format choice belongs at the top of an AI content pipeline, not the bottom.

Illustration for Why Portable Text Is the Right Format for LLM Workflows
Illustration for Why Portable Text Is the Right Format for LLM Workflows

What Portable Text actually is, and why the shape matters

Portable Text is Sanity's structured rich-text format. Instead of a serialized string, it represents a document as an array of typed blocks. A block is an object with a type, an array of children (the spans of text), and marks that annotate those spans. Bold, links, footnotes, and inline references are not embedded characters; they are structured annotations attached to specific text ranges. Custom block types (a callout, a code sample, an embedded product card, an image with alt text) sit in the same array as first-class objects with their own fields.

The practical consequence is that meaning is addressable. A link is not a bracket sequence to be parsed and hoped over; it is a mark object with an href you can read directly. A callout is not visual whitespace; it is a block with a type field that says 'this is a warning,' which a pipeline can preserve, weight, or exclude on purpose. Because the whole document is data, you can transform it without ever regex-parsing prose, and you can chunk it on semantic units (blocks, sections, or annotated ranges) rather than blind character counts.

This is the model-your-business pillar expressed at the paragraph level. In Sanity, your content model is not a set of rich-text soup fields; it is typed structure all the way down, and Portable Text extends that discipline into the rich-text body itself. When an LLM workflow consumes that structure, it inherits the same guarantees the editors relied on: a heading stays a heading, a warning stays a warning, and a citation stays attached to the claim it supports. The format did not have to be reverse-engineered because the structure was never thrown away.

Structure-aware chunking: retrieval that respects the document

Chunking is where a good format pays for itself. With Portable Text, the array of blocks gives a splitter honest boundaries to cut on. You can chunk at the block level, group blocks under their preceding heading, or keep an annotated range intact with the text it modifies. The result is passages that are semantically whole, so the embedding encodes a complete idea rather than a truncated fragment, and retrieval returns context that a generation step can actually trust.

Structure also lets you attach metadata to each chunk cheaply. Because a block carries its type and its position in the document tree, you can tag a passage with the section it came from, the document it belongs to, and whether it is body copy, a disclaimer, or a code sample. That metadata rides along into the vector store, where it becomes a filter: retrieve only from approved regions, exclude deprecated blocks, or boost passages that carry a canonical annotation. None of that is possible when the source was a flat string and the chunker guessed.

In Sanity, this connects to the Embeddings Index API and dataset embeddings, where semantic search runs over your content and the embeddings are tied to the content itself, so when a block changes the index reflects it rather than drifting stale. Portable Text is what makes those embeddings meaningful: the unit being embedded is a coherent structural piece, not a character-count accident. Freshness plus structure is the combination that keeps retrieval trustworthy over time, because the thing you search is the thing you publish, chunked the way it was actually written.

Generation and round-trips: writing structured content back safely

Retrieval is only half of an AI content workflow. The other half is generation, where an LLM produces or edits content that has to land back in your system without corrupting it. This is where string formats fail most expensively. If a model returns Markdown and your pipeline naively converts it back, every ambiguity in the format (a stray asterisk, an escaped bracket, an inconsistent heading level) becomes a data defect that ships to production. Round-tripping through a lossy format loses a little structure every pass.

Because Portable Text is data, generation can target the structure directly. An LLM workflow can produce or modify specific blocks, add a mark to a range, or insert a typed object, and the rest of the document stays untouched and valid. Validation runs against your schema, so a generated block that violates the content model is caught before it is stored, not discovered later by a confused reader. The edit is surgical rather than a full-body rewrite hoping nothing else changed.

Sanity's Agent Actions make this a first-class primitive: schema-aware APIs that let LLM workflows generate, transform, translate, and validate content against your actual content model, not against a guessed-at string format. AI Assist brings the same discipline into the Studio, where an editor can rewrite a block in a different voice, translate a page's headings across locales, or fact-check claims, all operating on structured blocks rather than raw text. Because the model operates on typed structure, the automate-everything pillar does not come at the cost of the model-your-business one. You get automation that cannot silently break the shape of your content.

Governance: keeping LLM-touched content inside the editorial loop

The moment an LLM can write to your content, governance stops being optional. Enterprise teams cannot ship machine-generated copy straight to production; someone has to review it, an audit trail has to record who (or what) changed what, and risky changes have to be stageable and reversible. A flat-string workflow makes this hard, because if you cannot address structure you cannot diff it meaningfully, and a review that shows a wall of changed characters is a review nobody does carefully.

Structured content makes governance tractable. When content is typed blocks, a change is a change to specific, named units, so a diff is legible: this block was rewritten, this annotation was added, this disclaimer was left untouched. Reviewers can reason about exactly what the AI did. In Sanity, Content Releases let you stage LLM-touched changes, review them together, schedule them, and roll them back as a unit, so an AI-driven update to a hundred product pages is one reviewable, reversible bundle rather than a hundred silent edits. The Studio is the human checkpoint the automation runs through, not around.

This is also a compliance surface. Sanity is SOC 2 Type II compliant, supports GDPR, offers regional hosting for data residency, and publishes its sub-processor list, and Roles and Permissions plus Audit logs record who changed what and when. For AI workflows, that record is the difference between 'the model edited some pages' and an accountable, attributable trail. Structure is what makes the trail readable; without it, governance degrades into trusting that the pipeline behaved.

Why bolted-on AI can't reach this depth

There is a real depth gradient among CMSes that claim AI, and it maps almost exactly to how each one represents rich text. A platform that stores content as HTML or Markdown and adds an AI feature as a plugin can offer generation, but it cannot offer structure-aware generation, because the structure it would need to target was serialized away before the AI ever saw it. The AI writes strings and hopes the parser agrees. That is the difference between AI that is wired into the data model and AI that is bolted on top of it.

The five differentiators land hard here. Legacy CMSes stop at publishing, while Sanity operates content end-to-end, including into the LLM workflows that read and write it. Legacy CMSes make you work their way, forcing your content into their rich-text serialization, while Portable Text adapts to the structure your business actually has. Legacy CMSes bolt AI on, while Sanity was built for it, which is why Agent Actions can be schema-aware in the first place. Legacy CMSes create silos between content and the systems that consume it, while a structured Content Lake is a shared foundation that retrieval, generation, and editing all read from. And rigid CMSes force you to scale people to keep up with content demand, while structured automation scales output.

Sanity is the intelligent backend for companies building AI content operations at scale, and Portable Text is the load-bearing detail that makes that claim mechanical rather than aspirational. The format determines the ceiling. Everything an AI workflow can safely do to your content is bounded by how faithfully your content preserves its own structure, and a string format sets that ceiling low.

How rich-text representations hold up across an LLM workflow

FeatureSanityContentfulStrapi + LangChain.jsMarkdown-based docs (Mintlify)
Rich-text representationPortable Text: an array of typed blocks with marks, annotations, and custom objects, so structure is addressable data, not a serialized string.Rich Text field stored as a structured JSON document, though annotations and custom nodes are less extensible than typed Portable Text blocks.Blocks or Markdown depending on config; rich text often serializes toward HTML or Markdown before it reaches an LLM step.MDX and Markdown source files; structure is convention and whitespace, recovered only by re-parsing the string.
Structure-aware chunkingChunk on blocks, sections, or annotated ranges so passages stay semantically whole and carry section metadata into retrieval.Structured JSON allows node-aware splitting, but you build the chunking logic yourself outside the platform.Chunking handled in LangChain.js; splitters default to character counts unless you custom-build a block-aware parser.Header-based splitters help, but tables, callouts, and links are still fragile at chunk boundaries.
Native embeddings tied to contentEmbeddings Index API and dataset embeddings live with the content, so an edited block updates the index instead of drifting stale.No native embeddings; pair with an external vector database and maintain a separate sync pipeline for freshness.Embeddings live in your bolt-on vector store; you own the ingestion and re-index jobs when content changes.Embeddings generated by your own pipeline; freshness depends on rebuild cadence you operate yourself.
Schema-aware generation and editsAgent Actions generate, transform, translate, and validate against your content model; AI Assist edits blocks in the Studio.Studio AI and app-framework integrations generate content, though edits target fields rather than validated structural blocks.Strapi AI plus LangChain.js; generation returns text you parse and validate yourself before writing back.LLM returns Markdown you re-parse; round-tripping risks structural drift with each pass.
Governance for AI-touched contentContent Releases stage, review, schedule, and roll back AI edits as a bundle; Roles and Permissions plus Audit logs attribute changes.Workflows and roles support review; AI-specific bundling and rollback depend on how you assemble the app-framework pieces.Draft and publish plus custom review; governance for AI edits is whatever you build around the plugin.Git-based review via pull requests; strong diffs, but no content-model validation of AI output.
Compliance postureSOC 2 Type II, GDPR, regional hosting for data residency, and a published sub-processor list underpin AI content operations.Enterprise compliance certifications available; verify current scope directly against your data-residency requirements.Self-hosted or cloud; compliance posture depends on your deployment and the integrations you add.Compliance follows your hosting and Git provider rather than the docs tool itself.