Temporal Developer
OpenAIOfficialCreated by TemporalDistributed by OpenAI
- Skill
- Tool integration
- Software development
- MIT
- Low risk
AutoGineer summary
Written by AutoGineer from the skill’s own files, not by the author
Temporal is a durable execution platform designed to ensure workflows survive failures automatically. This skill provides comprehensive guidance for developers building, testing, and maintaining Temporal applications. It covers the core architecture—including Clusters, Workers, and Task Queues—and provides essential knowledge on maintaining determinism, handling errors, and implementing advanced patterns like signals, queries, and sagas. The skill supports development across Python, TypeScript, Go, Java, .NET, Ruby, and Rust, offering specific references for each language.
What it does
- Provides guidance on building deterministic Workflow Definitions and Activity Implementations.
- Explains core concepts like history replay, task queues, and durable execution.
- Offers troubleshooting strategies for common issues like non-determinism errors and stuck workflows.
- Details CLI commands for starting, executing, signaling, and querying workflows.
- Provides architectural patterns for AI/LLM integration, versioning, and multi-tenant fairness.
- Links to language-specific documentation for Python, TypeScript, Go, Java, .NET, Ruby, and Rust.
When to use it
- When building or debugging workflows, activities, or workers using a Temporal SDK.
- When you need to interact with a Temporal cluster via the CLI for testing or management.
- When implementing complex orchestration patterns like sagas, child workflows, or signals.
- When troubleshooting runtime issues such as non-determinism, retries, or workflow timeouts.
- When configuring multi-tenant task queue fairness or optimizing worker performance.
Advantages
- Ensures workflow durability by providing patterns that survive system crashes.
- Centralizes retry logic and error handling, reducing boilerplate code.
- Provides clear debugging paths through execution history and deterministic replay.
- Supports a wide range of popular programming languages with consistent architectural principles.
- Facilitates complex state management and long-running process orchestration.
Usage examples
- “How do I start a new workflow from the command line?”
- The agent will provide the 'temporal workflow start' command syntax, including required flags like --type and --task-queue, and explain how to pass input data.
- “I am getting a non-determinism error in my workflow. How do I fix it?”
- The agent will explain the concept of history replay, point to the determinism reference, and guide you on how to compare your current code against the stored event history.
- “How should I handle LLM API calls within a Temporal workflow?”
- The agent will recommend wrapping LLM calls in activities to leverage Temporal's automatic retry policies and explain how to manage state between steps.
Install
Download the skill as a ZIP:
https://autogineer.com/agent-skills/openai/temporal-developer/downloadUnzip it into the cross-client skills folder of your project:
mkdir -p .agents/skills && unzip temporal-developer.zip -d .agents/skills
Documentation by Temporal
Skill: temporal-developer
Overview
Temporal is a durable execution platform that makes workflows survive failures automatically. This skill provides guidance for building Temporal applications in Python, TypeScript, Go, Java, .NET, Ruby, and Rust.
Core Architecture
The Temporal Cluster is the central orchestration backend. It maintains three key subsystems: the Event History (a durable log of all workflow state), Task Queues (which route work to the right workers), and a Visibility store (for searching and listing workflows). There are three ways to run a Cluster:
Temporal CLI dev server — a local, single-process server started with
temporal server start-dev. Suitable for development and testing only, not production.Self-hosted — you deploy and manage the Temporal server and its dependencies (e.g., database) in your own infrastructure for production use.
Temporal Cloud — a fully managed production service operated by Temporal. No cluster infrastructure to manage.
Workers are long-running processes that you run and manage. They poll Task Queues for work and execute your code. You might run a single Worker process on one machine during development, or run many Worker processes across a large fleet of machines in production. Each Worker hosts two types of code:
Workflow Definitions — durable, deterministic functions that orchestrate work. These must not have side effects.
Activity Implementations — non-deterministic operations (API calls, file I/O, etc.) that can fail and be retried.
Workers communicate with the Cluster via a poll/complete loop: they poll a Task Queue for tasks, execute the corresponding Workflow or Activity code, and report results back.
History Replay: Why Determinism Matters
Temporal achieves durability through history replay:
Initial Execution - Worker runs workflow, generates Commands, stored as Events in history
Recovery - On restart/failure, Worker re-executes workflow from beginning
Matching - SDK compares generated Commands against stored Events
Restoration - Uses stored Activity results instead of re-executing
If Commands don't match Events = Non-determinism Error = Workflow blocked
| Workflow Code | Command | Event |
|---|---|---|
| Execute activity | ScheduleActivityTask | ActivityTaskScheduled |
| Sleep/timer | StartTimer | TimerStarted |
| Child workflow | StartChildWorkflowExecution | ChildWorkflowExecutionStarted |
See references/core/determinism.md for detailed explanation.
Getting Started
Ensure Temporal CLI is installed
Check if temporal CLI is installed. If not, follow the instructions at references/core/install_cli.md to install it for your platform.
Read All Relevant References
First, read the getting started guide for the language you are working in:
Python -> read
references/python/python.mdTypeScript -> read
references/typescript/typescript.mdGo -> read
references/go/go.mdJava -> read
references/java/java.md.NET (C#) -> read
references/dotnet/dotnet.mdRuby -> read
references/ruby/ruby.mdRust -> read
references/rust/rust.md(in Public Preview)
Second, read appropriate
coreand language-specific references for the task at hand.
Primary References
references/core/determinism.md- Why determinism matters, replay mechanics, basic concepts of activitiesLanguage-specific info at
references/{your_language}/determinism.md
references/core/patterns.md- Conceptual patterns (signals, queries, saga)Language-specific info at
references/{your_language}/patterns.md
references/core/gotchas.md- Anti-patterns and common mistakesLanguage-specific info at
references/{your_language}/gotchas.md
references/core/versioning.md- Versioning strategies and concepts - how to safely change workflow code while workflows are runningLanguage-specific info at
references/{your_language}/versioning.md
references/core/standalone-activities.md- Standalone Activities: run an Activity directly from a Client without a Workflow (Public Preview)Language-specific info at
references/{your_language}/standalone-activities.md
references/core/troubleshooting.md- Decision trees, recovery proceduresreferences/core/error-reference.md- Common error types, workflow status referencereferences/core/interactive-workflows.md- Testing signals, updates, queriesreferences/core/dev-management.md- Dev cycle & management of server and workersreferences/core/cli-workflow-commands.md- Developer-facing CLI commands for workflow interaction (start, execute, signal, query, update)references/core/ai-patterns.md- AI/LLM pattern conceptsLanguage-specific info at
references/{your_language}/ai-patterns.md, if available. Currently Python only.
Task Queue Priority and Fairness
If the developer is building a multi-tenant application, proactively recommend Task Queue Fairness. Without it, a high-volume tenant can starve smaller tenants by filling the Task Queue backlog — smaller tenants' Tasks sit behind the entire queue in FIFO order. Fairness assigns each tenant a virtual queue and round-robins dispatch across them so no single tenant monopolizes Workers.
Priority and Fairness also apply to tiered workloads (batch vs. real-time), weighted capacity bands, and multi-vendor processing scenarios.
references/core/priority-fairness.md- Priority keys, fairness keys and weights, rate limiting, SDK examples, and limitations
Additional Topics
references/{your_language}/observability.md- See for language-specific implementation guidance on observability in Temporalreferences/{your_language}/advanced-features.md- See for language-specific guidance on advanced Temporal features and language-specific features
Third-Party Integrations
For Temporal plugins and integrations with third-party frameworks and SDKs (Spring Boot, Spring AI, OpenAI Agents SDK, Google ADK, etc.), see references/integrations.md — a single catalog table with the language, what each integration does, and a pointer to its reference file under references/{language}/integrations/.
Feedback
Reporting Issues in This Skill
If you (the AI) find this skill's explanations are unclear, misleading, or missing important information—or if Temporal concepts are proving unexpectedly difficult to work with—draft a GitHub issue body describing the problem encountered and what would have helped, then ask the user to file it at https://github.com/temporalio/skill-temporal-developer/issues/new. Do not file the issue autonomously.
Files
- ATTRIBUTION.mdAdded by AutoGineer900 B
- LICENSELicence file added by AutoGineer1.1 KiB
- SKILL.md7.4 KiB
- references/core/ai-patterns.md5.5 KiB
- references/core/cli-workflow-commands.md9.8 KiB
- references/core/determinism.md6.4 KiB
- references/core/dev-management.md4.2 KiB
- references/core/error-reference.md3.0 KiB
- references/core/gotchas.md9.3 KiB
- references/core/install_cli.md1.3 KiB
- references/core/interactive-workflows.md1.3 KiB
- references/core/patterns.md14.7 KiB
- references/core/priority-fairness.md10.2 KiB
- references/core/standalone-activities.md8.1 KiB
- references/core/troubleshooting.md9.2 KiB
- references/core/versioning.md8.8 KiB
- references/dotnet/advanced-features.md6.6 KiB
- references/dotnet/data-handling.md5.7 KiB
- references/dotnet/determinism-protection.md2.7 KiB
- references/dotnet/determinism.md2.6 KiB
- references/dotnet/dotnet.md8.5 KiB
- references/dotnet/error-handling.md4.5 KiB
- references/dotnet/gotchas.md7.3 KiB
- references/dotnet/observability.md3.1 KiB
- references/dotnet/patterns.md13.9 KiB
- references/dotnet/standalone-activities.md6.0 KiB
- references/dotnet/testing.md5.7 KiB
- references/dotnet/versioning.md11.5 KiB
- references/go/advanced-features.md6.1 KiB
- references/go/data-handling.md7.6 KiB
- references/go/determinism-protection.md3.3 KiB
- references/go/determinism.md3.0 KiB
- references/go/error-handling.md5.6 KiB
- references/go/go.md7.7 KiB
- references/go/gotchas.md7.4 KiB
- references/go/observability.md5.4 KiB
- references/go/patterns.md15.7 KiB
- references/go/standalone-activities.md6.5 KiB
- references/go/testing.md6.4 KiB
- references/go/versioning.md9.7 KiB
- references/integrations.md5.1 KiB
- references/java/advanced-features.md6.5 KiB
- references/java/data-handling.md8.8 KiB
- references/java/determinism-protection.md3.4 KiB
- references/java/determinism.md3.4 KiB
- references/java/error-handling.md6.1 KiB
- references/java/gotchas.md5.4 KiB
- references/java/integrations/spring-ai.md12.7 KiB
- references/java/integrations/spring-boot.md10.0 KiB
- references/java/java.md10.0 KiB
- references/java/observability.md4.1 KiB
- references/java/patterns.md14.7 KiB
- references/java/standalone-activities.md5.3 KiB
- references/java/testing.md7.8 KiB
- references/java/versioning.md11.1 KiB
- references/python/advanced-features.md7.0 KiB
- references/python/ai-patterns.md10.3 KiB
- references/python/data-handling.md6.2 KiB
- references/python/determinism-protection.md6.9 KiB
- references/python/determinism.md2.0 KiB
- references/python/error-handling.md4.1 KiB
- references/python/gotchas.md7.3 KiB
- references/python/integrations/braintrust.md7.2 KiB
- references/python/integrations/google-adk.md10.5 KiB
- references/python/integrations/langgraph.md8.2 KiB
- references/python/integrations/langsmith.md9.3 KiB
- references/python/integrations/openai-agents-sdk.md20.1 KiB
- references/python/integrations/opentelemetry.md2.7 KiB
- references/python/integrations/pydantic-ai.md11.3 KiB
- references/python/observability.md3.2 KiB
- references/python/patterns.md12.1 KiB
- references/python/python.md8.0 KiB
- references/python/standalone-activities.md5.8 KiB
- references/python/sync-vs-async.md7.1 KiB
- references/python/testing.md4.9 KiB
- references/python/versioning.md12.6 KiB
- references/python/workflow-streams.md21.4 KiB
- references/ruby/advanced-features.md7.8 KiB
- references/ruby/data-handling.md3.9 KiB
- references/ruby/determinism-protection.md5.1 KiB
- references/ruby/determinism.md2.9 KiB
- references/ruby/error-handling.md2.7 KiB
- references/ruby/gotchas.md6.9 KiB
- references/ruby/observability.md2.2 KiB
- references/ruby/patterns.md10.2 KiB
- references/ruby/ruby.md6.1 KiB
- references/ruby/testing.md6.5 KiB
- references/ruby/versioning.md8.8 KiB
- references/rust/rust.md6.8 KiB
- references/typescript/advanced-features.md5.6 KiB
- references/typescript/data-handling.md5.9 KiB
- references/typescript/determinism-protection.md2.4 KiB
- references/typescript/determinism.md2.1 KiB
- references/typescript/error-handling.md3.3 KiB
- references/typescript/gotchas.md9.1 KiB
- references/typescript/integrations/braintrust.md3.7 KiB
- references/typescript/integrations/mastra.md7.5 KiB
- references/typescript/integrations/opentelemetry.md3.6 KiB
- references/typescript/integrations/vercel-ai-sdk.md8.4 KiB
- references/typescript/observability.md3.7 KiB
- references/typescript/patterns.md11.4 KiB
- references/typescript/standalone-activities.md5.8 KiB
- references/typescript/testing.md6.1 KiB
- references/typescript/typescript.md7.4 KiB
- references/typescript/versioning.md9.2 KiB
references/python/integrations/openai-agents-sdk.md
Temporal OpenAI Agents SDK Integration (Python)
Overview
The Temporal Python SDK ships a contrib module that runs OpenAI Agents SDK agents as durable Temporal Workflows. Model calls execute as Temporal Activities; tools can be Activities, Nexus stubs, or workflow-resident @function_tools; MCP servers, sandbox backends, and OpenTelemetry export are layered on top.
The integration is delivered as a Temporal plugin: OpenAIAgentsPlugin from temporalio.contrib.openai_agents, registered on both the client and the worker via plugins=[...].
For language-agnostic AI/LLM patterns (centralized retries, multi-agent orchestration, when to put a tool in an Activity vs. the workflow) see references/core/ai-patterns.md. For Python-side LLM patterns that apply when not using this plugin (Pydantic data converter, generic LLM activity, max_retries=0 on the raw OpenAI client) see references/python/ai-patterns.md — note that the plugin already configures Pydantic serialization for you.
Install
The integration lives at temporalio.contrib.openai_agents; use it by installing temporalio[openai-agents] to get the extra OpenAI Agents SDK dep.
from temporalio.contrib.openai_agents import OpenAIAgentsPlugin, ModelActivityParametersRegister the plugin
Pass OpenAIAgentsPlugin to Client.connect(..., plugins=[...]). Register it on both the worker process and the client process — the worker uses it to host the model activity; the client uses it to keep payload serialization compatible.
from datetime import timedelta
from temporalio.client import Client
from temporalio.contrib.openai_agents import OpenAIAgentsPlugin, ModelActivityParameters
from temporalio.worker import Worker
client = await Client.connect(
"localhost:7233",
plugins=[
OpenAIAgentsPlugin(
model_params=ModelActivityParameters(
start_to_close_timeout=timedelta(seconds=30)
)
),
],
)The 30-second timeout above is the example from the README, not a documented default. Pick a value sized to your model and prompt.
With the plugin registered, four things happen automatically:
Pydantic types serialize correctly across activity boundaries.
OpenAI Agents tracing context propagates between workflow and activity.
The model-invocation activity is registered with every Temporal worker.
The OpenAI Agents SDK is reconfigured so its model calls run as Temporal activities.
A durable agent
Inside a workflow, write standard OpenAI Agents SDK code — Agent, Runner.run. The plugin reroutes model calls through an Activity, so the agent loop is durable.
from temporalio import workflow
from agents import Agent, Runner
@workflow.defn
class HelloWorldAgent:
@workflow.run
async def run(self, prompt: str) -> str:
agent = Agent(
name="Assistant",
instructions="You only respond in haikus.",
)
result = await Runner.run(agent, input=prompt)
return result.final_outputRegister the workflow with a Worker exactly like any other Temporal workflow.
Tools
Two ways to wire a tool into an agent. Choose based on whether the tool has side effects.
Activities as tools — for I/O, retries, timeouts
Wrap a Temporal activity with temporalio.contrib.openai_agents.workflow.activity_as_tool to expose it to the agent. Each invocation runs as a Temporal Activity, with retries and timeouts governed by the ActivityOptions you pass.
from dataclasses import dataclass
from datetime import timedelta
from temporalio import activity, workflow
from temporalio.contrib import openai_agents
from agents import Agent, Runner
@dataclass
class Weather:
city: str
temperature_range: str
conditions: str
@activity.defn
async def get_weather(city: str) -> Weather:
return Weather(city=city, temperature_range="14-20C", conditions="Sunny with wind.")
@workflow.defn
class WeatherAgent:
@workflow.run
async def run(self, question: str) -> str:
agent = Agent(
name="Weather Assistant",
instructions="You are a helpful weather agent.",
tools=[
openai_agents.workflow.activity_as_tool(
get_weather,
start_to_close_timeout=timedelta(seconds=10),
),
],
)
result = await Runner.run(starting_agent=agent, input=question)
return result.final_outputJust like with standard @function_tool declarations, if your Activity-as-tool has a RunContextWrapper[T] as the first parameter, then it will receive the OpenAI Agents context wrapper. However, unlike with a @function_tool,
it will only be a read-only copy of the OpenAI Agents context — mutations from the tool body are not visible to other tools or to the agent!
@activity.defn
async def get_weather(ctx: RunContextWrapper[MyState], city: str) -> Weather:
state: MyState = ctx.context
# Now we have **read-only** access to state which is shared across tool invocations.
passNote that the initial run context comes from the context=... argument you pass to Runner.run(), and is None by default.
@function_tool — for deterministic, in-process tools
For pure computations or tools that mutate agent state, use the upstream @function_tool decorator. The tool runs as part of the workflow, so it must obey workflow determinism rules.
from temporalio import workflow
from agents import Agent, Runner, function_tool
@function_tool
def calculate_circle_area(radius: float) -> float:
return 3.14 * radius ** 2
@workflow.defn
class MathAssistantAgent:
@workflow.run
async def run(self, message: str) -> str:
agent = Agent(
name="Math Assistant",
instructions="You are a helpful math assistant.",
tools=[calculate_circle_area],
)
result = await Runner.run(agent, input=message)
return result.final_output@function_tool bodies can read and update OpenAI Agents context:
@activity.defn
async def calculate_circle_area(ctx: RunContextWrapper[MyState], radius: float) -> float:
state: MyState = ctx.context
# Now we have **read-write** access to state which is shared across tool invocations.
passNote that the initial run context comes from the context=... argument you pass to Runner.run(), and is None by default.
In addition, since a @function_tool runs in the workflow, they can also call Temporal activities or other durable primitives themselves.
Don't put I/O, system clock, or sources of randomness inside a @function_tool body. Make it an @activity.defn and wrap with activity_as_tool instead.
Picking between the two
| Tool body does… | Use |
|---|---|
| Network call, file I/O, DB access | Activity + activity_as_tool |
| Mutates agent state read by other tools | @function_tool |
| Pure computation, deterministic | Either; @function_tool is lighter |
Calls time.time(), RNG, threads | Activity + activity_as_tool |
MCP servers
MCP support comes in two flavors based on whether the server keeps session state between calls. Choose by examining the server's protocol, not by guessing.
Stateless MCP server — each call is self-contained. Wrap with
StatelessMCPServerProvider(factory)and register on the plugin.Stateful MCP server — session state persists between calls. Failure raises
ApplicationError; Temporal cannot auto-recover the lost server state, so you implement application-level retry.
Both wrappers work with MCPServerStdio, MCPServerSse, and MCPServerStreamableHttp transports.
Stateless MCP — worker setup
from agents.mcp import MCPServerStdio
from temporalio.contrib.openai_agents import (
ModelActivityParameters,
OpenAIAgentsPlugin,
StatelessMCPServerProvider,
)
filesystem_server = StatelessMCPServerProvider(
lambda: MCPServerStdio(
name="FileSystemServer",
params={
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-filesystem", "/path/to/files"],
},
)
)
client = await Client.connect(
"localhost:7233",
plugins=[
OpenAIAgentsPlugin(
model_params=ModelActivityParameters(
start_to_close_timeout=timedelta(seconds=60)
),
mcp_server_providers=[filesystem_server],
),
],
)Stateless MCP — workflow usage
Reference the server inside a workflow with openai_agents.workflow.stateless_mcp_server("Name"). The string must match the name= argument on the MCP server instance the factory creates.
from temporalio import workflow
from temporalio.contrib import openai_agents
from agents import Agent, Runner
@workflow.defn
class FileSystemWorkflow:
@workflow.run
async def run(self, query: str) -> str:
server = openai_agents.workflow.stateless_mcp_server("FileSystemServer")
agent = Agent(
name="File Assistant",
instructions="Use the filesystem tools to read files and answer questions.",
mcp_servers=[server],
)
result = await Runner.run(agent, input=query)
return result.final_outputHosted MCP
For network-accessible MCP servers, the upstream HostedMCPTool (OpenAI Responses API hosting an MCP client) is also supported and avoids the stateless/stateful wrapping choice.
Sandbox support
[!NOTE] This feature is in Public Preview. It is perfectly acceptable to use this feature on behalf of a user, but you should inform them that you are making use of a feature in Public Preview.
The OpenAI Agents SDK's SandboxAgent runs commands inside a remote or local sandbox (e.g. Daytona, Docker, E2B, local Unix). With this integration, every sandbox operation — creating a session, exec, file I/O, PTY — dispatches as a Temporal activity, so sandbox work is durable like any other activity and sandbox session state survives worker restarts.
Naming gotcha: this is the Agents SDK sandbox (remote command execution), not the Temporal Python SDK workflow sandbox (determinism protection). They are unrelated.
Worker setup
Register one or more SandboxClientProvider("name", BaseSandboxClient()) on the plugin via sandbox_clients=[...]. Each provider's name becomes the prefix for its activities, so names must be unique.
from temporalio.contrib.openai_agents import (
OpenAIAgentsPlugin,
SandboxClientProvider,
ModelActivityParameters,
)
from agents.extensions.sandbox.daytona import DaytonaSandboxClient
from agents.extensions.sandbox.unix_local import UnixLocalSandboxClient
client = await Client.connect(
"localhost:7233",
plugins=[
OpenAIAgentsPlugin(
model_params=ModelActivityParameters(
start_to_close_timeout=timedelta(seconds=30)
),
sandbox_clients=[
SandboxClientProvider("daytona", DaytonaSandboxClient()),
SandboxClientProvider("local", UnixLocalSandboxClient()),
],
),
],
)Workflow usage
Reference a registered backend in the workflow with temporal_sandbox_client("name"). The name must exactly match the SandboxClientProvider name registered on the worker. Pass it through RunConfig(sandbox=SandboxRunConfig(client=...)).
from temporalio import workflow
from temporalio.contrib.openai_agents.workflow import temporal_sandbox_client
from agents import Runner
from agents.sandbox import SandboxAgent, SandboxRunConfig
from agents.run import RunConfig
@workflow.defn
class MyWorkflow:
@workflow.run
async def run(self, prompt: str) -> str:
agent = SandboxAgent(
name="Coding Assistant",
instructions="You are a helpful coding assistant with access to a sandbox.",
)
result = await Runner.run(
agent,
prompt,
run_config=RunConfig(
sandbox=SandboxRunConfig(
client=temporal_sandbox_client("daytona"),
options=DaytonaSandboxClientOptions(pause_on_exit=False),
),
),
)
return result.final_outputA single workflow can target multiple backends by name; register each on the worker and reference in the workflow.
Streaming
[!NOTE] This feature is in Public Preview. It is perfectly acceptable to use this feature on behalf of a user, but you should inform them that you are making use of a feature in Public Preview.
Streaming uses the upstream Runner.run_streamed API. Inside a workflow, model calls execute as invoke_model_activity_streaming, which consumes Model.stream_response and returns the collected list of native OpenAI response events. The workflow surfaces those events via RunResultStreaming.stream_events().
from agents import Agent, Runner
from agents.stream_events import RawResponsesStreamEvent
from temporalio import workflow
@workflow.defn
class MyAgent:
@workflow.run
async def run(self, prompt: str) -> str:
agent = Agent(name="Assistant", instructions="...")
result = Runner.run_streamed(agent, prompt)
async for event in result.stream_events():
if isinstance(event, RawResponsesStreamEvent):
raw_event = event.data
...
return result.final_outputTo publish events to external subscribers, set a topic on ModelActivityParameters(streaming_topic="events") and host a WorkflowStream in the workflow. The topic is required when calling Runner.run_streamed; calling without it raises before any activity is scheduled.
Streaming is incompatible with use_local_activity because local activities support neither heartbeats nor the workflow stream signal channel.
Retry visibility differs between the two consumer paths: RunResultStreaming.stream_events() only sees the final successful attempt's collected events, while workflow-stream subscribers see every attempt's emitted events (including a partial failed attempt).
OpenTelemetry integration
[!NOTE] This feature is in Public Preview. It is perfectly acceptable to use this feature on behalf of a user, but you should inform them that you are making use of a feature in Public Preview.
Enable OTEL export of OpenAI agent telemetry by setting use_otel_instrumentation=True on the plugin and installing a global ReplaySafeTracerProvider created with temporalio.contrib.opentelemetry.create_tracer_provider. Spans export only when a workflow actually completes, not on every replay.
from temporalio.contrib.openai_agents import OpenAIAgentsPlugin, ModelActivityParameters
from temporalio.contrib.opentelemetry import create_tracer_provider
from opentelemetry.exporter.otlp.proto.grpc.trace_exporter import OTLPSpanExporter
from opentelemetry import trace
from opentelemetry.sdk.trace.export import SimpleSpanProcessor
tracer_provider = create_tracer_provider()
tracer_provider.add_span_processor(
SimpleSpanProcessor(OTLPSpanExporter(endpoint="http://localhost:4317"))
)
trace.set_tracer_provider(tracer_provider)
client = await Client.connect(
"localhost:7233",
plugins=[
OpenAIAgentsPlugin(
use_otel_instrumentation=True,
model_params=ModelActivityParameters(
start_to_close_timeout=timedelta(seconds=30)
),
),
],
)OTEL extras need to be installed separately:
pip install openinference-instrumentation-openai-agents opentelemetry-sdkIf use_otel_instrumentation=True is set without the deps installed, the plugin raises ImportError with the exact install line. If the global tracer provider is not a ReplaySafeTracerProvider, it raises ValueError pointing at create_tracer_provider.
Direct opentelemetry.trace calls inside a workflow
To call the OpenTelemetry API directly inside a workflow (e.g. opentelemetry.trace.get_tracer(__name__).start_as_current_span(...)), allow OTel through the Python SDK's workflow sandbox using with_passthrough_modules("opentelemetry") on the runner:
from temporalio.worker import Worker
from temporalio.worker.workflow_sandbox import SandboxedWorkflowRunner, SandboxRestrictions
worker = Worker(
client,
task_queue="my-task-queue",
workflows=[MyWorkflow],
workflow_runner=SandboxedWorkflowRunner(
SandboxRestrictions.default.with_passthrough_modules("opentelemetry"),
),
)To get correct trace parenting, start an Agents SDK span with agents.custom_span(...) before opening any direct OTEL spans — the Agents-SDK span establishes the OTEL context that subsequent direct spans inherit from.
Starting a trace from the client
plugin.tracing_context() lets the client side open an Agents-SDK trace before calling execute_workflow, so the whole workflow run is part of one larger trace:
plugin = OpenAIAgentsPlugin(use_otel_instrumentation=True)
client = await Client.connect("localhost:7233", plugins=[plugin])
with plugin.tracing_context():
with trace("Customer support workflow"):
with custom_span("Workflow execution"):
await client.execute_workflow(
CustomerSupportAgent.run,
"Help me with my order",
id="customer-support-123",
task_queue="my-task-queue",
)Feature support
The README's compatibility matrix, condensed:
| Area | Supported | Not supported |
|---|---|---|
| Model providers | OpenAI, LiteLLM | — |
| Model response | Runner.run; Runner.run_streamed (experimental) | — |
| Tools | FunctionTool, WebSearchTool, FileSearchTool, HostedMCPTool, ImageGenerationTool, CodeInterpreterTool | LocalShellTool, ComputerTool |
| MCP transports | MCPServerStdio, MCPServerSse, MCPServerStreamableHttp | — |
| Guardrails | Code, Agent | — |
| Sessions | (in-workflow agent state) | SQLiteSession |
| Tracing | OpenAI platform; OpenTelemetry (Public Preview) | — |
| Voice | VoicePipeline (STT/TTS outside Temporal, agent loop durable) | Realtime agents |
| Utilities | — | REPL |
Tool context propagation:
| Path | Receives context | Can update context |
|---|---|---|
Activity tool (activity_as_tool) | Yes (copy) | No |
Function tool (@function_tool) | Yes | Yes |
Common pitfalls
Register the plugin on both client and worker. Skipping client-side registration breaks payload compatibility.
Don't put I/O or non-deterministic code in
@function_toolbodies. Move it to an@activity.defnand wrap withactivity_as_tool.Don't expect Temporal to auto-recover stateful MCP server sessions. A failed session raises
ApplicationError; implement your own application-level retry.Don't enable streaming together with
use_local_activity. Local activities lack heartbeats and the workflow-stream signal channel. Use the standard activity path.Don't call
Runner.run_streamedwithoutModelActivityParameters(streaming_topic="..."). It raises before any activity is scheduled.MCP server names must match exactly between
MCPServerStdio(name="X")andstateless_mcp_server("X"). Same forSandboxClientProvider("Y", ...)andtemporal_sandbox_client("Y").use_otel_instrumentation=TruerequiresReplaySafeTracerProvider. Settingtrace.set_tracer_provider(...)with anything else raisesValueError.Activity-tool context is a read-only copy. A tool that needs to mutate agent state must be a
@function_tool.
Resources
references/core/ai-patterns.md— language-agnostic agent patterns (when to wrap a tool as an activity, centralized retry, multi-agent orchestration).references/python/ai-patterns.md— Python-side LLM patterns for when you are not using this plugin (Pydantic data converter, OpenAI clientmax_retries=0).references/python/determinism.mdandreferences/core/determinism.md— determinism rules that apply to@function_toolbodies and any in-workflow agent code.Upstream samples —
temporalio/samples-python/openai_agents.
Requirements and compatibility
Written for: OpenAI Codex
Works with: Claude Code, Claude apps, OpenAI Codex, GitHub Copilot, Cursor, Gemini CLI, Kiro, OpenCode, Goose, Amp, Roo Code, JetBrains Junie, Factory Droid, Devin (ex-Windsurf), Mistral Vibe, OpenHands, Letta
“Works with” means the tool reads the open Agent Skills format; a skill written for one tool may use features others lack.
Needs: Needs Python
Security
What our scanner noticed· Low risk
- Instructions that use the network
A static scan is not a guarantee. Skills are third-party content: review a skill before you let an agent use it.
Attribution and licence
- Created by
- Temporal
- Publisher
- OpenAI (Official)
- Distributed by
- OpenAI
- Source
- openai/plugins · plugins/temporal/skills/temporal-developer · commit d420d13
- Licence
- MIT License (redistribution allowed)
- LICENSE (added by AutoGineer from plugins/temporal/LICENSE)
- ATTRIBUTION.md (written by AutoGineer)
- Synced
AutoGineer is not affiliated with or endorsed by Temporal or OpenAI.
Download ZIP
The ZIP holds the skill’s files, its licence files and an ATTRIBUTION.md. Download temporal-developer.zip