
Conference Session
AI-Powered Site Building in Drupal: From Blank Site to Styled Pages in a Conversation

Francesco Pesenti
Senior Engineer

Francesco Quagliati
Software Engineer
Building a Drupal site asks people to understand content types, the page builder, taxonomy, menus, blocks, and the theme all at once, and that weight falls hardest on the people writing the content. Transom, a Drupal 11 module, lets someone describe a page in plain language, get back a structured, styled result, and refine it in conversation. Drupal's structure stays in charge underneath: the AI works through tools that read the live site, its output is validated against Drupal's own definitions, and changes can be staged in a workspace before anything goes live.
Session Description
Natural language can be a front door to Drupal site building without giving up what makes Drupal work underneath. This session opens with a live demo that builds a Rotterdam city guide on a stock Drupal 11 site from plain-language prompts, then refines it through inline edits and chat.
Francesco Pesenti (Senior Engineer) and Francesco Quagliati (Software Engineer) then explain how it works. The model never touches Drupal's entity API directly. It calls tools that ask the live site which block types, layouts, and design tokens exist, and those tools call Drupal services. They cover validation and self-correction, scoped edits, queued image generation, a four-level styling cascade, and how Workspaces keeps AI changes reviewable before they publish.
They close with where Transom helps, such as first drafts, prototypes, and bulk structural edits, and where it does not, such as pixel-precise design and long-form writing in a house voice.
What You Will Learn
- Why tools that read the live site work better than prompts alone
- How validation and self-correction keep AI output within Drupal's definitions
- How scoped edits and workspaces keep AI changes reviewable
- How a four-level styling cascade keeps AI output within a site's design system
- Why well-described component schemas matter for AI-assisted authoring
- Where AI-assisted site building helps and where human editors still do better
Transcript
[00:00:04] Good afternoon, everyone. In about 10 minutes, we are going to build this page, larger and bigger, just by typing into our chat box. Then we'll spend the next half hour on how it actually works and where it breaks. We are Peximo and Francesco from Tag1 Consulting.
[00:00:23] So this is not a criticism about Drupal. This is what a mature CMS looks like. Building a Drupal site today means being fluent in six systems at once: content types and fields; the page builder (Layout Builder and now others); taxonomy and menus; block configuration; the theme design system; and also knowing which of those you are even supposed to use for this particular page. A site builder who knows modeling may not know the page builder. A content editor, no need. Every one of those screens exists because somebody needed that control. That control has a cost, though, and it falls hardest on the people who actually write the content.
[00:01:10] So our question was simple: can natural language be a front door to all of this without throwing away what makes Drupal Drupal underneath? And that "without throwing anything away" part is really the whole talk. First we show you the demo; we recorded one. Then we open it up in four parts: what the AI actually sees when it looks at your site; how we keep it from doing damage when it gets things wrong; how to write CSS without turning your theme into soup; and finally the honest part, what we tell you before you adopt this, not after.
[00:01:48] So, the demo. This is now the demo. This is a stock Drupal 11 site with a few SDC components and no content. We describe the page we want: a Rotterdam city guide, providing a color palette, two Google Fonts, some idea of the sections. We never name a component. The agent asks the site what exists, then proposes a plan section by section, and waits. Then you can choose to save it into a workspace or directly live.
[00:02:24] Okay. It creates the page, saves a styling variant, compiles Tailwind. Then, okay, this is the summary the AI provides to the user, so you can check what was done and change it if needed. The page is usable right away. This is the page. Images arrive from the queue. As we scroll, you can see the placeholder, this one for example. Okay, a moment.
[00:03:03] Okay, now the page is complete. The color palette is applied, and the font too. Every section has content with consistent images, and it's well styled. Under the hood, for example, I inspect the accordion. Okay, as you can see from the specific attributes and plain Tailwind classes on our components. We use some Google Fonts, for example. Okay. And some not-so-special effects, like this one.
[00:03:50] Okay, the creation of the page is done. Now we can change it. First one, the inline editing. Okay: one block, one instruction, only that block changes. And now in the page there's a contextual chat. We made a content change: we rename the hero and flip its columns.
[00:04:34] Okay. Still using the chat, we combine layout and content changes. We move the tips to the end and reorder them in one sentence. What I said.
[00:05:10] And last, from the general chat with no context, the same one we used before to create the new content, we ask to add visa info to the page. Okay. No, no. This was another change. Okay, this is the general chat, and we ask it to add the visa info to the page. It finds the page and inserts the section before the call to action. Okay. New section, the first one, and everything else stays exactly where it was. Okay, check.
[00:06:20] So, what the AI actually sees. We're starting here because this is the part we'd explain first to anyone building something like this themselves. And nothing downstream matters, not the validation, not the styling, not any safety net, if the agent doesn't start with an accurate picture of the site. So the first design decision was the most basic one: the agent asks the site what exists every single time instead of trying to remember it.
[00:06:54] There is the prompt versus the tool, and the distinction is not only cosmetic, because with only the prompt, the model has to remember your site, and it doesn't. In an early version, working from a prompt that described our components, it invented a block type called "hero section," while our actual block type was just called "hero." It wasn't confused; that's exactly what a language model does with no ground truth. It was producing the statistically plausible answer, and not the correct one. With the tools instead, the model asks, and every answer comes from the live site at that exact moment. So it cannot be out of date. It doesn't need to be remembered across a fine-tune or a prompt rewrite.
[00:07:50] Get block types structured tells it what exists. Get layouts tells it where things go. Get design system tells it how things may look. Validate layout checks whether a proposal is legal, and create landing page finally commits it. Notice the first four are read only, so they can be called as many times as the model wants, for free in terms of risk, because none of them is changing anything.
[00:08:21] That is the theory, but in practice those tools don't come from one big module; they come from four separate ones, and where we drew the line mattered more to us than what any single tool does. Only the first one, Transom, knows anything about Transom itself, or about AI at all. Layout Builder Tools is just four tools that read and write Layout Builder sections, like read sections, apply sections, get layouts, list content types, and it has no idea an AI even exists. You could install it today with no AI module anywhere on the site, point a completely different agent at it, and it just works. Component Variant Tools handles styling the same way. And the workspace tools (create, switch, get active, tracked content, publish) come from Tool Belt, a contrib module that we didn't write at all. That split was deliberate. So we wrote the generic primitives as their own modules from day one. Otherwise you end up with one enormous module nobody else can reuse, and if you change the page builder, it all dies with it.
[00:09:44] So, put those four modules behind one agent and a model, and this is the shape end to end: there's the editor, the agent, the tools, services, and the Drupal entities. Notice what's deliberately missing from this diagram: there's no arrow from the agent layer straight down to the database. The model never touches an entity API; it calls a tool. The tool calls a service, and the service is what actually writes to Drupal. And the provider, like OpenAI or Anthropic or whatever, sits right at the edge, so it can be swapped without touching anything below it. This is not just a clean diagram; it's the whole argument for why the next section is even possible. Every one of those tool calls is a checkpoint we control, because nothing skips it.
[00:10:40] So what does the discovery agent actually return? It's literally your site's current configuration, read live, and not a cached description. Add a block type or a field, and the discovery tool returns it immediately. Enable Layout Builder on a bundle, and it appears. Change the theme, and the class list changes with it. And there's nothing to keep in sync by hand: no registry, no fine-tuning run, no per-project prompt to rewrite every time someone adds a component. And the same module works on a site we've never seen, as long as the components have a decent schema.
[00:11:20] That's the second half of this slide. Your SDC schemas are now actually an AI-facing API. So a prop with no description, or a slot poorly named, like "content two" or something like that instead of something readable, degrades what may come out.
[00:11:42] None of this is free. Every one of those live lookups is context that the model has to read, and you pay for it in tokens on essentially every turn. So two rules kept that under control. The first one is that we want to always return the smallest thing that's still correct: class names instead of raw CSS, field names and field types instead of full field config, IDs instead of rendered output. And the second one, we want to make optional knowledge its own tool, so nobody pays for it by default. For example, the get Alpine reference tool exists precisely so the 90% of pages with no interactivity never load it. The single largest reduction in context size didn't come from either rule directly, but from not exposing every block type in the first place, only a curated subset. We'll come back to exactly how that subset gets decided when we talk about validation, because it turns out to reuse something that already existed.
[00:12:55] So this is the whole idea of this section in one sentence: the agent is not smart about your site, but it gets informed about your site. So this is what the agent sees, and it solved the problem for us at this point. A well-schema'd site just works, while a poorly schema'd one degrades predictably.
[00:13:21] But seeing the site correctly and writing to it correctly are two different problems. A model can call the get block types structured tool and get a perfect answer, but still propose a layout that references a region that doesn't exist on that particular layout. Or it can be asked to change one thing on a page that already has an hour of handwritten content on it, and happily throw away that content while trying to help. So discovery answers "does the agent know enough?", but it does nothing for what happens when it's wrong, or when you ask it to change its mind. This second question turned out to be the harder one to answer.
[00:14:07] So we want to make it reliable, and concretely there are five separate problems, and each one gets its own answer. Validation catches structurally illegal output before it's written. Self-correction gives the model a way to fix itself instead of just failing. Scoped edits stop "change one thing" from becoming "regenerate everything." Async keeps slow steps like image generation from blocking the page. And memory keeps a multi-turn conversation from starting over every time you say the next sentence.
[00:14:46] We start with validation, since everything else assumes it exists. The user intent goes in, the discovery runs, and it gets cached for the rest of that conversation, so you're not repaying for it on every turn. Then the agent proposes a specification, and validate layout checks three things against Drupal's live definitions, and not some static list anyone maintains by hand in the initial prompt. Like: does this layout plugin actually exist? Does this region exist inside it? Is this block type actually one the agent is allowed to use here? Nothing to keep in sync; the human and the agent see the same restricted things. And for example, does this field exist under this name on this bundle?
[00:15:42] If any of that is wrong, the specific error goes back to the model, naming what would actually be valid, and it tries again. Usually one or two passes are enough, three at most. At pass three, we assume that the request itself is the problem, so it stops and asks instead of guessing a fourth time. Once it's valid, the agent still shows the plan to the user in plain words before writing anything, because passing validation only proves that the page is legal from a structural point of view. It says nothing about whether the page is actually the page anyone wants to build.
[00:16:26] So the hard problem is where, especially, the moment you are not creating a page anymore but editing one that already has a person's work sitting inside it. Demos usually show generation, because generation is the easy half of the show, while editing is the half that decides if anyone uses the tool twice.
[00:16:50] If you say "make the three cards two columns and drop the third one," the layout changes, one card disappears, and the other two keep their text, their images, and anything you edited by hand. If you say "make the hero darker, more editorial, bigger type," only that one hero changes, and every other hero on the website stays exactly as it was. Just to be very clear, under the hood, applying a layout change is a full replace, not a patch. The tool that updates the layout is marked as destructive, and its own description even warns that any existing block you don't put back gets deleted.
[00:17:35] So the promise is not a structural guarantee baked into the data layer. It's three things stacked on top of each other. The tool is written to always reread the current page first, so the model has the entire existing layout in front of it before it changes anything. And editing a single block is surgical: the operation only touches the field you name, and that's enforced by the service itself. If the model still gets it wrong and drops something anyway, that mistake can land in a staging workspace and not on the live site. But we'll talk about this later.
[00:18:19] Before we get there, one more thing. Editing safely is one thing; doing it fast enough that nobody is staring at a spinner for minutes is another. Images are where that's the worst, because generating one can take several seconds, and a page can ask for eight, 10, maybe more of them at once. So eight images, two minutes of waiting; that's really a long time. So the images get queued, the page renders straight away with placeholders, and the human sees the current state, not the broken box.
[00:18:59] How do we do that? We immediately launch several background workers in parallel, each one working through a slice of the queue at once, and that's what actually gets images landing quickly instead of whenever a cron runs. So the page is already fully usable, and within a minute the queue has caught up and the placeholders are gone.
[00:19:23] As we were saying, we recommend that everything the agent does lands in a workspace, but it's not enforced. So once per session, the agent checks the active workspace, and if you are on live, it asks what you want to do: create a workspace and switch to it, or keep working directly on live. On a dev site, for a quick fix, working on live can be perfectly fine, but on a real site, a workspace is often the better choice. There, every piece of generated content is tracked inside it, and live stays untouched until you decide otherwise.
[00:20:00] Human editors review in a real preview. They can share a link with stakeholders like any other draft, and then choose to publish or revert it. Both actions are explicit and confirmed, so nothing happens by accident. In our experience, in fact, the question content teams actually ask is never "can it build the page?"; it's "what happens when it builds the wrong page on the live website?" So we wanted that question to come up at the start of every session, and not be something we promise to be careful about.
[00:20:35] So the generation was the easy part. The correction, scoping, queuing, and staging was the actual product part, and the hard part.
[00:20:46] Okay. The styling architecture. Everything so far has been about structure: section, region, block, field. None of it touched what any of it actually looks like. And visual generation is usually where AI building tools struggle, in one of two directions. Either the model reinvents your visual language from scratch in whatever taste it happens to have that day, or you strip that freedom away entirely and it can't touch styling at all. We needed something in between. It turned out to be an old idea applied here rather than a new one: give the model a fixed vocabulary and a fixed, named scope, and let it combine within that.
[00:21:37] So an editor says, for example, "make this hero darker." If you edit the component directly, every hero on the site changes with it. If you write inline styles instead, the site is unmaintainable within a month. So the AI picks a scope, one of four levels, and the most specific wins. Level one, for instance: the style for just this hero, nothing else. Level two, per page: dark specifically on the About page. Level three: the site default for that component. And level four, that is the original SDC template on disk, which we never touch. And this isn't a custom engineering concept that we built from scratch. Under the hood, every one of those first levels is an ordinary Drupal configuration entity. That's precisely why deleting one rolls you back cleanly. You are not undoing a database write; you are removing a piece of configuration, the same as reverting any other config change.
[00:22:50] So there are two modes. Two modes exist because there are two kinds of sites. So we implemented a Tailwind mode. In Tailwind mode, the agent writes utility classes into the variant's template, and a JIT build compiles them. That, of course, needs the standalone Tailwind CLI on the path. In CSS mode, the agent writes raw CSS instead, and it's scoped automatically at render time. Every variant gets one data attribute, and its CSS is wrapped in an attribute selector matching only that attribute, so there's no class name to collide with anything else on the page.
[00:23:32] And there is an operational cost. Obviously, the Tailwind CLI is unbundled. It has to be installed on every environment that uses it: local, CI, and production. Miss one and you get a warning on the status report. The option gets disabled, but content keeps generating, in CSS mode, regardless.
[00:23:55] Okay. So the whole idea of this section was: give the AI scope and vocabulary, and you don't need to give it taste. Maybe you want to work on the taste, applying something like Claude Design, but it's a separate task and problem.
[00:24:11] Okay. And let's cover the part we are proud of. Everything from here is the part that actually can be useful for you. So, okay, starting with the easiest one. Chat and image generation are operations assigned to a provider in config: OpenAI, Anthropic, Bedrock, Ollama, or whatever ships next month. Nothing in the tool layer depends on which one you pick, and self-hosting with Ollama works exactly the same way, same tool contract. The caveat worth mentioning: providers aren't equal in tool-call quality, and the edge cases we have seen are provider-specific, also model-specific.
[00:24:55] Another one here: the output is content, and content already has rules. Revisions, moderation, workspaces, permissions: all of them apply, with zero exceptions carved out for the AI. The agent generates into a workspace, a human editor reviews with a preview link, exactly as before. It moves through the same moderation states and gets published. The moment you add an exception, a fast path, a direct bypass just for convenience, the people who actually own that site will notice, and they'd be right to. We're using an "administer Transom" permission on purpose.
[00:25:35] So, when is Transom actually useful? For a site builder who already knows the components, building by hand is often faster. The win here isn't speed for experts. The win is that people who couldn't do this at all before now can. For example, bits that used to be an hour of clicking become one sentence. It works well for first drafts of structured marketing pages, populating a site for review, or for prototypes; bulk structural edits across many pages at once; getting a non-technical editorial staff styling inside a design system that already exists. It works badly for precise, pixel-specific design direction; long-form editorial writing with a distinct house voice; anything needing a real source or factual accuracy; sites with components that have poor schemas to begin with; and design ideas the design system simply has no vocabulary for.
[00:26:42] So if you are building something like this yourself, this is what we'd tell you to do differently than us from the beginning. Start with a primitives module: generic tools for your storage layer with no AI in it at all. Not for purity's sake; it's the piece other people can use tomorrow, and the piece that survives the day you change page builders. Build discovery tools before generation tools; you cannot generate against a site you can't see. Make validator errors enumerate the valid options, not just say "invalid." Queue anything slow; placeholders beat spinners every time. Stage everything: workspace first, generation second, never the other order. And fix your component schemas. They're an API now, whether you designed them to be one or not.
[00:27:34] Three things we can say. Page builders are moving: Canvas, Layout Builder. And the tool boundary was designed for exactly that. A port means rewriting one tool module, not starting the whole thing again. These are Tool API plugins already, the ones we implemented, so exposing them over MCP is probably a transport question. And the frontier isn't generation anymore. Generation is already good enough for what we need. Review is the part we haven't solved, and that's what needs the most work.
[00:28:11] If you remember three things from the last 30 minutes: tools, not prompts; discovery is what keeps the agent in step with a site that keeps changing. Most of our actual work went into the reliability layer (validation, scoping, queues, staging), not into the model or the prompting. And stage everything: governance is what made clients use this.
[00:28:39] Okay. Transom is on drupal.org. We now published its version, and Layout Builder Tools and Component Variant Tools are standalone and usable on their own, with no AI inside them at all. Everything is built on Drupal Tool, Tool Belt, AI Agents, Component Variants, and LB Plus. It depends on alpha and dev modules, so expect breaking changes, genuinely, not as a formality.
[00:29:12] Okay. Yeah, we made it past. If there's a question?
[00:29:34] (From the audience: Thanks very much. Just a quick question about the page generation tools. It looks like all of this is relatively agnostic to the tool that is in use. So in this case you've got Layout Builder, but I assume that Paragraphs or other tools would be fine.)
[00:29:48] Yeah, yeah. You have to implement the tools related to the page builder you want to use. But once implemented, it works, because everything is based on tools. So the main infrastructure is still valid even if you change the builder, the page builder. Okay. Thank you. Thank you.
Event Details
- Conference
- DrupalCon Europe
- Date
- September 30, 2026
- Location
- Rotterdam, Netherlands
- Skill Level
- Intermediate