Orchestrating ambient agents with Temporal

AUTHORS
Kevin Martin
DATE
Sep 18, 2025
CATEGORY
DURATION
0 MIN

Building a proactive, 24×7 crypto trading platform with multiple AI agents has been both challenging and enlightening. Using Temporal for orchestration and the Model Context Protocol (MCP) for tool interfaces, I designed a system around three core agents: a broker agent (the user-facing entry point that manages intents and orchestrates Workflows), an execution agent (responsible for making and executing trading decisions), and a judge agent (that continuously evaluates performance and updates the execution agent’s system prompt and strategy). Surrounding these are supporting Workflows for market data, order placement, and ledgering.

The inspiration came this past June at the AI Engineers World’s Fair in San Francisco, where I first encountered the concepts of ambient intelligence and proactive AI at a breakout hosted by AWS and Anthropic. The idea of agents that run continuously — quietly nudging the system forward without waiting for explicit prompts — sparked this project. Then in July, at IBM’s AI Agent Meetup, Claire Longo’s talk introduced the idea of an LLM as judge. It was such a compelling concept that I quickly extended my architecture with a judge agent, turning the system into one that is not only proactive but also self-refining over time.

Along the way, I discovered several key advantages of using Temporal in such an AI-driven system. In this post, I’ll dive into what I learned about five crucial features of Temporal and how they benefited my multi-agent architecture: Schedules, Signals & Queries, Temporal’s UI, workflow orchestration, and Temporal primitives as MCP tools. diagram-kevin

Temporal Schedules: Enabling proactive agents#

One of the first challenges was ensuring the trading agents act proactively at regular intervals without a user having to take action. Crypto markets never sleep, so my trading agent needed to wake up periodically, analyze data, and make decisions continuously. Temporal’s Schedules feature turned out to be perfect for this. Instead of writing custom cron jobs or sleep loops, I defined a Temporal Schedule that triggers a “nudge” Workflow every few seconds to prompt the execution agent to analyze the portfolio status and market data. This made the agent truly ambient — always running on a schedule managed durably by Temporal’s Server, not by ad-hoc timers in my code. This led to a powerful realization for me: LLM providers, like OpenAI & Anthropic, will provide the “brain” for ambient agents, but Temporal will provide the ever-beating heart that keeps the system running durably.

For example, I created a schedule called "ensemble-nudge" to run a Workflow every 25 seconds. In code it looks like this:

schedule = Schedule(
    action=ScheduleActionStartWorkflow(
        workflow=EnsembleNudgeWorkflow.run,
        id="ensemble-nudge-wf",
        task_queue="mcp-tools",
    ),
    spec=ScheduleSpec(intervals=[ScheduleIntervalSpec(every=timedelta(seconds=25))]),
)
await client.create_schedule("ensemble-nudge", schedule)

With a few lines, Temporal ensures a Workflow (EnsembleNudgeWorkflow) is started on that interval. This built-in scheduling freed me from managing threads or external cron services. If the Worker or process restarts, the schedule is still tracked by Temporal and will fire the next Workflow on time. Temporal Schedules thus made it easy to implement an always-on agent that reacts regularly without human intervention.

Signals & Queries: The language of inter-agent communication#

In a multi-agent system, the agents need to talk to each other. Temporal’s Signals and Queries became the backbone of communication between my agents’ Workflows. Each AI agent (broker, execution, judge) is implemented as a long-running Workflow that maintains state and waits for Signals. This is similar to an actor model: agents are always alive (durably so, thanks to Temporal) and react to incoming Signals/Events, and they expose Queries to fetch their internal state. I found this far cleaner and more reliable than building custom messaging or polling mechanisms.

@workflow.signal
def update_system_prompt(self, prompt: str) -> None:
    """Update the system prompt for the execution agent."""
    self.system_prompt = prompt
    workflow.logger.info(f"System prompt updated (length: {len(prompt)} chars)")

@workflow.query
def get_system_prompt(self) -> str:
    """Get the current system prompt."""
    return self.system_prompt

