Build durable, composable AI agents on Temporal using Python or TypeScript and the AI SDKs you already use.
Experimental. APIs change between releases. Pin versions and upgrade deliberately.
temporal-agent-harness-explainer-github.mp4
An agent is a Temporal workflow. The harness gives it typed messages, tools, streaming, and human interaction so you can focus on the agent's behavior.
- Durable execution: recover workflow state after worker restarts; retry model and activity calls by policy.
- Human approval: pause tool calls for decisions and resume when they arrive.
- Composition: connect agents through typed inputs, outputs, and observable state.
- Code Mode: let the model orchestrate tools and subagents with sandboxed code.
- Product interfaces: inspect runs in the console or build a typed React/Svelte application.
Both SDKs turn a typed message handler into a durable Temporal workflow. These agents use the OpenAI Agents SDK, stream replies, and keep conversation history across messages and worker restarts. The worker's harness and model plugins handle the Temporal integration.
from temporalio import workflow
from temporalio.contrib.workflow_streams import WorkflowStream
with workflow.unsafe.imports_passed_through():
from agents import Agent, Runner, TResponseInputItem
from temporal_agent_harness.harness import AgentWorkflowRunner, agent
from temporal_agent_harness.harness.agent_protocol import AgentConfig, TextMessage, TextReply
@agent.defn
class ChatAgent:
@agent.init
def __init__(self, config: AgentConfig) -> None:
self.runner = AgentWorkflowRunner(config, stream=WorkflowStream())
self.history: list[TResponseInputItem] = []
@agent.accepts
async def ask(self, message: TextMessage) -> TextReply:
"""Chat with the assistant."""
result = Runner.run_streamed(
Agent(name="Assistant", instructions="Answer briefly.", model="gpt-5.1"),
input=[*self.history, {"role": "user", "content": message.text}],
context=self.runner,
)
async for _event in result.stream_events():
pass
self.history = result.to_input_list()
return TextReply(text=str(result.final_output))import { Agent, type AgentInputItem } from "@openai/agents-core";
import { defineAgent, handler, TextMessage, TextReply } from "@temporalio/agent-harness";
import { runStreamed } from "@temporalio/agent-harness/ai-sdks/openai-agents-harness";
export const ChatAgent = defineAgent({
name: "ChatAgent",
handlers: {
ask: handler({ description: "Chat with the assistant.", input: TextMessage, output: TextReply }),
},
create: ({ runner }) => {
let history: AgentInputItem[] = [];
return {
async ask({ text }) {
const result = await runStreamed(
runner,
new Agent({ name: "Assistant", instructions: "Answer briefly.", model: "gpt-5.1" }),
[...history, { role: "user", content: text }],
{ defaultModelParams: { startToCloseTimeout: "2 minutes", heartbeatTimeout: "30 seconds" } },
);
for await (const _event of result) void _event;
await result.completed;
history = result.history;
return { text: String(result.finalOutput) };
},
};
},
});The quickstarts below provide complete projects with workers, registry configuration, and a sample weather tool. Add tools, approvals, and observable state, or define your own typed operations beyond chat. See the Python and TypeScript worker setup to run a custom agent definition.
| Start here | What you'll build |
|---|---|
| Python quickstart | A Python agent and worker, with the shared console |
| TypeScript quickstart | A TypeScript agent and worker, with the same console |
| Example agents | Run existing agents from a release checkout |
| Build with a coding agent | Install the SDK's versioned skill and starter |
The quickstarts'
init,skills,dev, anddoctorcommands ship with the next Python and npm releases; they are not in Python 0.8.0 / npm 0.2.0. The manual setup below works today.
To add the SDK to an existing project:
# Python
uv add 'temporal-agent-harness[ui]==0.9.0'
# TypeScript
npm install --save-exact @temporalio/agent-harness@0.3.1 @temporalio/agent-harness-worker@0.3.1The Python manual setup covers model integration extras and worker configuration; the TypeScript manual setup covers the complete compatible dependency set. No repository checkout is required for either.
flowchart LR
UI[Harness console or your application] --> API[Shared Python HTTP API]
API --> T[Temporal service]
M[Python session-manager worker] <--> T
W[Your Python or TypeScript agent worker] <--> T
The shared API, UI server, and session manager currently come from the Python package.
temporal-agent-harness dev agents.toml runs the API server and the session manager in one
process, so local development is three processes: Temporal, dev, and your agent worker.
TypeScript users run dev with uvx without creating a Python project. The npm SDK runs
TypeScript agents; it does not yet include a Node.js harness server.
The harness console is at localhost:8000. Temporal's own workflow UI is at localhost:8233 when using the local dev server. Both quickstarts explain which processes to start.
Each SDK ships a skill, focused references, and an OpenAI starter matching that SDK release. After installing the SDK, install its skill where your coding agents discover project skills:
uv run temporal-agent-harness skills install # Python
npx agent-harness skills install # TypeScriptEach asks which coding agents to install for: Claude Code, which reads .claude/skills
(--for claude), and Codex and other agents that read the shared .agents/skills directory
(--for agents). Choose both if you use both; pass --for to skip the question.
Then ask the agent to use it: /temporal-harness-python or /temporal-harness-typescript in
Claude Code, $temporal-harness-python or $temporal-harness-typescript in Codex. Tools with
another skill directory can install from the directory printed by skills path, or with
skills install --dest.
Package installation alone does not activate a skill.
Use temporal-agent-harness init ./my-agent or npx agent-harness init ./my-agent to copy a
starter. The commands create files without overwriting existing ones. Follow the generated
README to install dependencies, configure credentials, and start the application.
After upgrading an SDK, rerun skills install to update unchanged skill files. Local edits
produce a conflict instead of being overwritten. See coding-agent development.
| Topic | Guide |
|---|---|
| API, sessions, streaming, reconnects | Harness API |
| Tools, approvals, state, and composition | Capabilities |
| Handler schemas and mid-turn messages | Messages |
| Human approval and auto mode | Approvals |
| Code Mode, virtual files, and subagents | Code Mode |
| Typed application clients | React / Svelte |
| Embed the API/UI in your service | Self-hosting |
| Work on this repository | Contributing and development |
| Publish a release | Release guide |
The Python and npm SDKs have independent release versions. Keep the npm harness packages at
one harness version and use the underlying Temporal/model SDK versions documented by the
quickstart. Commit your dependency lockfile. Examples live in release checkouts, not in the SDK
packages; the small init starters are bundled separately.
Use the release notes when upgrading.
Links to moved sections
Former README sections now live in these guides:
- Capabilities: what you get, durable execution, standardized agents, your own UI, human in the loop, bring your own AI SDK, durable and inline tools, callback tools, agents beyond chatbots, composition, and Code Mode.
- Approvals: auto mode.
- Code Mode: Code Mode and OKF bundles.
- Messages: accepted messages and discovery.
- React / Svelte: build a UI in React or Svelte.
- Examples: requirements and running the examples, standalone or behind one UI.
- Self-hosting: self-hosting the web app.
- Python guide: the example agents, running the web UI, extras, a taste, running a worker, and closing idle agents.