Durable execution framework for AI agents in Go. Keeps agent state, tool calls, and execution loops resilient across process crashes.
See the codeBuild durable Go AI agents that pick up right where they left off.
Open-source Go SDK for building durable AI agents. Runs in-process with crash-resilient execution via durable-go with zero setup, or switch to Temporal / Restate for crash-resilient, distributed execution. Every core component is a pluggable interface, so you're never locked in.
📖 Documentation · Quickstart · Examples
Releases follow Semantic Versioning; see the latest release.
Independent community library — not affiliated with Temporal Technologies or Restate.
interfaces.LLMClientWith*ExecutionConfiggo get github.com/agenticenv/agent-sdk-go@latest
Go 1.26+. Agents are durable by default, no infrastructure required. Add a Temporal or Restate server only when you want distributed, multi-process execution — see temporal-setup.md and restate-setup.md.
In-process (zero setup):
import (
"context"
"fmt"
"time"
"github.com/agenticenv/agent-sdk-go/pkg/agent"
"github.com/agenticenv/agent-sdk-go/pkg/llm"
"github.com/agenticenv/agent-sdk-go/pkg/llm/openai"
)
// errors omitted for brevity
llmClient, _ := openai.NewClient(
llm.WithAPIKey("sk-..."),
llm.WithModel("gpt-4o"),
)
a, _ := agent.NewAgent(
agent.WithSystemPrompt("You are a helpful assistant."),
agent.WithLLMClient(llmClient),
// Durable by default (journals to ./agent_data/<agent_name>). To tune the journal or opt
// out, import "github.com/agenticenv/agent-sdk-go/pkg/agent/runtime/local" and add:
// local.WithLocalConfig(&local.LocalConfig{
// DataDir: "./agent_data/my-agent", // default: "./agent_data/<agent_name>"
// AutoPurgeAge: 24 * time.Hour, // default: 7 days
// Timeout: 2 * time.Minute, // default: none — bound long-running/stuck runs
// Durability: local.DurabilityOff(), // or opt out entirely — pure in-memory, no journal
// }),
)
defer a.Close()
// --- Run ---
run, _ := a.Run(context.Background(), "Reply with a short greeting.", nil)
result, _ := run.Get(context.Background())
fmt.Println(result.Content)
// --- Non-blocking ---
run, _ = a.Run(context.Background(), "Explain durable agents in two short paragraphs.", nil)
select {
case <-run.Done():
result, _ = run.Get(context.Background())
fmt.Println(result.Content)
case <-time.After(5 * time.Second):
fmt.Println("still running, check back later")
}
// --- Stream (AG-UI events: text deltas, tools, approvals, lifecycle, …) ---
stream, _ := a.Stream(context.Background(), "Write a four-line poem about the ocean.", nil)
events, _ := stream.Events(context.Background())
for event := range events {
switch e := event.(type) {
case *agent.AgentTextMessageContentEvent:
fmt.Print(e.Delta)
case *agent.AgentToolCallStartEvent:
fmt.Println("\n[tool call]", e.ToolCallName)
case *agent.AgentCustomEvent:
// tool / delegation approval (when approval policy requires it)
if e.Name == string(agent.AgentCustomEventNameToolApproval) {
if v, err := agent.ParseCustomEventApproval(e); err == nil {
// replace with real approval logic — this auto-approves for demonstration
_ = stream.Approve(context.Background(), v.ApprovalToken, agent.ApprovalStatusApproved)
}
}
// also RunFinished, ToolCallResult, …
}
}
Temporal (distributed execution) — import pkg/agent/runtime/temporal:
import "github.com/agenticenv/agent-sdk-go/pkg/agent/runtime/temporal"
a, _ := agent.NewAgent(
agent.WithSystemPrompt("You are a helpful assistant."),
agent.WithLLMClient(llmClient),
temporal.WithTemporalConfig(&temporal.TemporalConfig{
Host: "localhost",
Port: 7233,
Namespace: "default",
TaskQueue: "agent-task-queue",
}),
)
defer a.Close()
// --- Run ---
run, _ := a.Run(context.Background(), "Reply with a short greeting.", nil)
result, _ := run.Get(context.Background())
fmt.Println(result.Content)
// --- Stream + reconnect ---
stream, _ := a.Stream(context.Background(), "Write a four-line poem about the ocean.", nil)
savedRunID := stream.ID() // persist before consuming events
events, _ := stream.Events(context.Background())
for event := range events {
// persist event.Offset() before handling — needed for WithOffset on reconnect
_ = event
}
savedOffset := int64(0)
s, _ := a.GetAgentStream(context.Background(), savedRunID)
ch, _ := s.Events(context.Background(), agent.WithOffset(savedOffset))
for event := range ch {
_ = event
}
Restate (durable execution) — import pkg/agent/runtime/restate (mutually exclusive with Temporal):
import "github.com/agenticenv/agent-sdk-go/pkg/agent/runtime/restate"
a, _ := agent.NewAgent(
agent.WithSystemPrompt("You are a helpful assistant."),
agent.WithLLMClient(llmClient),
restate.WithRestateConfig(&restate.RestateConfig{
Ingress: restate.IngressConfig{
URL: "http://localhost:8080",
},
Endpoint: restate.EndpointConfig{
ListenAddress: ":9080",
AdminURL: "http://localhost:9070",
},
}),
)
defer a.Close()
// Same Run / Stream / GetAgentStream + WithOffset APIs as Temporal
Crashes and process restarts don't have to mean lost work or missed approvals — see durable_agent/local (single process, zero infrastructure), durable_agent/temporal (split worker), and durable_agent/restate (single process). For the stream reconnect protocol (
GetAgentStream+WithOffset), see the reconnect example and Durable Execution. Local has noWithOffset(n>0)— only replay from the start, with completed steps coalesced into one message each (step granularity), not the original token-by-token stream.
agctl)Download a binary from GitHub Releases, extract it, and put agctl on your PATH.
export AGCTL_LLM_APIKEY=sk-your-key
agctl run --model gpt-4o --prompt "hello"
# or interactive
agctl chat
See the CLI docs for commands, config, and env vars.

