claude-agent-sdk-go
[!WARNING]
Community-maintained Go SDK for the Claude Code CLI. Not an official Anthropic product. Anthropic publishes TypeScript and Python SDKs; this project provides the same interface in Go.
Go library for the Claude Code CLI. Stream messages, run multi-turn sessions, and wire Go functions as in-process MCP tools.
Install
go get github.com/bnema/claude-agent-sdk-go/pkg/sdk
Requires Go 1.23+ and the claude CLI on your PATH.
Quick start
sdk.Query runs a prompt and yields messages as the CLI produces them.
import "github.com/bnema/claude-agent-sdk-go/pkg/sdk"
for msg, err := range sdk.Query(ctx, "What is 2+2?", nil) {
if err != nil {
log.Fatal(err)
}
switch m := msg.(type) {
case *sdk.AssistantMessage:
for _, block := range m.Content {
if tb, ok := block.(*sdk.TextBlock); ok {
fmt.Println(tb.Text)
}
}
case *sdk.ResultMessage:
if m.TotalCostUSD != nil {
fmt.Printf("Cost: $%.4f\n", *m.TotalCostUSD)
}
}
}
Pass a *ClaudeCodeOptions to control the model, tools, permission mode, and more:
mode := sdk.PermissionAcceptEdits
maxTurns := 5
opts := &sdk.ClaudeCodeOptions{
SystemPrompt: "You are a helpful coding assistant.",
Model: "claude-opus-4-5",
PermissionMode: &mode,
MaxTurns: &maxTurns,
AllowedTools: []string{"Read", "Bash"},
}
for msg, err := range sdk.Query(ctx, "List the Go files here", opts) { ... }
Bidirectional client
Client keeps a CLI process open across multiple turns.
client := sdk.NewClient(&sdk.ClaudeCodeOptions{
Model: "claude-opus-4-5",
AllowedTools: []string{"Read", "Bash"},
})
defer client.Close()
if err := client.Connect(ctx, "List the files here"); err != nil {
log.Fatal(err)
}
// Drain the first response.
for msg, err := range client.Receive(ctx) {
if err != nil {
log.Fatal(err)
}
// handle msg ...
}
// Send a follow-up and read the next response.
if err := client.Send(ctx, "Now summarise main.go"); err != nil {
log.Fatal(err)
}
for msg, err := range client.Receive(ctx) { ... }
Receive stops after the ResultMessage for each turn. Call Send and Receive again for subsequent turns. ReceiveAll yields the full stream without stopping at turn boundaries.
Interrupt stops the current generation mid-stream.
Define Go functions as MCP tools. The CLI calls them without spawning a separate process. In-process tools require Client; they do not work with Query.
calc := sdk.NewTool(
"add",
"Add two numbers",
map[string]any{
"type": "object",
"properties": map[string]any{
"a": map[string]any{"type": "number"},
"b": map[string]any{"type": "number"},
},
"required": []string{"a", "b"},
},
func(ctx context.Context, input map[string]any) (*sdk.ToolResult, error) {
a := input["a"].(float64)
b := input["b"].(float64)
return sdk.TextResult(fmt.Sprintf("%g", a+b)), nil
},
)
server := sdk.NewSdkMcpServer("math", sdk.WithTools(calc))
client := sdk.NewClient(&sdk.ClaudeCodeOptions{
SdkMcpServers: map[string]*sdk.SdkMcpServer{"math": server},
})
Use sdk.TextResult(text) for text results and sdk.ErrorResult(msg) for errors.
Options reference
| Field |
Type |
Description |
AllowedTools |
[]string |
Tools Claude may call |
DisallowedTools |
[]string |
Tools Claude may not call |
SystemPrompt |
string |
Replace the system prompt |
AppendSystemPrompt |
string |
Append to the system prompt |
McpServers |
map[string]McpServerConfig |
External MCP servers |
SdkMcpServers |
map[string]*SdkMcpServer |
In-process MCP servers (Client only) |
PermissionMode |
*PermissionMode |
default, acceptEdits, plan, bypassPermissions |
ContinueConversation |
bool |
Resume the last session |
Resume |
string |
Resume a specific session by ID |
MaxTurns |
*int |
Stop after N turns |
MaxBudgetUSD |
*float64 |
Stop when cost exceeds this amount |
Model |
string |
Model name |
FallbackModel |
string |
Model to use if the primary is unavailable |
Effort |
string |
Effort level hint |
Cwd |
string |
Working directory for the CLI subprocess |
Env |
map[string]string |
Extra environment variables for the subprocess |
Bare |
bool |
Suppress the system prompt preamble |
NoSessionPersistence |
bool |
Disable session storage |
SessionID |
string |
Attach to or tag a specific session |
JSONSchema |
string |
Request output conforming to this JSON Schema |
IncludePartialMessages |
bool |
Stream intermediate assistant messages |
CanUseTool |
CanUseTool |
Callback to approve or deny each tool call |
Hooks |
map[HookEvent][]HookMatcher |
Lifecycle callbacks |
ExtraArgs |
map[string]string |
CLI flags not covered by named fields |
Permission modes
sdk.PermissionDefault // ask for each operation (default)
sdk.PermissionAcceptEdits // approve all file edits automatically
sdk.PermissionPlan // read-only planning mode
sdk.PermissionBypassPermissions // skip all permission checks
Hook events
Register callbacks for HookPreToolUse, HookPostToolUse, HookUserPromptSubmit, HookStop, HookSubagentStop, HookPreCompact, HookNotification, HookSessionStart, or HookSessionEnd.
Architecture
The library follows hexagonal architecture:
| Package |
Role |
pkg/sdk |
Public API — Query, NewClient, NewTool, NewSdkMcpServer |
pkg/domain |
Message types, content blocks, permissions, hooks — no external deps |
pkg/app |
Orchestration: streaming queries, control protocol handler |
pkg/ports |
Interfaces: Transport, Executor, McpServer |
pkg/adapters/subprocess |
Launches and communicates with the claude CLI process |
Import pkg/sdk for everything. Import pkg/domain only for types pkg/sdk does not re-export.
To override the CLI binary path, set the CLAUDE_CODE_BIN environment variable, or assign sdk.BinPath before the first call.
Prerequisites
- Go 1.23 or later (uses
iter.Seq2 range-over-func iterators)
- Claude Code CLI:
npm install -g @anthropic-ai/claude-code
ANTHROPIC_API_KEY set in your environment
License
MIT