With these in place, the LLM-as-judge agent can dynamically tune the execution agent’s behavior. After each performance evaluation, the judge uses Temporal’s client API to get a handle to the execution agent’s Workflow (by ID) and send it a Signal with a new prompt.

For example, the judge agent code calls:

await handle.signal("update_system_prompt", improved_prompt)

This is done whenever it determines a prompt update is needed. This Signal delivery is asynchronous and reliable — Temporal ensures the Signal is delivered to the Workflow instance, even if the target Workflow is running on a different Worker or the process restarts. In my case, I could see the ExecutionAgentWorkflow received the prompt update and logged the change ("System prompt updated..." appears in the Workflow logs).

I also used Signals for other interactions: a “nudge” Signal triggers the execution agent Workflow to begin its analysis, and logging Signals are used to record decisions and actions in each agent’s log Workflow. Queries complement this by allowing an agent to pull data from another agent. For example, the judge agent queries the execution agent for its current system prompt, and the broker agent queries the ledger Workflow for recent portfolio status & transaction history. Signals and Queries gave me a simple, strongly ordered way for inter-agent communication without needing an external message bus. This decoupling via Temporal constructs kept each agent Workflow isolated yet cooperative.

Observability with Temporal UI: Watching agents in action#

When orchestrating multiple intelligent agents, understanding what happened when is crucial. Temporal’s Web UI became an invaluable tool for observing the system’s behavior in real time. Every agent and tool in my system runs as a Temporal Workflow, which means I have a timeline of each Workflow’s execution and Events accessible in the UI. This proved extremely helpful for debugging and trustworthiness: I could literally watch the agents’ interactions step by step. event-history-kevin For example, whenever the judge agent updated the execution agent’s prompt via a Signal, I could open the ExecutionAgentWorkflow in Temporal’s UI and see the Signal Event recorded at that timestamp. Right next to it, I’d see the log entry confirming the prompt change. Similarly, the schedule-triggered Workflows (the “nudges”) showed up as runs of the EnsembleNudgeWorkflow every 25 seconds, visible in the history. Having this chronological view made it easy to answer questions like: Did the execution agent receive the nudge on time? Did the judge agent run its evaluation cycle after 10 minutes as expected? I could trace all these events in one place.

The Temporal UI also gave me confidence in the system’s auditability. Each Workflow’s history is stored, so I have an exact record of every decision and action the agents took (with timestamps and inputs) — a critical requirement in financial systems. Instead of logging to scattered files, I relied on Temporal’s histories (and some custom Workflow logs) to inspect what the agents were doing. This observability was especially useful when the agents’ behavior became complex; being able to visualize their coordination in the UI helped me fine-tune the Schedules and Signal handling. In short, Temporal’s UI turned the black-box nature of AI agents into a glass box, where I could see and debug the internals of the multi-agent orchestration easily.

Orchestrating multiple agents with Temporal Workflows#

Coordinating several agents and services — ticker feeds, a trading agent, a performance judge, and more — can get complicated fast. Temporal simplified this by acting as the central orchestrator for all agent workflows. In my design, each major component is a separate Workflow (or set of Workflows) and Temporal manages their lifecycles and interactions. This yielded a system where agents can run truly 24×7 with resilience and clarity in how they interact.

As I mentioned above, the architecture consists of three primary agents: a broker agent (user interface Workflow), an execution agent (trading decisions Workflow), and a judge agent (LLM-as-judge evaluator Workflow), plus supporting Workflows for market data streaming, order execution, and an execution ledger. Temporal allowed these to be broken into modular Workflows that each handle their domain. The broker starts a market data subscription Workflow which streams data from Coinbase. The execution agent Workflow listens for “nudge” Signals (from the Schedule) and uses MCP tools as Workflows/Queries/Signals to fetch data and place orders. The judge Workflow wakes up periodically (or on demand) to analyze performance and then signals the execution agent with adjustments. All of this is orchestrated by Temporal in a single connected system.

