All posts
Blog5 min read

Why your AI agent shouldn't write CSS

There's a tempting shortcut when you wire an agent to produce documents: let the model emit HTML and CSS directly. It can — ask any frontier model for "a styled invoice" and you'll get markup that renders. Ship that, and you've built a document pipeline in an afternoon.

You've also built two problems that won't show up until week three. This post is about both of them, and about the boundary that fixes them.

Problem one: LLMs can't do consistent

Language models are, at this point, genuinely good writers. Structure, argument, tone, tables of data — content is a solved problem for most business documents.

Design is a different kind of task. Good document design isn't one clever output; it's a system of relationships held constant across outputs: a type scale, a spacing rhythm, page geometry, table treatment, how a heading behaves at a page break. The value is in the invariance — proposal #40 looking exactly like proposal #1 is what makes a company's documents read as a set.

Invariance is precisely what sampling from a probability distribution doesn't give you. Ask an agent to style a document today and tomorrow, and you get two competent, slightly different designs. Neither is wrong. Together they're drift. Every hand-styled document — whether the hand is human or a model — diverges a little more from the last, and no prompt engineering fixes it, because the inconsistency isn't a bug in the model. It's what generation is.

You can chase it with ever-longer style prompts ("always use 24px H1, always #0F4C81, always…") and you'll be maintaining a stylesheet written in natural language, enforced by hope.

Problem two: generated markup is an injection surface

The second problem is sharper. If your pipeline renders model-emitted HTML/CSS, then whatever influences the model influences your markup. Agent inputs are rarely fully trusted: user uploads, scraped pages, email threads, retrieved documents. Any of them can carry instructions — and a model that's allowed to write form can be steered into writing hostile form: markup that escapes your container, styles that override your branding, content that impersonates your document chrome, or worse, depending on where that HTML ends up rendering.

Even with a well-behaved model and clean inputs, you're one hallucinated <style> tag away from a broken layout in a document that already went to a client. The failure mode isn't an error you catch in logs; it's a PDF that looks wrong on someone else's screen.

The boundary that fixes both

The fix is one of the oldest ideas in publishing, applied to agents: strictly separate content from form.

  • The agent supplies content — as Markdown, the format models already naturally produce. Markdown can express structure (headings, lists, tables, emphasis) and nothing else. It has no opinion about fonts and no ability to carry a style.
  • The theme supplies form — typography, color, spacing, page geometry, table design — authored once by someone good at it, versioned, and applied identically to every render.
  • The renderer enforces the wall: raw HTML in the input is not honored, so input can only ever become content — escaped text in a fixed vocabulary of elements. It cannot become markup, no matter what the model was tricked into writing.

Notice what happened: the consistency problem and the security problem turned out to be the same problem, and one wall solves both. Content that can't carry styling can't drift, and can't inject.

This division also happens to match what each party is good at. The model does what models do best — write, structure, summarize, and choose (pick a named template for the situation). The designer's judgment is captured once, in the theme. Nobody is asked to do the job they're bad at.

What the agent's interface should look like

Taken seriously, the boundary dictates a tool shape. The agent's entire document capability should be roughly:

create_pdf({ markdown, template })

Two arguments: the content, and a named choice of style. Not a CSS parameter. Not an HTML slot. Not a "custom styles" escape hatch — every escape hatch you add reopens both problems.

Around that one tool, a few supporting capabilities make the agent genuinely competent rather than merely constrained:

  • Introspection — the agent can list available templates and read what a theme looks like, so it chooses well instead of guessing ("this is an investor update; use the investor-update template").
  • Constrained personalization — the agent (or you) can mint a new template from a base theme with a validated accent color, preset fonts, and an allow-listed page size. Three knobs. The knobs are validated server-side, so even the customization path can't smuggle styling through.
  • Links, not blobs — the tool returns a URL to the stored PDF, which agents and chat interfaces handle far more gracefully than binary payloads.

This is exactly how we built Inkrun's MCP server, and the shape is the argument: the safest interface for an agent producing documents is also the one that produces the best documents.

"But I want the agent to be creative with design"

Then give it creative choices, not creative control. A library of well-designed themes and templates is a large expressive space — the agent picking "editorial letter, serif, warm accent" over "technical manual, mono, blue" is a real design decision, made safely. What it isn't allowed to do is invent the type scale on the fly, for the same reason your human teammates aren't: the brand is a constant, not an output.

The uncomfortable version of this post's thesis: if your agent's documents can each look unique, they will — and that's the failure, not the feature.

The takeaway

Give your agent the two things it's actually good at — writing the content and choosing the style — and make everything else a constant it cannot touch. You get documents that look designed, stay on-brand forever, and can't be broken by a bad input.

Your agent writes the doc. The template makes it a document.


See the whole design system your agent can introspect on the templates gallery — 20 named styles, each one render away.

Give your agent a PDF tool.
Connect Inkrun in five minutes — the free tier includes 20 renders a month.
Get started