Drive Claude Code from Go: run it as a subprocess under a claudewheel profile and read its stream-json output as typed events, with sandboxed permissions, budget thresholds, tools served over MCP, agent definitions, and a command line
The command:
go install github.com/stricttools/claudestream/cmd/claudestream@v0
Each GitHub Release also carries claudestream archives for Linux and macOS (amd64 and arm64).
The library:
go get github.com/stricttools/claudestream@v0
A session needs Claude Code 2.0.0 or newer and claudewheel, whose profile exec command starts Claude Code with a profile's environment. Versions up to 0.15.3 were a Python package, published to PyPI and npm; those releases stay there, and nothing newer is published to either.
ctx := context.Background()
claude, err := claudestream.ResolveOnPath(claudestream.ClaudeProgram)
if err != nil {
log.Fatal(err)
}
claudewheel, err := claudestream.ResolveOnPath(claudestream.ClaudewheelProgram)
if err != nil {
log.Fatal(err)
}
session, err := claudestream.Start(ctx, claudestream.Config{
Model: "sonnet",
Profile: "default",
ClaudeBinary: claude,
ClaudewheelBinary: claudewheel,
Session: claudestream.NewSession{},
})
if err != nil {
log.Fatal(err)
}
defer session.Close()
turn, err := session.Send(ctx, "What is 2 + 2?")
if err != nil {
log.Fatal(err)
}
for {
event, err := turn.Next(ctx)
if errors.Is(err, io.EOF) {
break
}
if err != nil {
log.Fatal(err)
}
if text, ok := event.(claudestream.AssistantText); ok {
fmt.Print(text.Text)
}
}From the command line:
claudestream ask --model sonnet --profile default --new-session --no-skip-permissions --prompt "What is 2 + 2?"
| Command | Description |
|---|---|
ask |
Send one prompt to Claude Code and print only the reply's final text on stdout; with --json, the reply and its metadata are the document's payload. A turn that Claude Code ends with an error exits 1 with the result text on stderr |
stream |
Send one prompt to Claude Code and write the reply's text to stdout as it arrives, with a one-line marker on stderr for each thinking block, tool call, tool result, and notice. A turn that Claude Code ends with an error exits 1 with the result text on stderr |
send |
Send one prompt to Claude Code and render the whole turn on stdout: the reply's text as it arrives, thinking, each tool call with its input as JSON, and each tool result; notices go to stderr. A turn that Claude Code ends with an error exits 1 with the result text on stderr |
events |
Send one prompt to Claude Code and copy every line Claude Code writes to its stdout (stream-json) to stdout verbatim, for debugging the protocol. A turn that Claude Code ends with an error exits 1 with the result text on stderr |
doctor |
Check what a session needs: the claude path and its version against the minimum 2.0.0 (claude -v, within 2s), and the claudewheel path; with --profile, also run claudewheel profile exec --name <profile> -- <claude> -v (within 10s). Prints one [ok] or [FAIL] line per check and exits 1 when any check fails |
| agent | Run and inspect agent definitions: strict TOML files at .claudestream/agents/.agent.toml (format_version = 2) that declare a prompt template with {variable} placeholders and, optionally, a model, tools, a sandbox, budget thresholds, MCP servers, and stream options |
agent run |
Run one prompt through an agent definition and write the reply's text to stdout as it arrives, with markers on stderr as the stream command writes them. The agent's resolved prompt template becomes the system prompt, its name the session name, and its sandbox, budget, MCP, and stream tables replace the defaults. With --agent-name, the agents directory is searched under --cwd, or under the current directory when --cwd is omitted. Agents that declare tools are refused: their handlers exist only in Go programs that call the agent package. A turn that Claude Code ends with an error exits 1 with the result text on stderr |
agent list |
List the agents in .claudestream/agents/ as a table of name, version, and description; any file there that fails to load is an error |
agent info |
Load an agent definition and print every field it declares: name, version, file, description, model, prompt placeholders, tools, sandbox, budget, MCP servers, and stream options. --agent-name searches the agents directory under the current directory |
agent validate |
Load an agent definition, checking it as agent run would, and print its name and version; every problem the file has is reported and exits 1. --agent-name searches the agents directory under the current directory |
The guide, the agent definition format, and the API reference (the session config, every event type, and the sandbox) are at https://smmh.dev/claudestream.
MIT