The benefit was huge: continuous orchestration without downtime, and guaranteed state tracking. Temporal’s fault tolerance means if one agent Workflow or Activity fails, it can be retried or continued without bringing down the whole system. This was critical because crypto trading must not stop; Temporal gave me the building blocks to ensure the agents coordinate reliably around the clock. Additionally, because Temporal Workflows are deterministic and replayable, I gained deterministic audit trails of the agents’ decision processes — an important factor if I ever need to explain a trade or comply with regulations.

Orchestrating with Temporal also simplified the design: rather than writing complex multi-threaded code or managing distributed state, I let Temporal Workflows handle concurrency and state isolation. Each agent had its own Workflow “instance” (for example, an ExecutionAgentWorkflow with a well-known ID) and could maintain internal variables (like the current prompt or recent actions) in memory safely. Temporal’s single-responsibility Workflows made the multi-agent system easier to extend too. I can add another agent or tool by just creating a new Workflow and perhaps scheduling or signaling it, without touching the core loop of other agents. This modular orchestration on Temporal proved to be a robust way to manage a complex ensemble of AI components.

Temporal primitives as MCP tools: Durable actions for AI Agents#

One of the most powerful patterns I implemented was using Temporal primitives (Workflows, Signals, Queries) as the “tools” that the AI agents call to interact with the world. In the Model Context Protocol (MCP) framework I used, agents invoke tools like get_historical_ticks, place_order, get_portfolio_status, etc., to gather data or execute trades. Instead of these tools being simple functions or external APIs, I made each one a Temporal primitive under the hood. This marriage of MCP tools with Temporal brought significant reliability, observability, and scalability benefits.

For example, when the execution agent wants to execute a trade, it calls a place_mock_order tool. That tool is actually implemented as a Temporal Workflow (PlaceMockOrder) which wraps an Activity to simulate the trade fill. Here’s a glimpse of that Workflow code:

@workflow.defn
class PlaceMockOrder:
    @workflow.run
    async def run(self, intent: OrderIntent) -> Dict:
        logger.info("Placing mock order: %s", intent)
        result: Dict = await workflow.execute_activity(
            mock_fill,
            intent,
            schedule_to_close_timeout=timedelta(seconds=5),
            retry_policy=RetryPolicy(maximum_attempts=1),
        )
        return result

Every time the agent “places an order,” it’s invoking this Workflow. The use of Temporal here means the action is durable, and if the underlying Activity fails (say the exchange API is down, in a real scenario), Temporal can retry or timeout gracefully. In fact, every @mcp.tool() in the system is backed by a deterministic Temporal Workflow, which gives us automatic retries and full replay for audit/compliance out of the box. The AI agents’ tools became durable operations. I didn’t have to worry about inconsistent state if an agent’s tool call crashed midway — Temporal ensures either the whole Workflow completes or it doesn’t happen at all, and we can always inspect what happened from the history.

Using Temporal for tool implementations also kept the agent’s reasoning loop deterministic. The agent (an LLM) would decide on an action, call a tool, and receive the result — all that heavy lifting (fetching market data, logging a trade, etc.) was done inside a Temporal Workflow which is isolated from the agent’s prompt and handled by a Temporal Worker, keeping the MCP server’s load low. This maintains a clear separation: the MCP server shows what can be done, the LLM decides what to do, and Temporal Workflows handle how it’s done reliably. The result is an AI trading system that marries the flexibility of LLM-driven decision-making with the robustness of Temporal’s Workflow execution.

Real-time feedback routing#

In this multi-agent crypto trading system, the broker agent acts as a coordinator that relays human feedback to the appropriate specialist agent (either the execution or judge agent) without needing to interrupt their operation. The broker leverages an MCP tool called send_user_feedback for this purpose. When the broker receives a user’s feedback, it invokes this tool with a target parameter indicating which agent should get the message. Internally, the tool uses the target to fetch the corresponding Temporal Workflow handle and sends an asynchronous Signal to that agent’s Workflow. For example, if target_agent="execution", it grabs the execution agent’s Workflow ("execution-agent") and signals its add_user_feedback method with the feedback payload; if targeting the judge, it does the analogous call on the judge agent’s Workflow:

