Go SDK · Claude Code CLI

Build agents in Go,
over the stream.

A typed, dependency-light client for the claude binary. One-shot runs, live sessions, in-process Go tools, and Go callbacks for every permission and hook — spoken over one bidirectional pipe.

$go get github.com/tggo/claude-agent-go
View on GitHub →
Zero runtime deps >90% coverage 17 live-binary tests
01

Everything the CLI can do, typed

The agent loop stays in the binary. The SDK gives you a clean Go surface over it — and over the control protocol most wrappers never reach.

In-process tools // tools

The agent calls your Go functions during a run. No server to deploy. Untyped, or typed with schema inferred from a struct.

tools.Register(reg, "add", "Add two ints", func(ctx, in Args) (Out, error) { return Out{in.A + in.B}, nil })

Permission callbacks // can_use_tool

Decide allow / deny for every tool call, in Go, while the turn is paused. Deny actually blocks it.

// deny shell, allow the rest if tool == "Bash" { return client.Deny("no shell"), nil } return client.Allow(), nil

Hook callbacks // PreToolUse

Run Go logic before a tool fires — observe it, rewrite its input, or block it outright.

// block, with a reason the model sees {"permissionDecision": "deny", "permissionDecisionReason": "policy"}

Inline subagents // agents

Define subagents from Go — no files on disk. The main agent delegates to them through the Task tool.

Agents: {"reviewer": { Description: "Audits diffs", Prompt: "You are terse.", Model: "opus", }}

Interactive sessions // client

One long-running process, many turns, full memory. Token-level streaming and interrupt-with-ack included.

c.Query(ctx, "Remember 7.", nil) t := c.Query(ctx, "Which number?", nil) // t.Text → "7"

One-shot runs // runner

Plain, JSON, or streaming — with cost, session id, tokens, and turns parsed for you. Resume across processes.

res := r.RunJSON(ctx, Input{ Prompt: "Summarize.", }) // res.TotalCostUSD, res.SessionID
02

Claims you can re-run

Every capability has an integration test that asserts the effect against the real binary — a denied tool that doesn't write, a skill whose marker appears only when loaded, a subagent whose prompt reaches the answer.

17 / 17

live-binary integration tests passing — plus >90% unit coverage on every package.

  • Deny blocks. can_use_tool denial leaves the file uncreated, not just the callback fired.
  • Skills filter. A local skill's marker appears when allowed and vanishes when the allowlist omits it.
  • Subagents run. A token that exists only in the subagent's prompt reaches the final answer.
  • Resume continues. A second process recalls a codeword from the first session.
  • Tools execute. The Go handler runs and its result shapes the reply.