This specification is maintained by the AgentRules Working Group. Have enhancements or want to claim maintainership?Submit Specification →
backendcritical PriorityID: temporal-go-workflow-determinism-replay-guardrails

Temporal Go SDK Workflow Determinism, Side-Effect Isolation, and Safe Replay Versioning

Enforces absolute determinism and side-effect isolation within Temporal Go workflow definitions to prevent NonDeterministicWorkflowError panics during event history replays. Mandates the use of Temporal-encapsulated primitives (workflow.Now, workflow.Sleep, workflow.Go, workflow.Channel) and strict change-management versioning via workflow.GetVersion across rolling cluster deployments.

Prohibited Anti-Pattern: Invoking Non-Deterministic Native Primitives and Mutating Orchestration Graph Without workflow.GetVersion Migration Barriers

Export Ready-to-Drop Configuration

Select format below to copy code or download file directly.

---
description: Temporal Go SDK Workflow Determinism, Side-Effect Isolation, and Safe Replay Versioning - Enforces absolute determinism and side-effect isolation within Temporal Go workflow definitions to prevent NonDeterministicWorkflowError panics during event history replays. Mandates the use of Temporal-encapsulated primitives (workflow.Now, workflow.Sleep, workflow.Go, workflow.Channel) and strict change-management versioning via workflow.GetVersion across rolling cluster deployments.
globs: **/workflow/*.go, **/workflows/**/*.go, **/*_workflow.go
alwaysApply: true
verified_by: "agentrules.org"
license: "CC-BY-4.0"
source: "https://agentrules.org/rules/temporal-go-workflow-determinism-replay-guardrails"
---

# Temporal Go SDK Workflow Determinism, Side-Effect Isolation, and Safe Replay Versioning

> **Severity**: CRITICAL | **Category**: backend
> **Anti-Pattern Warning**: Invoking Non-Deterministic Native Primitives and Mutating Orchestration Graph Without workflow.GetVersion Migration Barriers

## System Constraints
You are a Principal Distributed Systems Engineer enforcing Temporal Go SDK Workflow Determinism and Replay Guardrails. You must reject any workflow implementation that violates replay determinism, introduces direct side effects, utilizes raw Go concurrency or time APIs, iterates non-deterministically over Go maps, or modifies existing workflow execution graphs without explicit versioning fences.

## Strict Guidelines
- Engineers MUST NEVER invoke standard Go runtime time or randomness primitives (time.Now, time.Sleep, rand.Read, uuid.NewUUID) inside workflow definitions; use workflow.Now(ctx), workflow.Sleep(ctx, d), or delegate to an Activity or workflow.SideEffect.
- Engineers MUST NEVER spawn raw goroutines (`go func()`) or use native Go sync primitives (sync.Mutex, sync.WaitGroup, raw channels) inside workflows; use workflow.Go(ctx, ...), workflow.Channel, workflow.Selector, and workflow.Mutex instead.
- Engineers MUST NEVER execute direct network I/O, database queries, file system access, or IPC within a workflow function; all I/O must be encapsulated in Temporal Activities.
- Engineers MUST NEVER iterate over native Go maps to drive execution order, trigger sequential activities, or build execution graphs, because Go map iteration is randomized by the runtime and breaks replay history.
- Engineers MUST ALWAYS protect structural workflow graph mutations (adding, removing, or reordering Activities, Timers, or Child Workflows) using workflow.GetVersion to preserve compatibility with in-flight workflow histories.
- Engineers MUST NEVER remove obsolete version checks from workflow definitions until all open workflow executions started under historical versions have reached terminal states in production.
- Services MUST validate determinism by running temporal-sdk-go/testsuite Replayer tests against real exported production JSON workflow histories in automated CI pipelines.

## Bad vs Good Implementations
### Workflow Logic Modification and Side-Effect Isolation

#### Bad Antipattern (AI Common Hallucination)
> **Why it fails**: Directly invokes uuid.New(), time.Now(), and time.Sleep(), which yield completely different values on replay and corrupt the workflow state machine. Spawns an unmanaged Go goroutine, bypassing Temporal's cooperative scheduler. Introduces an unversioned Activity call (RunFraudCheckActivity), causing NonDeterministicWorkflowError during rolling deployment when existing executions replay against updated code.
```go
package workflows

import (
	"time"
	"github.com/google/uuid"
	"go.temporal.io/sdk/workflow"
)

func OrderFulfillmentWorkflow(ctx workflow.Context, orderID string) error {
	ao := workflow.ActivityOptions{
		StartToCloseTimeout: 10 * time.Second,
	}
	ctx = workflow.WithActivityOptions(ctx, ao)

	// VIOLATION: Native time and random UUID generation break replay determinism
	trackingID := uuid.New().String()
	createdAt := time.Now()

	// VIOLATION: Direct Go concurrency inside workflow
	go func() {
		println("Processing order:", orderID, trackingID, createdAt.String())
	}()

	// VIOLATION: Native sleep locks execution thread and corrupts event clock
	time.Sleep(5 * time.Second)

	// VIOLATION: Added new fraud check activity directly without workflow.GetVersion;
	// breaks deterministic replay of existing in-flight workflow histories
	var fraudResult bool
	err := workflow.ExecuteActivity(ctx, RunFraudCheckActivity, orderID).Get(ctx, &fraudResult)
	if err != nil {
		return err
	}

	return workflow.ExecuteActivity(ctx, ProcessPaymentActivity, orderID).Get(ctx, nil)
}
```

#### Production Standard (Correct)
> **Standard**: Replaces native UUID generation with workflow.SideEffect and uses workflow.Now() for replay-safe timestamps. Replaces native goroutine with workflow.Go and native sleep with workflow.Sleep. Safely gates the new Activity invocation using workflow.GetVersion, ensuring older in-flight executions run the InitialVersion branch without encountering non-determinism panics during rolling updates.
```go
package workflows

import (
	"time"
	"github.com/google/uuid"
	"go.temporal.io/sdk/workflow"
)

const (
	OrderFulfillmentVersionChangeID = "add-fraud-check-step"
	InitialVersion                  = workflow.DefaultVersion
	FraudCheckAddedVersion          = 1
)

func OrderFulfillmentWorkflow(ctx workflow.Context, orderID string) error {
	ao := workflow.ActivityOptions{
		StartToCloseTimeout: 10 * time.Second,
	}
	ctx = workflow.WithActivityOptions(ctx, ao)

	// FIX: Encapsulate non-deterministic generation in workflow.SideEffect
	var trackingID string
	encodedID := workflow.SideEffect(ctx, func(ctx workflow.Context) interface{} {
		return uuid.New().String()
	})
	if err := encodedID.Get(&trackingID); err != nil {
		return err
	}

	// FIX: Deterministic temporal time and coordinated logging
	createdAt := workflow.Now(ctx)
	logger := workflow.GetLogger(ctx)

	// FIX: Managed Temporal coroutine
	workflow.Go(ctx, func(gCtx workflow.Context) {
		logger.Info("Processing order", "orderID", orderID, "trackingID", trackingID, "createdAt", createdAt)
	})

	// FIX: Deterministic Temporal timer
	if err := workflow.Sleep(ctx, 5*time.Second); err != nil {
		return err
	}

	// FIX: Safely gate structural workflow modification with workflow.GetVersion
	version := workflow.GetVersion(ctx, OrderFulfillmentVersionChangeID, InitialVersion, FraudCheckAddedVersion)
	if version >= FraudCheckAddedVersion {
		var fraudResult bool
		err := workflow.ExecuteActivity(ctx, RunFraudCheckActivity, orderID).Get(ctx, &fraudResult)
		if err != nil {
			return err
		}
	}

	return workflow.ExecuteActivity(ctx, ProcessPaymentActivity, orderID).Get(ctx, nil)
}
```

Architectural Specification & Invariant Rationale

Architectural Invariant Design: Temporal Go SDK Workflow Determinism, Side-Effect Isolation, and Safe Replay Versioning

Temporal Go SDK Workflow Determinism, Side-Effect Isolation, and Safe Replay Versioning defines an industrial-grade behavioral standard for backend engineering. Enforces absolute determinism and side-effect isolation within Temporal Go workflow definitions to prevent NonDeterministicWorkflowError panics during event history replays. Mandates the use of Temporal-encapsulated primitives (workflow.Now, workflow.Sleep, workflow.Go, workflow.Channel) and strict change-management versioning via workflow.GetVersion across rolling cluster deployments. Modern software architectures require strict adherence to deterministic patterns to guarantee high availability, maintainability, and zero security vulnerabilities.

Framework Paradigm Shift & Drift MechanicsLLMs are trained on millions of open-source repositories containing outdated code, legacy idioms, and unpatched antipatterns. When coding assistants generate implementations for this stack, they default to common statistical tokens: Invoking Non-Deterministic Native Primitives and Mutating Orchestration Graph Without workflow.GetVersion Migration Barriers Without an explicit system instruction file, developers spend hours debugging silent failures.
Failure Modes & Production Blast Radius

Hazard Analysis: What Breaks Without This Rule

The following failure modes have been cataloged from hundreds of hours of production code reviews where AI assistants produced non-compliant implementations:

Failure ModeAI Symptom (The Anti-Pattern)SeverityProduction Impact & Remedy
AI Hallucination & Deprecation DriftInvoking Non-Deterministic Native Primitives and Mutating Orchestration Graph Without workflow.GetVersion Migration BarriersCritical
Violating this industrial standard introduces regression bugs, security risks, and unexpected runtime failures in production.
Enforce explicit behavioral system directives across all AI coding assistants in your repository.
Silent Architecture InconsistencyAI assistants produce mixed paradigms across files, creating fragmented codebase conventions.Medium
Increases cognitive load during code reviews and leads to maintenance debt across engineering teams.
Pin project conventions in .cursor/rules, CLAUDE.md, and AGENTS.md so all team agents follow identical guardrails.
Architectural Directives in Detail

Step-by-Step Production Directives

Each rule constraint below is injected into the AI agent's system prompt to establish deterministic boundaries:

1

Engineers MUST NEVER invoke standard Go runtime time or randomness primitives (time.Now, time.Sleep, rand.Read, uuid.NewUUID) inside workflow definitions

Engineers MUST NEVER invoke standard Go runtime time or randomness primitives (time.Now, time.Sleep, rand.Read, uuid.NewUUID) inside workflow definitions; use workflow.Now(ctx), workflow.Sleep(ctx, d), or delegate to an Activity or workflow.SideEffect.

Rationale:AI models frequently generate unconstrained code here because statistical language distributions lack project-specific architectural context. Mandating this directive ensures that generated code adheres to verified industrial production requirements.
Enforcement:Integrated into the Agent Pack rule file. When Cursor, Claude Code, or Codex processes this prompt, it applies this constraint before emitting syntax.
2

Engineers MUST NEVER spawn raw goroutines (`go func()`) or use native Go sync primitives (sync.Mutex, sync.WaitGroup, raw channels) inside workflows

Engineers MUST NEVER spawn raw goroutines (`go func()`) or use native Go sync primitives (sync.Mutex, sync.WaitGroup, raw channels) inside workflows; use workflow.Go(ctx, ...), workflow.Channel, workflow.Selector, and workflow.Mutex instead.

Rationale:AI models frequently generate unconstrained code here because statistical language distributions lack project-specific architectural context. Mandating this directive ensures that generated code adheres to verified industrial production requirements.
Enforcement:Integrated into the Agent Pack rule file. When Cursor, Claude Code, or Codex processes this prompt, it applies this constraint before emitting syntax.
3

Engineers MUST NEVER execute direct network I/O, database queries, file system access, or IPC within a workflow function

Engineers MUST NEVER execute direct network I/O, database queries, file system access, or IPC within a workflow function; all I/O must be encapsulated in Temporal Activities.

Rationale:AI models frequently generate unconstrained code here because statistical language distributions lack project-specific architectural context. Mandating this directive ensures that generated code adheres to verified industrial production requirements.
Enforcement:Integrated into the Agent Pack rule file. When Cursor, Claude Code, or Codex processes this prompt, it applies this constraint before emitting syntax.
4

Engineers MUST NEVER iterate over native Go maps to drive execution order, trigger sequential activities, or build execution graphs, because Go map iteration is randomized by the runtime and breaks replay history.

Engineers MUST NEVER iterate over native Go maps to drive execution order, trigger sequential activities, or build execution graphs, because Go map iteration is randomized by the runtime and breaks replay history.

Rationale:AI models frequently generate unconstrained code here because statistical language distributions lack project-specific architectural context. Mandating this directive ensures that generated code adheres to verified industrial production requirements.
Enforcement:Integrated into the Agent Pack rule file. When Cursor, Claude Code, or Codex processes this prompt, it applies this constraint before emitting syntax.
5

Engineers MUST ALWAYS protect structural workflow graph mutations (adding, removing, or reordering Activities, Timers, or Child Workflows) using workflow.GetVersion to preserve compatibility with in-flight workflow histories.

Engineers MUST ALWAYS protect structural workflow graph mutations (adding, removing, or reordering Activities, Timers, or Child Workflows) using workflow.GetVersion to preserve compatibility with in-flight workflow histories.

Rationale:AI models frequently generate unconstrained code here because statistical language distributions lack project-specific architectural context. Mandating this directive ensures that generated code adheres to verified industrial production requirements.
Enforcement:Integrated into the Agent Pack rule file. When Cursor, Claude Code, or Codex processes this prompt, it applies this constraint before emitting syntax.
6

Engineers MUST NEVER remove obsolete version checks from workflow definitions until all open workflow executions started under historical versions have reached terminal states in production.

Engineers MUST NEVER remove obsolete version checks from workflow definitions until all open workflow executions started under historical versions have reached terminal states in production.

Rationale:AI models frequently generate unconstrained code here because statistical language distributions lack project-specific architectural context. Mandating this directive ensures that generated code adheres to verified industrial production requirements.
Enforcement:Integrated into the Agent Pack rule file. When Cursor, Claude Code, or Codex processes this prompt, it applies this constraint before emitting syntax.
7

Services MUST validate determinism by running temporal-sdk-go/testsuite Replayer tests against real exported production JSON workflow histories in automated CI pipelines.

Services MUST validate determinism by running temporal-sdk-go/testsuite Replayer tests against real exported production JSON workflow histories in automated CI pipelines.

Rationale:AI models frequently generate unconstrained code here because statistical language distributions lack project-specific architectural context. Mandating this directive ensures that generated code adheres to verified industrial production requirements.
Enforcement:Integrated into the Agent Pack rule file. When Cursor, Claude Code, or Codex processes this prompt, it applies this constraint before emitting syntax.
Technical Questions & Answers

Frequently Asked Technical Questions

Common questions developers face when configuring AI coding assistants for this stack:

Q:Why is Temporal Go SDK Workflow Determinism, Side-Effect Isolation, and Safe Replay Versioning critical for AI coding assistants?

Enforces absolute determinism and side-effect isolation within Temporal Go workflow definitions to prevent NonDeterministicWorkflowError panics during event history replays. Mandates the use of Temporal-encapsulated primitives (workflow.Now, workflow.Sleep, workflow.Go, workflow.Channel) and strict change-management versioning via workflow.GetVersion across rolling cluster deployments. Without explicit behavioral boundaries, AI coding assistants (Cursor, Claude Code, Windsurf, Codex) rely on training data averages, which frequently produce deprecated, inefficient, or vulnerable code patterns.

Q:How does adopting this rule prevent AI hallucinations?

This rule explicitly declares what the AI must avoid (Invoking Non-Deterministic Native Primitives and Mutating Orchestration Graph Without workflow.GetVersion Migration Barriers) and prescribes verified positive examples. Grounding the LLM with negative and positive pairs eliminates guesswork.

Q:Which AI coding environments are supported?

This specification is multi-platform compatible: Cursor (.cursor/rules/*.mdc & .cursorrules), Anthropic Claude Code (CLAUDE.md), Windsurf (.windsurfrules), Codex / Cline (AGENTS.md), and GitHub Copilot (.github/copilot-instructions.md).

Q:Can I combine this rule with other technology stacks?

Yes. Use the Interactive Stack Builder or download an Agent Pack to merge this rule with other frontend, backend, database, security, and DevOps rules without syntax collision.

Open Specification · CC BY 4.0·Free for Personal, Team & Commercial In-Repo Use

Citation & Open Source Attribution Guidelines

This specification is licensed under Creative Commons Attribution 4.0 International (CC BY 4.0). You are completely free to adapt and share this rule in your workspace. If citing, including in public AI benchmark datasets, or redistributing, attribution to AgentRules.org is required.

1 Rule in Stack

Temporal