Andre
May 20, 2026
  38
(0 votes)

Optimizely Opal: How to Build Effective Workflow Agents

If you're building workflow agents in Optimizely Opal, this post covers how specialized agents pass context to each other, why keeping agents small and focused matters, and a useful trick for handling situations where you're not sure how to proceed.

I recently decided to put Optimizely Opal through its paces. The experiment: build a simple mock API, feed external data into Opal, and see if a workflow agent could take it from there and autonomously publish content to the CMS, with no human intervention required.

The workflow agent I built pulls data from an external mock API on a schedule, analyzes it, checks it against existing content in the CMS, makes a judgement call on whether a new article is warranted, and if it is, writes and publishes it to the CMS, all without any human intervention.

It is made up of 5 specialized agents, each with a single responsibility, and a condition that branches the workflow based on whether a new article is warranted.

My example consists of the following:

  • An agent that retrieves route information from the mock AviationStack API
  • An agent that compares the route info with articles published in the CMS, and makes a judgement call on whether the info from the API call warrants a new article in the CMS
  • An agent that writes an article based on the info received from the external mock AviationStack API
  • An agent that publishes the new article to the CMS
  • An agent that gracefully ends the workflow if no new article is needed


image.png

The full workflow agent. A scheduler triggers the process, data flows through each specialized agent in sequence, and a condition branches the workflow: TRUE continues to writing and publishing, FALSE ends the workflow cleanly

 
If you want to build a similar workflow agent yourself and apply some of the tips here in practice, here’s what you need:

  • Optimizely Opal
  • Access to Optimizely CMS
  • A mock API with a Custom Tool configured in Opal
  • Basic familiarity with creating specialized agents in Opal

Here's what I learned


There’s no prompting between specialized agents

Each agent passes its output directly to the next and runs completely on its own, with no human in the loop. This keeps the workflow consistent and predictable, but it also means you need to be deliberate about what each agent outputs, because the next agent depends on it entirely.

Agent 1 output:

image.png

The first specialized agent outputs a simple JSON object containing the route information retrieved from the mock AviationStack API


Agent 2 Input:

image.png

image.png

That same "routes" object becomes the input for the next agent, defined as a required variable and referenced directly in the prompt template. This is what "output becomes input" looks like in practice.

Create as many specialized agents as you need

Don't hesitate to create as many agents as your workflow needs, and be as granular as necessary. Each agent should do one thing well, not many things adequately.

Developers will recognize this as the Single Responsibility Principle (SRP), and it applies just as well here. For those less familiar with the term, the idea is simple: don't create one agent that retrieves external data, analyzes it, writes an article, and publishes it. That's too much for one agent to handle reliably, and you'll end up with bloated instructions. Split those responsibilities across separate agents instead, and let them pass context to each other.

image.png

A single agent handling too many responsibilities. This is harder to debug, harder to maintain, and more likely to produce inconsistent results.

image.png

The same workflow split across three focused agents, each with a single responsibility, and each passing its output to the next.

If you run into a gray area and you're not sure how to handle it, create a specialized agent

This is simpler than it sounds. When you hit a question like "How do I get it to write an article?", you create a specialized agent for it. "How do I get it to publish to the CMS?", you also create a specialized agent for it. Most problems in a workflow agent have the same answer: a focused, purpose-built specialized agent.

A good example from my own workflow: when the condition evaluates to false, meaning the external data doesn't warrant a new article, I needed the workflow to simply stop cleanly. There's no built-in "do nothing" option, but the answer was straightforward: create an "End Workflow" agent whose only job is to acknowledge the decision and exit gracefully.

image.png

The "End Workflow" agent keeps it simple by design. No tools, no content creation, no external calls. Its only job is to end the workflow cleanly when no action is needed, which is exactly the kind of focused single-responsibility agent your workflow will thank you for later.

Don't assume an agent has context from earlier in the workflow unless you explicitly pass it

This is an important one. Just because multiple specialized agents live inside the same workflow agent doesn't mean they automatically share context. If Agent 4 needs data that Agent 1 retrieved, you need to explicitly pass it through each agent's inputs and outputs along the way, it won't be there by default.

In my workflow, by the time the article-writing agent needs to do its job, it has no automatic awareness of the route data retrieved at the start. If I want it to have that context, I need to explicitly include it in the outputs of the agents before it, and specify it as an input to the agents that follow.

image.png

The output schema of my "Gap Analyzer" agent explicitly carries the "routes" object forward, alongside its own "reason" and "publishDecision" fields. Without "routes" being defined here as an output, the article-writing agent downstream would have no access to the original API data, even though it was retrieved earlier in the same workflow.

That's about it for now! Hope this helps someone else out. If you've built something similar or have any questions or suggestions, I'd love to hear about it in the comments. Thanks for reading!



May 20, 2026

Comments

Please login to comment.
Latest blogs
ReviewPR: An Azure Function That Reviews Your Azure DevOps Pull Requests With Claude

A while back I wrote about an  Azure Function App for PDF creation that we use to offload PDF rendering from our Optimizely DXP site. That same...

KennyG | May 19, 2026

Accelerating Optimizely CMS and Commerce upgrades with agentic AI (Part 2 of 2)

The Real Transformation in Optimizely CMS 13: Why the Upgrade Itself Is the Easy Part. A field-tested playbook for enterprise teams moving from...

Hung Le Hoang | May 18, 2026

Is the most powerful AI model really the best value?

Artificial Intelligence is already becoming part of everyday software development. Developers now use AI tools to generate code, write documentatio...

K Khan | May 16, 2026

Optimizely London Dev Meetup 2026

Well, everyone, it's that time of the year again, and we have another London Developer meet up coming for this summer. The date is set for the 2nd ...

Scott Reed | May 15, 2026

Building a Custom RAG for Optimizely Opal

How to design a standalone RAG service for documents that don't belong in Optimizely One, and expose it to Opal and other AI tools without coupling...

Michał Mitas | May 14, 2026 |