# Broker routes feedback by signaling the target agent's workflow
if target_agent.lower() == "execution":
    handle = client.get_workflow_handle("execution-agent")
    await handle.signal("add_user_feedback", feedback_data)
    # ... feedback sent to execution agent ...
elif target_agent.lower() == "judge":
    handle = client.get_workflow_handle("judge-agent")
    await handle.signal("add_user_feedback", feedback_data)
    # ... feedback sent to judge agent ...

This simple routing logic ensures the right agent receives the user’s note in real time. Because the broker uses Temporal Signals, the feedback delivery is fire-and-forget — it does not interrupt the agent’s ongoing Workflow. The broker agent merely acts as a messenger, letting the specialized agents handle the feedback when they are ready.

On the receiving end, both the execution and judge agents’ Workflows define an add_user_feedback Signal handler to record these incoming messages. In the ExecutionAgentWorkflow, for instance, add_user_feedback simply timestamps the feedback, assigns a unique ID, marks it unprocessed, and appends it to an internal list of feedback messages:

@workflow.signal
def add_user_feedback(self, feedback_data: Dict[str, Any]) -> None:
    """Add user feedback to be incorporated into the agent's conversation."""
    feedback_entry = {
        **self._get_timestamp(),
        "feedback_id": f"feedback_{len(self.user_feedback) + 1}",
        "message": feedback_data.get("message", ""),
        "source": feedback_data.get("source", "user"),
        "processed": False
    }
    self.user_feedback.append(feedback_entry)
    workflow.logger.info(f"User feedback received: {feedback_data.get('message', '')[:100]}...")

The JudgeAgentWorkflow implements the same pattern for its own feedback list (GitHub). Storing feedback in a queue with a processed=False flag allows the agent to defer processing until a convenient moment. The running agent (e.g., the execution agent’s loop) can periodically query its Workflow for any pending feedback (via a get_pending_feedback query) and incorporate those messages into its context. For example, the execution agent’s client checks for new feedback and injects it into the conversation as a special user message (e.g., prefixing with “[USER FEEDBACK]”), then marks it as processed. This design lets a human trader “nudge” or guide the agents on the fly — the feedback is delivered instantly and queued, to be digested by the agent without halting its autonomous flow. In short, the Broker’s feedback relay and the agents’ Signal handlers work together to enable real-time human guidance of the trading agents without any interruption to their Workflows.

Conclusion#

Building an always-on, multi-agent trading system with an AI and a human-in-the-loop taught me just how much a platform like Temporal can simplify complex automation. Here are the key takeaways from this project:

  • Proactive orchestration with Schedules — Agents can operate continuously without custom schedulers or external cron jobs.
  • Real-time communication with Signals and Queries — Agents can coordinate, share state, and accept human feedback seamlessly without pausing their loops.
  • Visibility with the Temporal UI — Every agent action, Signal, and update is captured in Workflow history, making the system transparent, debuggable, and auditable.
  • Reliability from Temporal’s core guarantees — Durable Execution, retries, and durable state tracking ensure the system runs 24×7 without drift or data loss.
  • Durability by implementing tools as Workflows — Every agent action is executed as a Temporal Workflow, giving audit trails and fault tolerance “for free.”
  • Extendability — Adding a new agent or tool is as simple as creating another Workflow. The modular architecture makes it straightforward to experiment, iterate, and grow the system.
  • Team-friendly design — Temporal enforces a clean separation of concerns: one engineer can focus on a single Workflow, develop and test it locally, and deploy it independently. This makes collaboration easy, even on a multi-agent system.

In the end, Temporal handled the timing, communication, reliability, and observability, freeing me to focus on the higher-level logic of the agents. That’s what made it possible to turn a set of experimental AI agents into a robust, proactive trading system — a pattern I expect to reuse in future projects where complex agents need dependable orchestration.

Temporal Cloud

Ready to see for yourself?

Sign up for Temporal Cloud today and get $1,000 in free credits.