Codex Agent SDK Go
Go SDK for the OpenAI Codex CLI app-server transport β JSON-RPC 2.0 over stdio with typed events, approval callbacks, MCP config, structured output
Ask AI about Codex Agent SDK Go
Powered by Claude Β· Grounded in docs
I know everything about Codex Agent SDK Go. Ask me about installation, configuration, usage, or troubleshooting.
0/500
Reviews
Documentation
Codex Agent SDK for Go
Go SDK for the OpenAI Codex CLI app-server transport β spawns codex app-server as a child process, speaks JSON-RPC 2.0 over stdio, and exposes a typed Go API for threads, turns, streaming events, approvals, and MCP configuration.
Status: preview (
v0.x). API may change beforev1.0.0. Feedback welcome.
Sibling SDK: claude-agent-sdk-go does the same thing for the Claude Code CLI.
Why this SDK?
Codex's app-server exposes a JSON-RPC 2.0 protocol over stdio β bidirectional, stateful, with server-initiated approval requests. Consuming it directly means handling line-framing with a 2 MiB minimum buffer, demultiplexing three request shapes (responses, notifications, server-initiated requests), serializing concurrent turns to preserve event boundaries, and mapping ~15 notification types to typed Go events. This SDK handles all of that and exposes a clean, typed API.
Feature matrix
| Feature | Status on current mainline |
|---|---|
codex app-server transport | β |
codex exec --json one-shot | β deferred to v2 |
| Thread start / resume / fork / archive / list | β |
thread.Run() (buffered) + thread.RunStreamed() (channel) | β |
| Streaming events: turn/started, turn/completed, item/started, item/updated, item/completed, error, tokenUsage, compaction | β |
| ThreadItem variants: agentMessage, userMessage, commandExecution, fileChange, mcpToolCall, webSearch, memoryRead/Write, plan, reasoning, systemError | β |
| Input variants: text, localImage | β |
| Sandbox modes: read-only, workspace-write, danger-full-access | β |
| Approval policies: auto, read-only, untrusted, never, on-request | β |
| Approval callback (server-initiated request β caller decides) | β |
| MCP server config (stdio + streamable HTTP) | β |
| JSON-schema structured output | β |
Typed errors with Is*() helpers | β |
| Turn interrupt | β |
| CLI discovery + soft version probe | β |
| Goroutine leak detection (goleak) | β |
| Hook observer events (HookStarted / HookCompleted) | β
v0.2.0 β via WithHooks(true) |
| Programmatic Go hook callbacks (shim bridge, auto-wired) | β
v0.3.0 β WithHookCallback(h) writes hooks.json automatically and restores on Close. See docs/hooks.md. |
| Slash-command equivalents (Compact, SetModel, ListMCPServers, Review, etc.) | β
v0.4.0 β 20 typed methods + GitDiff / InitAgentsMD helpers. See docs/commands.md. |
| Native FFI (CGO) | β deferred |
Prerequisites
- Go 1.25+
- Codex CLI installed:
npm install -g @openai/codex(or your distro's equivalent) - Auth (one of):
OPENAI_API_KEYenvironment variable (pay-per-token)~/.codex/auth.json(ChatGPT Plus/Pro subscription; runcodex loginonce outside the daemon)
Install
go get github.com/hishamkaram/codex-agent-sdk-go
Quick start
One-shot query
package main
import (
"context"
"fmt"
"log"
codex "github.com/hishamkaram/codex-agent-sdk-go"
"github.com/hishamkaram/codex-agent-sdk-go/types"
)
func main() {
ctx := context.Background()
opts := types.NewCodexOptions().
WithModel("gpt-5.4").
WithSandbox(types.SandboxReadOnly).
WithApprovalPolicy(types.ApprovalOnRequest)
events, err := codex.Query(ctx, "Summarize the repo in the current directory", opts)
if err != nil {
log.Fatal(err)
}
for event := range events {
switch e := event.(type) {
case *types.ItemCompleted:
if msg, ok := e.Item.(*types.AgentMessage); ok {
fmt.Println(msg.Content)
}
case *types.TurnCompleted:
fmt.Printf("Tokens: in=%d out=%d\n", e.Usage.InputTokens, e.Usage.OutputTokens)
}
}
}
Interactive multi-turn client
client, err := codex.NewClient(ctx, opts)
if err != nil { log.Fatal(err) }
defer client.Close(ctx)
thread, err := client.StartThread(ctx, &types.ThreadOptions{Cwd: "/my/project"})
if err != nil { log.Fatal(err) }
events, _ := thread.RunStreamed(ctx, "Make a plan to fix the CI failure")
for event := range events { /* ... */ }
events2, _ := thread.RunStreamed(ctx, "Now implement the plan")
for event := range events2 { /* ... */ }
Approval callback
opts = opts.WithApprovalCallback(func(ctx context.Context, req types.ApprovalRequest) types.ApprovalDecision {
if r, ok := req.(*types.CommandExecutionApprovalRequest); ok {
if isSafeCommand(r.Command) {
return types.ApprovalAccept{}
}
}
return types.ApprovalDeny{Reason: "not on allowlist"}
})
What it does
- Spawns
codex app-serveras a subprocess with stdin/stdout pipes - Frames JSON-RPC 2.0 messages with LF termination (
jsonrpcfield omitted on wire) - Demultiplexes responses (id β pending chan), notifications (β events chan), server-initiated requests (β approval callback)
- Serializes all stdin writes via single
stdinMuto prevent frame interleave - Serializes per-thread
Run()calls viaturnMuto preserve turn boundaries - Maintains a 2 MiB read buffer for large notification payloads
- Translates raw JSON-RPC notifications into typed Go events
- Handles CLI discovery (PATH,
~/.codex/bin, brew, npm install paths) and soft version probe - Emits structured logs via zap
What it does NOT do (current preview)
codex exec --json(fire-and-forget) transport β theapp-serverpath is the only one implemented- Lifecycle hooks (Codex upstream doesn't expose SDK-side pre/post-tool hook registration yet)
- CLI slash commands (those live in the interactive TUI, irrelevant to SDK callers)
- Codex-as-MCP-server mode (experimental upstream)
- Dynamic OpenAI pricing table (use static rates in this SDK; fetch at integration time if needed)
Docs
docs/getting-started.mdβ install, first query, multi-turn, streaming, resume, approvals in ~2 pagesdocs/architecture.mdβ the four layers, dispatcher goroutine, turn lock, concurrency contract, shutdown ladderdocs/wire-protocol.mdβ JSON-RPC method reference, wire quirks (flat vs nested IDs, per-item delta methods), known-unknown methodsdocs/approvals.mdβ approval request/decision taxonomy, sandbox Γ policy matrix, deadlock warningdocs/hooks.mdβ observer mode + auto-wired programmatic callbacks viaWithHookCallback(v0.3.0)docs/commands.mdβ slash-command-equivalent typed methods (Compact, SetModel, Rollback, StartReview, β¦) and local-helper parity (GitDiff, InitAgentsMD) (v0.4.0)
Examples
Seven runnable examples under examples/:
| Example | What it shows |
|---|---|
simple_query | One-shot Query() |
streaming | Multi-turn RunStreamed + delta streaming |
resume | Persistent thread across process restarts |
fork | Branching a thread |
with_approvals | Command + file approval callback |
with_mcp | Registering MCP servers (stdio + HTTP) |
with_hooks | Observe HookStarted/HookCompleted events from your configured hooks |
structured_output | JSON-schema-constrained final response |
Build all: make examples. Run any: go run ./examples/<name>.
License
MIT β see LICENSE.
