Skip to main content
The problem: Your API or UI process needs to submit agent runs and stream results to users — but you don’t want it to also host the Temporal worker that executes LLM calls and tools. Mixing both in one process couples your UI latency to compute load, limits independent scaling, and makes deploys riskier. The solution: Split the agent client (submits runs, handles streaming and approvals in your API) and the worker (polls the task queue and executes everything else) into separate processes. Workers are stateless — Temporal holds all state — so you can scale them independently, deploy them separately, and restart them without losing in-flight runs.

Architecture

ProcessRole
Agent (NewAgent + DisableLocalWorker)Starts Run, Stream, RunAsync; handles approvals in your UI
Worker (NewAgentWorker)Polls the task queue; executes LLM calls, tools, memory, and approvals as Temporal activities
TemporalDurable workflow history — survives crashes and deploys
See Temporal runtime for the full architecture diagram.

Setup

Worker process — polls the task queue and executes runs:
w, err := agent.NewAgentWorker(
    agent.WithTemporalConfig(&agent.TemporalConfig{
        Host: "localhost", Port: 7233,
        Namespace: "default", TaskQueue: "my-app",
    }),
    agent.WithLLMClient(llmClient),
    agent.WithSystemPrompt("You are a helpful assistant."),
)
if err != nil {
    log.Fatal(err)
}

go func() {
    if err := w.Start(ctx); err != nil {
        log.Fatal(err)
    }
}()

// On shutdown:
// w.Stop()
Agent process — starts runs without polling:
a, err := agent.NewAgent(
    agent.WithTemporalConfig(&agent.TemporalConfig{
        Host: "localhost", Port: 7233,
        Namespace: "default", TaskQueue: "my-app",
    }),
    agent.WithLLMClient(llmClient),
    agent.WithSystemPrompt("You are a helpful assistant."),
    agent.DisableLocalWorker(),
)
if err != nil {
    log.Fatal(err)
}
defer a.Close()

result, err := a.Run(ctx, "Hello", nil)
NewAgentWorker requires Temporal — it cannot run with the in-process runtime alone.

Configuration alignment

Both processes must share identical agent configuration:
Must matchWhy
Task queue and namespaceWorker polls what the client submits to
WithInstanceId (if set)Derives {TaskQueue}-{InstanceId} on both sides
LLM client, system prompt, toolsFingerprint check at activity entry
Tool approval policy and execution modeSame approval semantics
MCP, A2A, sub-agent setupSame tool surface for the LLM
Conversation backendRedis (not in-memory) for remote workers
Memory configSame store and scope settings
Hook group namesFingerprint includes hook group names
Observability configSame OTLP endpoint on both processes
The SDK uses a fingerprint check to detect config drift between the client that started a run and the worker that executes it. Mismatches fail the run with a clear error. WithDisableFingerprintCheck bypasses the check on the agent process only — not allowed on NewAgentWorker. Use as break-glass only.

Remote workers for streaming and approvals

When using DisableLocalWorker with streaming or approvals across processes, also pass EnableRemoteWorkers() on the agent:
a, _ := agent.NewAgent(
    agent.WithTemporalConfig(cfg),
    agent.WithLLMClient(llmClient),
    agent.DisableLocalWorker(),
    agent.EnableRemoteWorkers(),
    agent.WithStream(true),
)
This starts Temporal’s remote event path for out-of-process event delivery.

Distributed conversation and memory

In-memory conversation fails at build time with remote workers. Use Redis or another distributed backend on both processes:
conv, _ := redis.NewRedisConversation(redis.WithAddr("localhost:6379"))
convCfg := conversation.Config{Conversation: conv, Size: 20, SaveOnIteration: true}

w, _ := agent.NewAgentWorker(/* ... */, agent.WithConversation(convCfg))
a, _ := agent.NewAgent(/* ... */, agent.DisableLocalWorker(), agent.WithConversation(convCfg))
See Conversation and Memory.

Sub-agents

Each sub-agent typically runs on its own task queue with its own worker. Pair NewAgentWorker with the same options as the NewAgent that runs that sub-agent. Example: Agent Worker · Durable Agent.

Example

Agent Worker

Minimal split client and worker

Temporal Runtime

Durable execution and fingerprint alignment

Multiple Agents

Task queues and instance IDs

Observability

OTLP on both agent and worker

Agent Modes

Interactive vs autonomous worker checks