Main Image
Photo by Jason Leung on Unsplash
October 28, 2026

One trace, inside and outside Drupal: a proposal for Rosetta

by Jürgen Haas

Dries launched Rosetta in his DriesNote at DrupalCon Rotterdam. Last week, his blog post set the technical scope. Modules describe their data and operations once, and AI assistants, front ends and workflow systems reuse that description. One of his examples: a Maestro workflow calls a tool exposed by ECA. "Neither system needed a direct integration with the other."

That's exactly how it should work. Until something breaks.

Then I have two traces. Maestro recorded its process, ECA recorded its model run, and neither knows the other exists. Put an AI agent in between and an Activepieces flow at the end, and I'm debugging four strangers.

My proposal for Rosetta: describe an operation once, trace it once. Everything below is open for discussion.

Everybody has a logger

In German, a log is a "Protokoll". We take those seriously. So do Drupal's workflow and AI projects, each in its own way:

ProjectRecordsIdentifies a run byReplay
ECAEvery step, with all available tokensModel and eventPlayback in the Workflow Modeler
AIPrompts and responses (AI Logging), OpenTelemetry spans for provider callsThread and parent IDsIdentical requests, in tests
FlowDropInput and output of each stepPipeline, parent and root pipelineRe-run as a new pipeline
MaestroProcess, tasks and variablesProcess IDRewind and continue, via the trace screen
OrchestrationNothing--

Replay was the feature ECA users had asked for most. It even plays back a run in a standalone viewer, without Drupal. I wrote about it in Test, Replay, Debug.

But none of these IDs ever leaves its own system. And the last row is mine. Orchestration connects Drupal with Activepieces and keeps no run log at all. Not my proudest table row.

The runner already has a slot reserved

Dries wrote that Drush, MCP, ECA, FlowDrop, Maestro and his album module "can all call the same runner, ToolRunner::run()." They can. Four callers don't. Orchestration is one of them. Again. Maestro's tool task, FlowDrop's tool provider and WebMCP are the other three. All four load the tool plugin and execute it directly. Maestro will move its tool task to the runner, time permitting.

The runner should be the one place every tool call passes through. The Tool API maintainers say so themselves, and the source already reserves the spot:

// Attach points: an at-most-once claim on a call id, and the audit
// record of the call opening, belong here.
...
// [attach point: audit - call closed, outcome attached]

Both are comments. Nothing is attached yet.

The other half is the Invoker, the object that tells a tool who is calling. It holds an ID string and a list of capabilities. No run, no parent step, no trace. A Maestro task calling an ECA tool can't even say "I'm step 7 of process 4711".

The proposal

One shared API for tracing, debugging and replay. ECA, AI, FlowDrop, Maestro, Tool API and Orchestration use its services instead of maintaining their own. Four parts.

Correlation: don't invent anything. W3C Trace Context has been a Recommendation since 2021, and OpenTelemetry builds on it. Its PHP SDK is stable for traces, metrics and logs. The MCP spec of 2026-07-28 carries traceparent in each request's _meta. It also deprecates MCP's own logging in favour of OpenTelemetry. n8n's tracing, still in preview, accepts and forwards traceparent. The AI module already emits spans, but its parent IDs don't become span parents yet. Drupal has the OpenTelemetry module, which traces requests, database queries and exceptions. It works extremely well. What's missing are runs and steps: each should become a span, with the trace context travelling along every tool call, queue item and webhook.

Across systems means end to end, not only inside Drupal. The Claude Platform's MCP connector already sends a traceparent in _meta with every tool call. If Drupal's MCP server picks it up, the trace starts where somebody typed the prompt. That helps with debugging, and with evals.

Step state: what OpenTelemetry doesn't cover. A span says that a step ran and how long it took. It doesn't keep what the step saw. Replay needs exactly that: ECA's tokens, FlowDrop's job data, Maestro's variables. So we need one serializer for all, and it has to be cheap. ECA learned that the hard way. Before we fixed it, a single recorded step reached 28 MB. Now an unchanged step stores a marker, an entity under several token names is stored once, and identical sub-trees across steps collapse into a hash. Then everything gets compressed.

