An idiomatic Go SDK for the OpenCode REST API. Built with Go's standard library — no generated code, no heavy dependencies.
go get github.com/dominicnunez/opencode-sdk-goimport opencode "github.com/dominicnunez/opencode-sdk-go"Go 1.22+
Full API surface documented in api.md.
package main
import (
"context"
"fmt"
"log"
"time"
opencode "github.com/dominicnunez/opencode-sdk-go"
)
func main() {
client, err := opencode.NewClient(
opencode.WithBaseURL("http://localhost:8080"),
opencode.WithTimeout(30 * time.Second),
)
if err != nil {
log.Fatal(err)
}
// List all sessions
sessions, err := client.Session.List(context.Background(), &opencode.SessionListParams{})
if err != nil {
log.Fatal(err)
}
fmt.Printf("Found %d sessions\n", len(sessions))
// Create a new session
session, err := client.Session.Create(context.Background(), &opencode.SessionCreateParams{
Agent: "general-purpose",
Contents: []opencode.MessageUnionParam{
opencode.UserMessageParam{
Role: opencode.MessageRoleUser,
Parts: []opencode.PartInputParam{
opencode.TextPartInputParam{
Text: "Hello, how can you help me?",
},
},
},
},
})
if err != nil {
log.Fatal(err)
}
fmt.Printf("Created session: %s\n", session.ID)
}Idiomatic Go types — required fields are direct types, optional fields use pointers:
params := opencode.SessionCommandParams{
Command: "list-files", // required: direct type
Arguments: "--recursive", // required: direct type
Directory: opencode.Ptr("./src"), // optional: pointer
Agent: nil, // optional: nil = omit
}Functional options pattern:
client, err := opencode.NewClient(
opencode.WithBaseURL("https://api.opencode.ai"),
opencode.WithTimeout(60 * time.Second),
opencode.WithMaxRetries(5),
opencode.WithHTTPClient(myHTTPClient),
)Discriminated unions with As*() methods:
for _, msg := range messages {
if user, err := msg.AsUser(); err == nil {
textPart, textErr := user.Parts[0].AsText()
if textErr != nil {
continue
}
fmt.Printf("User: %s\n", textPart.Text)
} else if assistant, err := msg.AsAssistant(); err == nil {
textPart, textErr := assistant.Parts[0].AsText()
if textErr != nil {
continue
}
fmt.Printf("Assistant: %s\n", textPart.Text)
}
}stream := client.Event.ListStreaming(context.Background(), &opencode.EventListParams{})
defer stream.Close()
for stream.Next() {
event := stream.Current()
if msgUpdated, err := event.AsMessageUpdated(); err == nil {
fmt.Printf("Message updated: %s\n", msgUpdated.Data.Info.ID)
}
}
if err := stream.Err(); err != nil {
log.Fatal(err)
}Typed errors with errors.As:
_, err := client.Session.List(context.Background(), &opencode.SessionListParams{})
if err != nil {
var apierr *opencode.APIError
if errors.As(err, &apierr) {
fmt.Printf("status=%d request_id=%s message=%s\n", apierr.StatusCode, apierr.RequestID, apierr.Message)
}
panic(err)
}Exponential backoff (default: 2 retries) for connection errors, 408, 429, and 5xx responses. Base schedule is 500ms → 1s → 2s → 4s → 8s (capped), with jitter applied so each retry sleeps within 50%-100% of that step.
This SDK was originally generated by Stainless for the upstream anomalyco/opencode-sdk-go. It has been fully rewritten as an idiomatic Go SDK using only the standard library — all 51 endpoints, with proper Go conventions (functional options, typed errors, pointer optionals, discriminated unions).
This package follows SemVer. Minor versions may include changes to internals not intended for external use.
See CONTRIBUTING.md.