On Tuesday PHP's security team gave notice of two critical bugs, both scored 9.2, with the fixes due on Wednesday at 14:00 UTC. By Wednesday morning every BOA server, PHP 5.6 to 8.6, had switched off one setting which neither Drupal nor Backdrop uses, session upload progress, and a new PHP security floor was waiting, empty. PHP published at 13:34 UTC, and ninety-odd minutes later 8.2.35, 8.3.36, 8.4.27 and 8.5.12 and the floor were on all three BOA trees, so every box below the floor starts its own system pass within half an hour of seeing it, automatic updates switched off or not. By the evening the fixed 8.6 candidate and PHP's own backports for 7.4, 8.0 and 8.1 had gone the same road, leaving 5.6 and 7.0 to 7.3 on BOA's settings, with no patch. BOA's defaults, PHP-FPM alone behind Nginx with no per-request PHP settings, had shut most of the described routes before anyone outside PHP's security team knew of the bugs, though not the out-of-memory bug, which only the fix closes.
When a company sells under several brands, someone eventually asks the obvious question: why can't customers put products from every brand into one cart and check out once?
But that's only half of the story. What happens after the order is placed? The hard part of a shared cart experience is everything after checkout, especially fulfillment.
How the cart works by default
In amulti-brand Drupal Commercesetup, each brand gets its own store entity. A store holds a brand's commerce settings:
Which merchant account takes the payment
Which prices and promotions apply
Which payment methods are available
Once something likeCommerce Store Domainis installed and configured, a shopper's cart belongs to the store of the brand they're browsing.
What makes a healthcare website HIPAA compliant on Drupal: the three places patient data gets in, the BAA question, the tracking-pixel rules after AHA v. Becerra, the module stack, and what 46 healthcare Drupal projects actually prioritise.
We're introducing AI Neuron, a module that bridges Drupal with Neuron AI, a PHP framework for building agents, tools and multi-step workflows.
When you're building AI features in Drupal, the AI module is the obvious place to start. It gives the whole site one place to configure providers and keys, and a default model for each kind of call.
Building an agentic solution means sequencing those calls into something that plans, decides what to do with a tool's result, and calls another tool in response. The Drupal ecosystem already offers modules for that: AI Agents, ECA, the Tool API. Each gets you part of the way, but what's left for the developer is gluing them together into one coherent solution. And that's the hard part: each piece lives in its own module, configured on its own screen, in its own way, which makes iterating on the result, adjusting it, and evaluating it, slow.
What we wanted was one place to drive that development end to end, from a developer's point of view: write the agent in PHP, iterate on its configuration quickly, and get real observability and evaluation, without ever leaving code to go configure something on a Drupal settings page.
Enter Neuron AI
Neuron AI is a PHP framework for building agents, tools and multi-step workflows. It handles the provider calls, the conversation memory, and the observability a run needs, so what's left to write is the part specific to what your agent actually does.
Under the hood, five concepts drive it:
Agent holds the conversation: give it a provider, instructions and a list of tools, and it takes a message, calls the model, calls a tool if the model asks for one, and keeps going until it has an answer.
Tools are what an agent is allowed to do: a name and description the model reads to decide when to call one, the inputs it accepts, and the code that runs when it does.
Workflow is the layer underneath all of this: a graph of nodes wired by the events they emit and accept. An agent is really just a workflow built for the common case of holding a conversation. Because it is a workflow, a run can pause to wait on a person and resume later, in a different request, which is what a step that needs a human's approval needs.
Chat history and memory keeps every conversation in a message store, from one scoped to a single request to one backed by a database that survives it. Once a thread grows past the model's context window, the store trims the oldest messages to keep the next call from failing.
Streaming sends the same four kinds of chunk no matter who's listening: text, a tool call, a tool's result, and reasoning where the model produces it. What changes is the adapter: it translates that stream into the shape a given consumer expects, the Vercel AI SDK's protocol, the AG-UI protocol, or a channel that keeps delivering chunks after the request that started the run has already ended.
Introducing the AI Neuron module
Reading the overview above, the shape of the integration seems obvious: translate each Drupal AI object into its Neuron equivalent, one for one. For providers, that's exactly what happens. A Drupal AI provider becomes a native Neuron provider, and the site's keys, default models and caching apply unchanged.
For tools and agents, we built something different. Neuron is a full framework in its own right, with its own tool-calling loop, its own memory, its own way of streaming and evaluating a run. Translating a Drupal tool or a Drupal agent into its Neuron equivalent would mean keeping two shapes in sync, and whatever came out the other end would still carry Drupal's own assumptions into an object Neuron has to treat as entirely its own.
So instead, developers write Neuron objects directly, as Drupal plugins, with no translation step in between. A plugin is a factory for the agent, the tool or the workflow it declares, built fresh each time one is asked for: it reaches into Drupal, its service container, its permissions, whatever the site has configured, and uses all of that to build a native Neuron object.
What comes out is exactly what Neuron itself would build from its own API, with no Drupal shape to it, which is the point: Neuron can test it against its own fake providers and evaluate it with its own harness, with no idea Drupal was ever involved.
That division pays off later, too. When the AI module's own tools and agents get bridged in, they'll be built the same way: plugins that manufacture the native Neuron object itself.
What you don't have to build: data persistence and logging
Every agent and workflow a plugin manager builds also gets storage, persistence and logging for free, on top of the provider bridge above.
Conversation storage: nothing to declare. Every message is a neuron_message entity row, keyed by the thread id, and already recording its own token usage. The entity is bundleable and fieldable, so a module that needs to track something else about a conversation extends the same entity with its own fields.
Workflow persistence: every agent and workflow gets a durable record of its run, so it can suspend in one request and resume in another, which is what a human approval step or a queue-driven agent actually needs.
Logging and observability: every run is tagged per agent and reported to the ai_neuron log channel.
That's the original promise kept: iterate on the agent, while the storage, persistence, logging and provider connection around it stay fixed.
Manufacturing native Neuron objects
With the ai_neuron module, Neuron's three building blocks, agent, tool and workflow, become Drupal plugins.
As outlined above, a plugin is a factory for native Neuron objects: ask the related plugin manager for one by its id and get back a native Neuron object.
Here's an example of a Drupal plugin that builds the matching Neuron object. Extend the base class and fill in the same methods you'd write against Neuron directly:
#[NeuronAgent( id: 'reporter', label: new TranslatableMarkup('Reporter'),)]final class ReporterNeuronAgent extends NeuronAgentPluginBase { protected function instructions(): string { return 'Summarize the content that changed.'; }}
A tool is a plugin too. Declare its properties, then put the tool's logic in __invoke():
#[NeuronTool( id: 'count_posts', description: 'Count the published posts of a content type.',)]final class CountPostsNeuronTool extends NeuronToolPluginBase { protected function properties(): array { return [new ToolProperty('type', PropertyType::STRING, 'The content type.', TRUE)]; } public function __invoke(string $type): string { // Count them and say so. }}
A workflow is declared the same way: list the nodes it's made of, and Neuron takes care of the rest:
#[NeuronWorkflow( id: 'edit_post', label: new TranslatableMarkup('Edit a post'),)]final class EditPostNeuronWorkflow extends NeuronWorkflowPluginBase { protected function nodes(): array { return [ new LoadPostNode($this->entityTypeManager), new ReviseNode($this->agents), new SavePostNode($this->entityTypeManager), ]; }}
Each node declares, in its own method signature, the one event it accepts, but it can fire any event back. That's the whole wiring: whichever node listens for the fired event starts next, with nothing left to configure by hand.
It also means a node can fire a different event depending on what it finds, starting a different node in response, which is what lets developers build workflows that branch and loop, as complex as they need.
Declaring these as Drupal plugins buys the usual things for free. The site discovers them with no manual registration, from any module that declares one, and a constructor asking for EntityTypeManagerInterface, or any other Drupal service, gets it through dependency injection like any other plugin.
Fetching and using one goes through its manager, which hands back a native Neuron object each time, a new one, because an agent carries the conversation it's having:
From there it goes anywhere Neuron takes it, straight through Neuron's own API: chat(), stream(), tools, middleware, chat history.
getNeuron() is the factory method behind all of this: it builds the native object, wiring in the provider, the tools, the error handler, whatever the plugin declared.
Overriding getNeuron() is the escape hatch, and it goes both ways. Drop in a hand-written Neuron agent, tool or workflow wholesale, and the base class configures nothing on top of it. That's also the door for anything built outside Drupal entirely: NeuronHub, Neuron's own package registry, publishes ready-made agents, workflows and toolkits, and any of them plugs into a site the same way, through the same override.
Try it
The easiest way to try it is to clone the repo and follow the instructions in its README.md: they set up a working site with the example module already enabled.
The ai_neuron_example submodule is a working agent you can talk to from the terminal: a Ghostwriter that writes blog posts for you. It ships a minimal Blog content type, three tools that create, list and edit posts, and an editing workflow of three nodes that the agent reaches through a tool, so one command exercises all three plugin types, plus structured output for the node that rewrites a post:
ddev drush ghost
It asks for a title and a body, and only invents them when you tell it to ("you decide", "don't ask, just create it"), in which case it writes whatever's missing and creates the post in the same reply. Every event a run emits prints to the terminal as it happens, tool calls and workflow nodes included, so you watch a run happen live. The command also names the conversation it reopens, so you can leave it and pick it back up later, which is the conversation store's work made visible.
What's next
Five things are planned, in no particular order:
Neuron tools derived from Tool API: one Neuron tool per tool plugin installed on the site, built from the typed inputs and JSON schema it already declares, so a tool written once is callable from a Neuron agent exactly as it already is from AI Agents, ECA, etc.
Neuron agents derived from the AI module's own agent plugins: one Neuron agent per configured AI Agents entity, usable as a step in a larger workflow.
Evaluations, running Neuron's own harness against agents the site already has.
Channels, so a long-running agent can run in the background and stream its output to the UI through them, even after the request that started it has ended.
Providers running both ways: a Neuron provider exposed as a Drupal AI provider too.
Audio has no picture to put an icon on, so the European Code of Practice asks for it to be declared by voice. Here I follow how version 1.0.0-beta1 of AI Disclosure, the module I created on drupal.org within the Drupal AI Initiative, does it. Images have an article of their own, and so does video.
Audio needs to be declared when it is a deep fake: when a voice credibly resembles a person who exists or could exist, and whoever listens would take it as real. The Commission's guidelines give exactly this example: a newspaper podcast with the voices of its hosts and a guest cloned to discuss current events. A voice given to a fictional character, in an audiobook or a game, stays out if nobody is misled about who is speaking. Noise reduction or normalisation, which removes interference without changing the words, stays out too.
The obligation falls on the publisher, under Article 50(4) of the AI Act, and it applies from 2 August 2026. The watermark the voice generator puts in the file is the provider's obligation, and a publisher cannot rely on it for their own declaration.
For audio, the final June 2026 version of the Code of Practice asks for a short spoken notice at the start of the deep fake, in plain words, in the language of the content or in English.
Planning a DNN to Drupal migration? See how Drupal helps government agencies meet WCAG 2.1 AA, Section 508, and ADA Title II rules with stronger web governance.
PHP has announced a critical PHP security release for Wednesday, October 21, 2026, at 14:00 UTC. We recommend that all Drupal site owners reserve time to ensure their PHP version is updated as soon as the release is available.
Site owners are responsible for maintaining the security of their hosting platform
It is the policy of the Drupal Security Team that site owners are responsible for monitoring and maintaining the security of third-party libraries and any non-Drupal components of the application and hosting platform. In rare cases, the Drupal Security Team will post an informational public service announcement (PSA) such as this one, but the remit of the Drupal Security Team remains limited to code hosted on Drupal.org's systems. Previous PSAs on third-party code in the Drupal ecosystem include:
If a host or developer runs your site, ask them today whether PHP has been updated. At Tag1 we have been updating client servers all day, and we made sure Drupal.org, whose infrastructure we manage, is patched.
What to do now
If a host or developer runs your server, start with them. Ask which PHP version is running and when PHP was restarted, then use the checks below.
Otherwise, update PHP. This is the only complete fix. I would patch mod_php servers first; where no patched build exists yet, use the stopgaps below. As of 18:25 UTC on 21 October:
Ubuntu has published USN-8948-1 for 22.04, 24.04, 26.04 and 26.10, and USN-8948-2 for 14.04 to 20.04 through Ubuntu Pro.
Debian has published DSA-6574-1 for trixie and, through Debian LTS, DLA-4848-1 for bookworm.
Docker Hub has fixed images for all four branches on the main architectures, and latest now points at them. Pull fresh and rebuild; running containers keep the old PHP.
The Remi repository carries the fixed releases for Enterprise Linux 9 (for example 8.4.27).
To confirm, check the version your site reports: Drupal shows it on its status report and WordPress under Tools > Site Health > Info > Server. Builds from php.net show the new number. Distribution packages often keep the old one: Ubuntu 24.04's fixed package is 8.3.6-0ubuntu0.24.04.13, yet the site still reports 8.3.6. There, check the installed PHP packages (for example dpkg -l | grep php) against your distribution's notice, or ask whoever runs the server to.
The PHP project's advisory lists stopgaps that reduce exposure to specific attack paths. They are a bridge to the update, not a fix. Restart every PHP worker after applying them:
Set session.upload_progress.enabled=0 in php.ini, the FPM pool or the Apache configuration. Do not rely on ini_set() or FPM .user.ini files.
Set memory_limit=-1 with php_admin_value so applications cannot override it, and put a container or cgroup memory limit in its place. This blocks only one route to CVE-2026-109618. Do not use RLIMIT_AS or RLIMIT_DATA for the replacement limit.
Cap post_max_size at 8M if you accept no uploads, or 32M if you do, and keep upload_max_filesize below it.
On PHP 8.5, also set fatal_error_backtraces=0.
After you patch
Patching does not tell you whether anyone got in first. The researchers list signs to look for, such as oversized PHPSESSID cookies, memory limit errors after multipart requests, and unexplained worker crashes. They add that none of these proves or rules out an attack. I would also look for PHP files in the web root that you did not deploy, and for new cron jobs and accounts. Because CVE-2026-109619 can leak process memory even if the attacker never gains code execution, I would rotate the database password and API keys on any internet-facing server that ran an affected version.
PHP released 8.5.12, 8.4.27, 8.3.36, and 8.2.35 on October 21, 2026. They fix CVE-2026-109618 and CVE-2026-109619, nicknamed "PHP2Shell", two vulnerabilities that can let a single unauthenticated request run code on a server. According to PHP's security advisory, every PHP installation that serves web requests is at risk.
TL;DR:
If you use DDEV only for local development, your DDEV projects aren't affected.
Update PHP on the servers where your sites are hosted.
If you use DDEV for casual hosting or ddev share, get the fixed PHP into those projects now, as described below, or upgrade to DDEV v1.25.5, which we hope to release on October 22.
What It Means for Your DDEV Projects
Local development isn't affected because a DDEV project listens only on your own computer, so nobody on the internet can send it a request. A project is exposed in two cases:
Casual hosting runs a public site with DDEV. An attack would run code in the project's web container rather than on the host, but that container can still change the site's files and reach its database.
ddev share puts a project on a public URL. Don't share a project until it has the fixed PHP.
:::warning[Update PHP where your sites are hosted] Your production servers are exposed to the internet, so update PHP there first; distributions and LTS vendors got the patches in advance. PHP 8.1 and older get no updates from the PHP project, so check with your vendor or upgrade. If you can't update right away, see Reducing Exposure below. :::
Getting the Fixed PHP Into DDEV Before v1.25.5
DDEV gets PHP from deb.sury.org. When we checked around 16:00 UTC on October 21, it had fixed packages for PHP 5.6 through 8.5 for Intel and AMD processors (AMD64), which run the vast majority of the world's web servers, most Windows and Linux computers, and Intel Macs. The builds for ARM processors (ARM64), such as Apple Silicon Macs (M1 and later), come later, and v1.25.5 waits for them.
On Intel and AMD computers, you don't have to wait for v1.25.5:
PHP 5.6 through 8.1 aren't in the ddev-webserver image. DDEV installs them when it builds the project's web image, so a rebuild installs the fixed packages. The version number doesn't change for these old versions, so check that ddev php -v shows built: Oct 21 2026 or later:
PHP 8.2 through 8.5 are in the image. Create this file in the project, rebuild, and check that ddev php -v shows 8.5.12, 8.4.27, 8.3.36, or 8.2.35:
# .ddev/web-build/Dockerfile.php2shell
# Safe to keep; you can delete it after upgrading to DDEV v1.25.5
RUN (apt-get update || true) && apt-get install -y --only-upgrade 'php*'
We tested both cases on DDEV v1.25.4 on an Intel computer, with and without use_hardened_images. On Apple Silicon Macs (M1 and later) and other ARM computers, wait for deb.sury.org's ARM64 builds or for v1.25.5.
Reducing Exposure Until You Can Update
PHP's advisory lists settings that block the attack paths it knows about. They don't make an installation safe, and a low post_max_size can break large uploads, so update as soon as you can. In a DDEV project, put them in a file and run ddev restart:
; .ddev/php/php2shell.ini
; Delete this file once PHP is updated
session.upload_progress.enabled = 0
; Use 32M if the site takes file uploads
post_max_size = 8M
upload_max_filesize = 6M
On PHP 8.5, also add fatal_error_backtraces = 0. DDEV adds .ddev/php files to PHP-FPM's configuration, so they apply before PHP parses a request, as the advisory requires. On other servers, the same lines go in php.ini or PHP's conf.d directory, followed by a restart of every PHP worker. The advisory has the full list.
Thanks, Ondřej
Ondřej Surý, who maintains the PHP packages for Debian and Ubuntu that DDEV and much of the PHP world use, published fixed packages for Intel and AMD processors for every version back to PHP 5.6 on the day PHP released the fixes, with ARM builds to follow. If your work depends on those packages, consider sponsoring him.
We'll update this post when DDEV v1.25.5 is out. If you have questions, reach out in any of the support channels.
This article was edited and refined with assistance from Claude Code.
This post is adapted from the DA Insider, the Drupal Association's monthly newsletter. Subscribe here to get it in your inbox each month.
A note from our CTO
The Drupal Association team is incredibly grateful to have spent time with our community at DrupalCon Rotterdam. Dries Buytaert made one thing clear: Drupal is light-years ahead of its reputation. Our keynotes proved it, and stories from brands like Mars and World Cancer Day showcased Drupal's global power and ability to scale for good, both with cutting edge page building and AI integrations.
We were thrilled to celebrate our International Splash award winners, and the winners of the Women in Drupal award. It's our mission moving forward to expand our recognition for Makers, Patrons, and Advocates across the Drupal ecosystem, and to share Drupal's story beyond our own community.
Thank you to every attendee, speaker, sponsor, volunteer, and contributor who made Rotterdam absolutely unforgettable. We're excited to share what's next.
Tim Lehnen, CTO
DrupalCon Rotterdam Was Everything & More!
This year's event welcomed 876 participants across 46 countries for four days of sessions, summits, workshops, and contribution activities at the Postillion Hotel & Convention Centre WTC Rotterdam.
The Driesnote was remarkable. Key highlights included the launch of the Drupal Advocacy Program, which awards contribution credit for writing, recording, and sharing about Drupal; the announcement of the Rosetta Sprint, aimed at making Drupal's capabilities readable by AI agents, systems, and humans alike; and a new public AI demo site showcasing Drupal's growing AI capabilities - watch the six demos here.
Dries also introduced the concept of Stewarded Open Source, positioning Drupal as the ideal platform for Europe's push for digital sovereignty. Read the full Driesnote recap here.
A huge thank you to every attendee, speaker, sponsor, volunteer and contributor who made DrupalCon Rotterdam unforgettable. Relive the memories through the official photo pool from the event.
The Drupal community doesn't stop. Next stop: Orlando (March 22-25) and Edinburgh (October 25-28) in 2027! See you there!
Introducing the Drupal Advocacy Program
Drupal is light-years ahead of its reputation. We can change that together.
We've launched the Drupal Advocacy Program: a new Drupal Association pilot that awards contribution credit for content that helps the world discover modern Drupal.
Write a blog post for your market. Record a demo. Speak at a non-Drupal event. Translate a case study for your language. Appear on a podcast. Even boosting someone else's talk or story counts.
Throughout the year, we'll roll out themes with ready-made messaging and proof points for you to make your own - and themed content earns 2x-3x credits.
The Engineering Team Had A Busy DrupalCon.
The Drupal Association engineering team was just on-site at DrupalCon Rotterdam, presenting the latest updates and working with the community in the contrib room on everything from the future of Drupal.org, to reducing friction with our GitLab contribution tools.
One of the major highlights of DrupalCon was the release of a brand-new Drupal AI demo experience. This new demo showcases the incredible breadth and depth of AI capabilities in Drupal, including page building capabilities and extremely powerful tools for context and governance.
If you attended Rotterdam but missed the session, keep an eye out in your inbox for a link to the private playlist. For the public at large, the DrupalCon session recordings will be available to everyone after a 30 day embargo from the end of the event.
Get Involved With DrupalCon Orlando 2027
Speak
The Drupal community thrives on the knowledge and experiences its members bring to the stage. Submit your session proposal for DrupalCon Orlando 2027 and share your expertise with the global Drupal community. The Call for Speakers closes October 20, 2026.
Register
Early Bird registration is open, register by January 30, 2027 to save on your ticket. Consider adding a Summit or training to connect with industry peers and deepen your Drupal knowledge.
Sponsor
A variety of sponsorship packages are available, from exhibitor booths and high-visibility branding to smaller events like the Business Leaders Dinner, Summits, and training. Explore sponsorship opportunities and find your right fit.
Volunteer
Want to give back to the Drupal community while making DrupalCon Orlando 2027 an unforgettable experience? Volunteer applications are open for a new set of committees. Explore volunteer opportunities. Apply by October 30, 2026.
Attend
If you need financial assistance to attend DrupalCon Orlando 2027, this is your chance! The Inclusion and Community Scholarships are now open. Apply by October 30, 2026.
Participate
Can't make it to a Drupal event? You can still enter the Mascot Contest featuring an alligator. Be it a plushy, a photo, or a friend in a gator costume! If you prefer to stay off social media, let us know and we'll post it anonymously for you.
Why It's vital to upgrade, and how to easily move to D11 hassle-free Better a little bit of time & money for an efficient solution, than a lot of time & money for a big problem . Your Drupal site may be one unpatched vulnerability away from trouble. Drupal 7, 8 & 9 no longer receive security updates, and end-of-life for Drupal 10 is around the corner this December. Here's why it matters. If your site goes unsupported: There aren't community-supported updates for any new vulnerabilities that may come up There aren't community-supported updates for most contrib modules While your site may still be running and your visitors keep browsing, the gap between "working" and "protected" widens Your content, your user data, and your organization's reputation are at risk An unpatched website can become an audit finding in security and compliance reviews The longer you wait to address it, the bigger (and more expensive) the upgrade job becomes. The good news? Fixing it doesn't have to be a long
An AI-generated image can reach a Drupal site with a digital signature attached, and leave it with another one. Three modules sit in between, and each does one job. Here I follow them one by one on a real image, the cover of this article made with ChatGPT, and I say what held up on my test site and where it broke. What an AI image carries and how AI Disclosure, the module I created on drupal.org within the Drupal AI Initiative, labels it is covered in the article on metadata and labels for AI images. Content Credentials reads: it opens the signature of the files an editor uploads and, if it says the file was made with AI, proposes the grade in AI Disclosure. AI Disclosure declares: it keeps the grade the editor confirms, shows the label to readers where the law asks for it and writes the metadata into the copies.
In May 2025, the Drupal Association proposed an International Drupal Federation under Belgian law. It could unlock European public funding, give Drupal's assets a neutral legal home, and reduce dependence on a single legal system. At its public board meeting in Rotterdam, the DA said it supports the idea but won't drive it. Somebody else has to pull the strings. Jürgen, watching from the outside, sees one trap: every stakeholder starting with "what's in it for us?" and "how much is it?". He suggests two phases. First, write a charter that defines the Federation's objectives, responsibilities, decision-making, legal framework, membership and conflict resolution, with everyone's own stakes left out. Then let each prospective member decide whether to join.
We've spent the last year building an AI-assisted development pipeline for daily use on client projects. Here's what that looks like in practice, and where humans stay firmly in control.
Whether you're a technical lead at another Drupal agency or a government team new to AI, here's what accountable adoption looks like in practice.
The pipeline: ticket to pull request
Planning
We ask Claude to review the ticket-Jira or the relevantDrupal.orgissue queue-and ask clarifying questions before proposing a plan. We iterate until the developer and AI share the same understanding of what's required.
Implementation
We draw on approximately 30 reusable skills during implementation. Among them is a profiling skill for Drupal performance bottlenecks.
We also connect 2-3 MCP servers depending on the task-typically PHPStorm, Chrome DevTools, and Xdebug for runtime debugging instead of dump statements. A simple grep is often faster than routing a search through an IDE's MCP server, so we default to whichever tool is cheapest and still gets the job done.
Review and test coverage
Before anything nears a pull request, Claude reviews its own code and tests for scope creep and duplication. It also tests whether a slower browser test could be a faster kernel test.
Quality checks
We run PHPCS, PHPStan, and relevant PHPUnit tests. Claude Code's built-in security-review skill flags vulnerabilities before code goes anywhere near a pull request.
Final review and PR creation
One more pass for optimisations. A human creates and pushes the commits and creates the pull request.
Human review, always
Lastly, a team member gets assigned for manual review. Every pull request receives a human sign-off before merge, regardless of how it was produced.
Bootstrapping our own tooling
Beyond the skills above, we're building custom Symfony commands to bootstrap repetitive parts of our own code, currently living in github.com/previousnext/commands. We plan to move them into a Drupal contrib project, and are weighing whether a version belongs in core.
We're also watching the new dr command that landed in Drupal 11.4.0. It's an experimental native CLI in core, built on Symfony Console, that lets modules register their own commands directly. It's also a natural home for this kind of tooling as it matures.
Guardrails
For government readers, "how do you control this" usually matters more than "how much faster is it."
Claude Code runs in an auto-mode configuration that restricts its access.
We're trialling Docker sandboxes to isolate it further.
Senior developers direct every stage.
Where we're going next
We're trialling AWS Kiro alongside Claude Code, comparing its spec-driven approach on the same kind of tickets. We're also evaluating other models, looking for anything that matches our output more efficiently than our current default.
On the guardrails side, we're extending the Docker sandbox trial into a locked-down local development environment for the whole team, not just the agent. And we're building out more front-end-driven tooling to match the depth we already have on the PHP side.
One result is already paying off after using AI to reverse-engineer our Mixtape design system from Storybook into Figma. New designs now start from accurate Figma components and export directly to Mixtape code. This has closed a loop that previously required manual translation between design and code.
We're also aligning with the Drupal AI Initiative's Outside AI workstream. This focuses on how external agents connect to, inspect, and safely act on a Drupal site.
Drupal's structured content, permissions, and governance model are what make agent-driven changes safe in the first place. Our pipeline is a working example of that.
What this means in practice
We've shared our approach to demonstrate that AI can be integrated responsibly and to encourage others to adopt best-practice approaches.
For other Drupal agencies, the biggest gains aren't "AI writes code faster". The efficiencies lie in the steps teams skip when moving fast, like clarifying tickets before planning and keeping test coverage lean.
For government teams, this doesn't require removing human accountability. In fact, we view human oversight as non-negotiable.
AI changes what a senior developer spends time on, such as planning, architecture design, refinement and review. It doesn't change who's responsible for the outcome.
What it means for clients
For our clients, nothing changes regarding who's accountable for what ships. Every change still goes through the same human review it always did. A senior developer signs off on every pull request, regardless of how it was produced.
What does change is where the time goes. Less of it sits in boilerplate, repetitive setup, and chasing down under-specified tickets. Instead, more of it goes into the actual problem you're asking us to solve.
Turnaround on well-scoped work is faster, without lowering the bar on what gets reviewed before it ships.
Let's compare notes
We don't have a rigorous study to back this up, but our estimate is a 20-30% efficiency gain across the board.
The gains vary by task type: boilerplate work like scaffolding new content types is up to 80% faster. Debugging, both backend and frontend, has improved dramatically.
While we've always been thorough in our reviews, we've still seen review time increase. This is because we're being extra cautious (rather than having previously waved through reviews).
AI in Drupal development moves fast. What we're using today will likely look different in six months.
New techniques will emerge, model costs will shift, and the community will settle on what actually works. We expect to keep adapting, and we'll keep sharing what we learn as we go.
We're genuinely curious about how other Drupal agencies are using AI in development and the efficiency gains you're seeing.Let's talk.
Build a reliable local Drupal environment with DDEV. Follow the steps to start a new site, import an existing project, and export the code, database, and uploaded files needed to recreate it elsewhere.