Rosetta helps here, too. Tool API already describes each tool's inputs and outputs, so the serializer knows what it records and a viewer knows how to show it. Describe once, record once. Large state goes to storage, with only a reference on the span. The OpenTelemetry GenAI conventions recommend the same. Maestro already works that way. It keeps entity IDs, sometimes of revisions, never copies of attachments. A revision ID points to the content as it was.

Storage: pluggable, preferably external. The database is fine for a small site and a few days of history. That's what ECA does today: by default, the last ten runs per event, for seven days. Anything bigger belongs outside Drupal. Grafana Tempo and Loki, Elastic, Jaeger and OpenObserve all accept OpenTelemetry data natively. Meilisearch was on my first list, too. With filterable values capped at 468 bytes, it's a good index to find a run, not a place to keep one.

Replay: playback first. The Workflow Modeler plays back ECA runs today. The Modeler API defines a replay contract for any model owner, but no data format: each owner brings its own. With a shared record, playback could cover a whole run across systems. The Maestro task, the ECA model it called, the AI agent inside that model, the tool the agent picked. One timeline. WebMCP already shows tool activity in a browser sidebar, for one page. The same record could fill it for the whole run.

A before/after diagram

Re-execution is a different beast. An email can't be unsent. Temporal records side effects once and never runs them again on replay. Activepieces re-runs the step that was in flight, so it may run twice. Maestro does a third thing: rewind to a task, fix the variables, let the process continue. Randy Kolenko, one of Maestro's maintainers, and his team do that for customers all the time. Picture a financial task completed at 3 a.m., with a photo of the children attached instead of the Excel file. Maestro's upcoming Trace Archive module keeps a before and after picture of each task's variables. Those are the values a rewind can restore. That's a decision for all of us, not for each module.

Six open questions

Context across boundaries. Tool calls, queue items, cron runs and webhooks all have to carry the trace context. Activepieces exports logs and metrics but, in its own words, "OpenTelemetry tracing is not emitted". Every call from there into Drupal starts a fresh trace.

Long-running runs. A Maestro process can wait days for a human. OpenTelemetry has an open issue from December 2024: no solution yet for spans that last hours or days. Tail sampling in the OpenTelemetry Collector waits 30 seconds by default before it decides. Maestro waits until Tuesday. That doesn't lock Maestro out. Each task run can be its own short span, with a span link back to whatever started it. n8n already links runs that resume after a wait. It works the other way round, too: ECA starts a Maestro process and is done, while Maestro carries on for days. What's missing is a convention we all follow.

Privacy and retention. Recorded state contains personal data, and sometimes secrets. Who may view a trace? What gets redacted before it leaves Drupal? How long do we keep it? GDPR has an opinion on all three.

Identity and access decisions. Who started the run, and on whose behalf does a step act? Was it delegated to an agent, and through which interface? Which gates did each step pass, and which one said no? ECA already records "access denied" as a step type, and the runner tells denied access apart from failure. OpenTelemetry has user.* attributes, still in development, and nothing for delegation. A proposal for authorization spans was closed as not planned. Room for Drupal to help. The trace should record decisions. It should never carry permissions.

Scoped recording and config versions. ECA's debug mode is site-wide. We need recording per model, per caller, sampled, or on a condition like "orders above 1,000 euros". And each record must say which version of a model ran. Yesterday's run replayed against today's model shows you something that never happened.

A shared vocabulary. OpenTelemetry has conventions for HTTP, databases, CI pipelines and AI agents. For workflows in general, it has none. Drupal alone runs several workflow engines. We could define run, step and trigger once and contribute them upstream.

Why not wait for the sprint

The Rosetta Sprint has no date yet. Tool API is at beta 12. Adding a trace context to the Invoker and filling those attach points is easier now than after 1.0. The same goes for every project in that table.

There's a public Rosetta channel on Drupal Slack. Bring your logger. Everybody has one.

Thanks to Ronald te Brake, Dries Buytaert, Scott Falconer, Randy Kolenko and Michael Lander for their feedback on this post in the Rosetta channel.

Add new comment

Klartext

  • No HTML tags allowed.
  • Lines and paragraphs break automatically.
  • Web page addresses and email addresses turn into links automatically.
CAPTCHA