Runnable examples in examples/ — see examples/README.md for setup and run instructions.
Config-driven benchmark runner — see benchmarks/README.md
Evaluate agent quality with Promptfoo and DeepEval — locally or in CI. See eval-harness/README.md
See CONTRIBUTING.md for setup, workflow, and guidelines. Project policies: SECURITY.md · CODE_OF_CONDUCT.md
Quick commands (requires Task): task check | task test | task lint | task fmt | task tidy | task test-coverage
Coverage reports (PR and default branch) are on Codecov. Run task test-coverage locally to produce coverage.out and coverage.html.
This project is provided "as is" under the Apache License 2.0. When building AI agents that execute real-world actions, ensure appropriate safeguards, validation, and human-in-the-loop approval workflows are in place. You are responsible for compliance, access control, and operational safety in your deployment. For security issues, follow SECURITY.md.
54 followers · starred Jun 2026
Go
99.7%
Durable execution framework for AI agents in Go. Keeps agent state, tool calls, and execution loops resilient across process crashes.
See the codeBuild durable Go AI agents that pick up right where they left off.
Open-source Go SDK for building durable AI agents. Runs in-process with crash-resilient execution via durable-go with zero setup, or switch to Temporal / Restate for crash-resilient, distributed execution. Every core component is a pluggable interface, so you're never locked in.
📖 Documentation · Quickstart · Examples
Releases follow Semantic Versioning; see the latest release.
Independent community library — not affiliated with Temporal Technologies or Restate.
interfaces.LLMClientWith*ExecutionConfiggo get github.com/agenticenv/agent-sdk-go@latest
Go 1.26+. Agents are durable by default, no infrastructure required. Add a Temporal or Restate server only when you want distributed, multi-process execution — see temporal-setup.md and restate-setup.md.
In-process (zero setup):
import (
"context"
"fmt"
"time"
"github.com/agenticenv/agent-sdk-go/pkg/agent"
"github.com/agenticenv/agent-sdk-go/pkg/llm"
"github.com/agenticenv/agent-sdk-go/pkg/llm/openai"
)
// errors omitted for brevity
llmClient, _ := openai.NewClient(
llm.WithAPIKey("sk-..."),
llm.WithModel("gpt-4o"),
)
a, _ := agent.NewAgent(
agent.WithSystemPrompt("You are a helpful assistant."),
agent.WithLLMClient(llmClient),
// Durable by default (journals to ./agent_data/<agent_name>). To tune the journal or opt
// out, import "github.com/agenticenv/agent-sdk-go/pkg/agent/runtime/local" and add:
// local.WithLocalConfig(&local.LocalConfig{
// DataDir: "./agent_data/my-agent", // default: "./agent_data/<agent_name>"
// AutoPurgeAge: 24 * time.Hour, // default: 7 days
// Timeout: 2 * time.Minute, // default: none — bound long-running/stuck runs
// Durability: local.DurabilityOff(), // or opt out entirely — pure in-memory, no journal
// }),
)
defer a.Close()
// --- Run ---
run, _ := a.Run(context.Background(), "Reply with a short greeting.", nil)
result, _ := run.Get(context.Background())
fmt.Println(result.Content)
// --- Non-blocking ---
run, _ = a.Run(context.Background(), "Explain durable agents in two short paragraphs.", nil)
select {
case <-run.Done():
result, _ = run.Get(context.Background())
fmt.Println(result.Content)
case <-time.After(5 * time.Second):
fmt.Println("still running, check back later")
}
// --- Stream (AG-UI events: text deltas, tools, approvals, lifecycle, …) ---
stream, _ := a.Stream(context.Background(), "Write a four-line poem about the ocean.", nil)
events, _ := stream.Events(context.Background())
for event := range events {
switch e := event.(type) {
case *agent.AgentTextMessageContentEvent:
fmt.Print(e.Delta)
case *agent.AgentToolCallStartEvent:
fmt.Println("\n[tool call]", e.ToolCallName)
case *agent.AgentCustomEvent:
// tool / delegation approval (when approval policy requires it)
if e.Name == string(agent.AgentCustomEventNameToolApproval) {
if v, err := agent.ParseCustomEventApproval(e); err == nil {
// replace with real approval logic — this auto-approves for demonstration
_ = stream.Approve(context.Background(), v.ApprovalToken, agent.ApprovalStatusApproved)
}
}
// also RunFinished, ToolCallResult, …
}
}
Temporal (distributed execution) — import pkg/agent/runtime/temporal:
import "github.com/agenticenv/agent-sdk-go/pkg/agent/runtime/temporal"
a, _ := agent.NewAgent(
agent.WithSystemPrompt("You are a helpful assistant."),
agent.WithLLMClient(llmClient),
temporal.WithTemporalConfig(&temporal.TemporalConfig{
Host: "localhost",
Port: 7233,
Namespace: "default",
TaskQueue: "agent-task-queue",
}),
)
defer a.Close()
// --- Run ---
run, _ := a.Run(context.Background(), "Reply with a short greeting.", nil)
result, _ := run.Get(context.Background())
fmt.Println(result.Content)
// --- Stream + reconnect ---
stream, _ := a.Stream(context.Background(), "Write a four-line poem about the ocean.", nil)
savedRunID := stream.ID() // persist before consuming events
events, _ := stream.Events(context.Background())
for event := range events {
// persist event.Offset() before handling — needed for WithOffset on reconnect
_ = event
}
savedOffset := int64(0)
s, _ := a.GetAgentStream(context.Background(), savedRunID)
ch, _ := s.Events(context.Background(), agent.WithOffset(savedOffset))
for event := range ch {
_ = event
}
Restate (durable execution) — import pkg/agent/runtime/restate (mutually exclusive with Temporal):
import "github.com/agenticenv/agent-sdk-go/pkg/agent/runtime/restate"
a, _ := agent.NewAgent(
agent.WithSystemPrompt("You are a helpful assistant."),
agent.WithLLMClient(llmClient),
restate.WithRestateConfig(&restate.RestateConfig{
Ingress: restate.IngressConfig{
URL: "http://localhost:8080",
},
Endpoint: restate.EndpointConfig{
ListenAddress: ":9080",
AdminURL: "http://localhost:9070",
},
}),
)
defer a.Close()
// Same Run / Stream / GetAgentStream + WithOffset APIs as Temporal
Crashes and process restarts don't have to mean lost work or missed approvals — see durable_agent/local (single process, zero infrastructure), durable_agent/temporal (split worker), and durable_agent/restate (single process). For the stream reconnect protocol (
GetAgentStream+WithOffset), see the reconnect example and Durable Execution. Local has noWithOffset(n>0)— only replay from the start, with completed steps coalesced into one message each (step granularity), not the original token-by-token stream.
agctl)Download a binary from GitHub Releases, extract it, and put agctl on your PATH.
export AGCTL_LLM_APIKEY=sk-your-key
agctl run --model gpt-4o --prompt "hello"
# or interactive
agctl chat
See the CLI docs for commands, config, and env vars.

Runnable examples in examples/ — see examples/README.md for setup and run instructions.
Config-driven benchmark runner — see benchmarks/README.md
Evaluate agent quality with Promptfoo and DeepEval — locally or in CI. See eval-harness/README.md
See CONTRIBUTING.md for setup, workflow, and guidelines. Project policies: SECURITY.md · CODE_OF_CONDUCT.md
Quick commands (requires Task): task check | task test | task lint | task fmt | task tidy | task test-coverage
Coverage reports (PR and default branch) are on Codecov. Run task test-coverage locally to produce coverage.out and coverage.html.
This project is provided "as is" under the Apache License 2.0. When building AI agents that execute real-world actions, ensure appropriate safeguards, validation, and human-in-the-loop approval workflows are in place. You are responsible for compliance, access control, and operational safety in your deployment. For security issues, follow SECURITY.md.
54 followers · starred Jun 2026
Go
99.7%