Go client SDK for OpenCode server. Generated from the OpenAPI spec using oapi-codegen, with hand-written helpers for SSE streaming, authentication, and prompt building.
go get github.com/EternisAI/opencode-go-sdkimport opencode "github.com/EternisAI/opencode-go-sdk"Two client types:
Client— returns raw*http.Response(needed for SSE)ClientWithResponses— auto-parses JSON into typed structs
opts := []opencode.ClientOption{
opencode.WithBasicAuth("password"), // optional
}
rawClient, _ := opencode.NewClient("http://localhost:4096", opts...)
apiClient, _ := opencode.NewClientWithResponses("http://localhost:4096", opts...)resp, _ := apiClient.GlobalHealthWithResponse(ctx)
fmt.Println(resp.JSON200.Version) // "1.2.22"title := "my-agent"
dir := "/workspace"
resp, _ := apiClient.SessionCreateWithResponse(ctx,
&opencode.SessionCreateParams{Directory: &dir},
opencode.SessionCreateJSONRequestBody{Title: &title},
)
session := resp.JSON200Returns HTTP 204 immediately. Track progress via SSE events.
resp, _ := apiClient.SessionPromptAsyncWithResponse(ctx, sessionID,
&opencode.SessionPromptAsyncParams{Directory: &dir},
opencode.TextPromptAsyncBody("Create a hello world server in Go"),
)
// resp.StatusCode() == 204Blocks until the agent finishes.
resp, _ := apiClient.SessionPromptWithResponse(ctx, sessionID,
&opencode.SessionPromptParams{Directory: &dir},
opencode.TextPromptBody("What is 2 + 2?"),
)
// resp.JSON200.Parts — response parts
// resp.JSON200.Info — cost, model, etc.stream, _ := opencode.SubscribeEvents(ctx, rawClient)
defer stream.Close()
for stream.Next() {
ge := stream.Current()
eventType := opencode.EventType(ge.Payload)
switch eventType {
case opencode.EventTypeSessionIdle:
idle, _ := opencode.EventAs[opencode.EventSessionIdle](ge.Payload)
fmt.Printf("Session %s is idle\n", idle.Properties.SessionID)
case opencode.EventTypePermissionAsked:
perm, _ := opencode.EventAs[opencode.EventPermissionAsked](ge.Payload)
apiClient.PermissionReplyWithResponse(ctx, perm.Properties.Id,
&opencode.PermissionReplyParams{},
opencode.PermissionReplyJSONRequestBody{
Reply: opencode.PermissionReplyJSONBodyReplyAlways,
})
case opencode.EventTypeQuestionAsked:
q, _ := opencode.EventAs[opencode.EventQuestionAsked](ge.Payload)
apiClient.QuestionReplyWithResponse(ctx, q.Properties.Id,
&opencode.QuestionReplyParams{},
opencode.QuestionReplyJSONRequestBody{
Answers: []opencode.QuestionAnswer{{"yes"}},
})
case opencode.EventTypeMessagePartDelta:
// Streaming token — forward to UI
}
}apiClient.SessionAbortWithResponse(ctx, sessionID,
&opencode.SessionAbortParams{Directory: &dir})| Helper | Description |
|---|---|
WithBasicAuth(password) |
ClientOption for HTTP Basic Auth |
SubscribeEvents(ctx, client) |
Opens global SSE stream → *Stream[GlobalEvent] |
SubscribeInstanceEvents(ctx, client, params) |
Opens per-instance SSE stream → *Stream[Event] |
EventType(event) |
Extracts type string from Event union |
EventAs[T](event) |
Deserializes Event into typed struct |
TextPromptBody(text) |
Sync prompt body with single text part |
TextPromptAsyncBody(text) |
Async prompt body with single text part |
Ptr[T](v) |
Pointer helper for optional fields |
| Constant | Value |
|---|---|
EventTypeSessionIdle |
session.idle |
EventTypeSessionError |
session.error |
EventTypeSessionStatus |
session.status |
EventTypePermissionAsked |
permission.asked |
EventTypeQuestionAsked |
question.asked |
EventTypeMessagePartUpdated |
message.part.updated |
EventTypeMessagePartDelta |
message.part.delta |
EventTypeMessageUpdated |
message.updated |
# Download spec from running server
curl http://localhost:4096/openapi.json > openapi-spec.json
# Convert 3.1.1 → 3.0.3 (oapi-codegen requires 3.0.x)
python3 convert_spec.py
# Generate
oapi-codegen -generate types -package opencode openapi-spec-3.0.json > types.gen.go
oapi-codegen -generate client -package opencode openapi-spec-3.0.json > client.gen.go
go build ./...MIT