Skip to main content

Drupal Claude Agent SDK Runtime: Real Tool Execution Inside Drupal

· 5 min read
Victor Jimenez
Software Engineer & AI Agent Builder

The first version of drupal-claude-agent-sdk-runtime gave you session management and result objects, but tools were mocked. You could simulate agent workflows inside Drupal, but you could not actually execute anything. That ceiling had to go.

What Changed

The runtime now ships a real tool execution framework. Two new classes define the contract and the dispatcher:

  • ToolInterface.php declares three methods every tool must implement: getName(), getDescription(), and execute(). This is the boundary. If a class satisfies the interface, the runtime can run it.
  • ToolExecutor.php manages the registry. It exposes register(), remove(), has(), get(), execute(), listTools(), and describeTools(). You register tool instances, the executor validates and dispatches calls, and you get structured results back.

ClaudeAgentRuntime now accepts an optional ToolExecutor at construction time. If you pass one in, the runtime gains an executeTool() method that delegates to the executor. If you don't, the runtime still works for session-only use cases -- no breaking changes. The runtime also has a closeSession() method for explicit lifecycle control.

ClaudeAgentSession tracks a closed state with double-close protection. Calling closeSession() twice does not throw -- it short-circuits cleanly. This matters in Drupal's request lifecycle where shutdown hooks can fire more than once.

Tech Stack

ComponentTechnologyWhy
CMSDrupal 10/11Service container, dependency injection
RuntimePHP ClaudeAgentRuntimeOptional ToolExecutor, backward-compatible
ContractToolInterface (3 methods)Small surface, any tool can implement it
DispatchToolExecutor serviceRegistry pattern, validates and dispatches
TestingPHPUnit (32 tests, 4 classes)Every public method, happy + failure paths
LicenseMITOpen for adoption
Define the Contract First

ToolInterface is three methods. That is it. The executor does not know or care what your tools do internally. Keep the contract small and the registry dumb. The intelligence belongs in the tools, not the framework.

Double-Close Protection Matters in Drupal

Drupal's request lifecycle means shutdown hooks can fire more than once. If your session close handler throws on the second call, you get mysterious errors in production. The runtime short-circuits cleanly on double-close.

src/ToolInterface.php
interface ToolInterface {
public function getName(): string;
public function getDescription(): string;
public function execute(array $input): array;
}

Test Coverage

32 PHPUnit tests across 4 test classes: RuntimeTest, SessionTest, ResultTest, and ToolExecutorTest. The test suite validates tool registration, duplicate handling, execution dispatch, session state transitions, and the full runtime integration path. Every public method on every new class has at least one assertion covering the happy path and one covering the failure mode.

Test class breakdown
Test classCoverage area
RuntimeTestSession lifecycle, tool execution delegation
SessionTestState transitions, double-close protection
ResultTestStructured output formatting
ToolExecutorTestRegistration, dispatch, duplicate handling, error paths

Drupal Integration

The module wires the executor as a Drupal service: claude_agent_sdk.tool_executor. You inject it the same way you inject any other Drupal service -- through the container, via \Drupal::service(), or through constructor injection in your own services and controllers. The runtime and executor are decoupled, so you can swap, extend, or decorate the executor without touching the runtime.

Why this matters for Drupal and WordPress

Drupal's service container and dependency injection make it a natural fit for a registry-based tool executor -- you wire claude_agent_sdk.tool_executor like any other service, and custom modules can register tools without modifying the runtime. WordPress developers building similar agent integrations can adapt the ToolInterface pattern as a plugin contract, using WordPress hooks to register and dispatch tools. The double-close session protection is especially relevant for both CMS platforms, where shutdown hooks and request lifecycle callbacks can fire unpredictably.

Technical Takeaway

Define the tool contract first, then build the executor around it. ToolInterface is three methods. That's it. The executor doesn't know or care what your tools do internally -- it only knows the interface. This means you can write tools that call Drupal APIs, external services, or pure computation, and the runtime dispatches them identically. Keep the contract small and the registry dumb. The intelligence belongs in the tools, not the framework.

References


Looking for an Architect who doesn't just write code, but builds the AI systems that multiply your team's output? View my enterprise CMS case studies at victorjimenezdev.github.io or connect with me on LinkedIn.