> ## Documentation Index
> Fetch the complete documentation index at: https://hastekit.ai/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Temporal

Durable agent execution ensures that your agents can survive process crashes, restarts, or failures without losing progress. Using [Temporal](https://temporal.io), each step of the agent's execution (LLM calls, tool executions) is checkpointed, allowing the agent to resume from exactly where it left off after a failure.

## Why Durable Execution?

Traditional agents run in-memory. If your process crashes during:

* A long-running LLM call
* An external API request in a tool
* A multi-step conversation with many tool calls

...all progress is lost, and the entire execution must restart from scratch.

With durable execution:

* **Checkpoint Every Step**: Each LLM call and tool execution is automatically saved
* **Automatic Recovery**: After a crash, the agent resumes from the last checkpoint
* **Exactly-Once Guarantees**: Tool executions are never duplicated, even after retries
* **Long-Running Workflows**: Agents can run for hours or days without risk

## Prerequisites

1. **Temporal Server**: You need a running Temporal server. Follow the [Temporal installation guide](https://docs.temporal.io/self-hosted-guide/quick-start) to set one up.

2. **Redis Server**: Temporal agents require Redis for streaming support. Install and run Redis locally or use a hosted Redis service.

## Creating a Durable Agent

To make an agent durable with Temporal, create a Temporal runtime with `hastekit.NewTemporalRuntime` and attach it to the agent with `hastekit.WithRuntime`:

```go theme={null}
package main

import (
    "log"
    "net/http"
    "os"

    hastekit "github.com/hastekit/hastekit-sdk-go"
)

func main() {
    client := hastekit.NewLLMClient([]hastekit.ProviderConfig{
        {
            ProviderName: hastekit.ProviderOpenAI,
            ApiKeys: []*hastekit.APIKeyConfig{
                {
                    Name:   "Key 1",
                    APIKey: os.Getenv("OPENAI_API_KEY"),
                },
            },
        },
    })

    model := client.Model("OpenAI/gpt-4o-mini")

    // Create a Temporal runtime: (Temporal server endpoint, Redis endpoint)
    rt, err := hastekit.NewTemporalRuntime("0.0.0.0:7233", "localhost:6379")
    if err != nil {
        log.Fatal(err)
    }

    broker, err := hastekit.NewRedisStreamBroker("localhost:6379")
    if err != nil {
        log.Fatal(err)
    }

    // Create a durable agent by attaching the runtime
    agentName := "SampleAgent"
    agent := hastekit.NewAgent(&hastekit.AgentConfig{
        Name:        agentName,
        Instruction: hastekit.NewPrompt("You are helpful assistant."),
        LLM:         model,
        History:     hastekit.NewFileHistory("./conversations"),
    }, hastekit.WithRuntime(rt, broker))
}
```

## Deployment Options

There are two ways to deploy durable agents:

### Option 1: Single Process (Development/Testing)

Run both the Temporal worker and the application code in the same process. This is simpler but less resilient since both components share the same process lifecycle.

```go theme={null}
func main() {
    // ... client, runtime, and agent setup from above ...

    // Start the Temporal worker in a goroutine
    rt.Start()

    // Start HTTP server for invoking the workflow
    http.ListenAndServe(":8070", hastekit.NewHTTPHandler())
}
```

With this setup:

* The Temporal worker connects to the Temporal server at `0.0.0.0:7233`
* Your application server runs on `http://localhost:8070`
* Both are in the same process

**Note**: If this process crashes, both components restart together. True durability requires separation (Option 2).

### Option 2: Separate Processes (Production)

For production deployments, run the Temporal worker and application in separate processes. This provides true fault isolation—if your application crashes, the Temporal worker continues running and can recover the workflow.

#### Application Process

```go theme={null}
// application/main.go
package main

import (
    "log"
    "net/http"
    "os"

    hastekit "github.com/hastekit/hastekit-sdk-go"
)

func main() {
    client := hastekit.NewLLMClient([]hastekit.ProviderConfig{
        {
            ProviderName: hastekit.ProviderOpenAI,
            ApiKeys: []*hastekit.APIKeyConfig{
                {
                    Name:   "Key 1",
                    APIKey: os.Getenv("OPENAI_API_KEY"),
                },
            },
        },
    })

    model := client.Model("OpenAI/gpt-4o-mini")

    rt, err := hastekit.NewTemporalRuntime("0.0.0.0:7233", "localhost:6379")
    if err != nil {
        log.Fatal(err)
    }
    broker, err := hastekit.NewRedisStreamBroker("localhost:6379")
    if err != nil {
        log.Fatal(err)
    }

    // Register the agent with the runtime attached (but don't start the worker here)
    agentName := "my-agent"
    _ = hastekit.NewAgent(&hastekit.AgentConfig{
        Name:        agentName,
        Instruction: hastekit.NewPrompt("You are a helpful assistant."),
        LLM:         model,
        History:     hastekit.NewFileHistory("./conversations"),
    }, hastekit.WithRuntime(rt, broker))

    // Start application server (no Temporal worker here)
    log.Println("Application server starting on :8070")
    http.ListenAndServe(":8070", hastekit.NewHTTPHandler())
}
```

#### Temporal Worker Process

```go theme={null}
// temporal-worker/main.go
package main

import (
    "log"
    "os"

    hastekit "github.com/hastekit/hastekit-sdk-go"
)

func main() {
    client := hastekit.NewLLMClient([]hastekit.ProviderConfig{
        {
            ProviderName: hastekit.ProviderOpenAI,
            ApiKeys: []*hastekit.APIKeyConfig{
                {
                    Name:   "Key 1",
                    APIKey: os.Getenv("OPENAI_API_KEY"),
                },
            },
        },
    })

    model := client.Model("OpenAI/gpt-4o-mini")

    rt, err := hastekit.NewTemporalRuntime("0.0.0.0:7233", "localhost:6379")
    if err != nil {
        log.Fatal(err)
    }
    broker, err := hastekit.NewRedisStreamBroker("localhost:6379")
    if err != nil {
        log.Fatal(err)
    }

    // Register the SAME agent with the SAME configuration
    agentName := "my-agent"
    _ = hastekit.NewAgent(&hastekit.AgentConfig{
        Name:        agentName,
        Instruction: hastekit.NewPrompt("You are a helpful assistant."),
        LLM:         model,
        History:     hastekit.NewFileHistory("./conversations"),
    }, hastekit.WithRuntime(rt, broker))

    // Start only the Temporal worker
    log.Println("Temporal worker starting...")
    rt.Start()

    // Block forever (worker runs in background goroutine)
    select {}
}
```

**Important**: Both processes must register the agent with the **exact same name and configuration**. This ensures the Temporal worker can execute the agent with the correct setup.

#### Running the Services

```bash theme={null}
# Terminal 1: Start the Temporal worker
cd temporal-worker
go run main.go

# Terminal 2: Start the application
cd application
go run main.go
```

## Starting the Temporal Server

If you don't have a Temporal server running, you can start one locally using Docker:

```bash theme={null}
# Using Temporal CLI (recommended for development)
temporal server start-dev

# Or using Docker Compose
git clone https://github.com/temporalio/docker-compose.git
cd docker-compose
docker compose up
```

The Temporal server will be available at:

* **gRPC endpoint**: `localhost:7233` (for workers and clients)
* **Web UI**: `http://localhost:8233` (for monitoring workflows)

## Starting Redis

Redis is required for streaming support in Temporal agents:

```bash theme={null}
# Using Docker
docker run -d --name redis -p 6379:6379 redis

# Or using Homebrew on macOS
brew install redis
brew services start redis
```

## Example: Complete Durable Agent

See the complete working example in the repository: [`examples/agents/9_temporal_agent/main.go`](https://github.com/hastekit/hastekit-docs/blob/master/examples/agents/9_temporal_agent/main.go)

## Learn More

* [Temporal Documentation](https://docs.temporal.io)
* [Temporal Go SDK](https://docs.temporal.io/dev-guide/go)
* [Temporal Self-Hosted Guide](https://docs.temporal.io/self-hosted-guide)
* [Temporal Web UI](https://docs.temporal.io/web-ui)
