Documentation
¶
Overview ¶
Package opencodesdk is a Go SDK for driving the opencode CLI in its Agent Client Protocol (ACP) mode.
The SDK spawns `opencode acp` as a subprocess, wires its stdio into the protocol layer supplied by github.com/coder/acp-go-sdk, and adds:
- one-shot and lifecycle helpers (Query, QueryContent, QueryStream, QueryStreamContent, WithClient) for simple cases, plus a stateful Client and Session API with functional options for long-running use. The *Content variants accept multimodal prompts ([]acp.ContentBlock) alongside the iterator helpers PromptsFromStrings, PromptsFromSlice, PromptsFromChannel, and SinglePrompt.
- content-block ergonomics: Text, Blocks, TextBlock, ImageBlock, ImageFileInput (load an image from disk), ResourceBlock, ResourceLinkBlock.
- pluggable transport via WithTransport + Transport: swap the default `opencode acp` subprocess for a test double or alternate carrier without touching the rest of the API.
- ACP unstable `additionalDirectories` pass-through via WithAddDirs (capability-gated on SessionCapabilities.AdditionalDirectories; silently dropped when the agent doesn't advertise support).
- opencode `--pure` shortcut via WithPure for disabling external plugins on the spawned CLI.
- typed wrappers for opencode-specific unstable RPCs (Client.ForkSession, Client.ResumeSession, Client.UnstableSetModel) and the _meta.opencode.variant channel (OpencodeVariant).
- typed session/update subscribers via Session.Subscribe and UpdateHandlers for AgentMessage, Plan, ToolCall, Mode, etc., so callers can register per-variant callbacks instead of draining Session.Updates() with a switch.
- a turn-complete hook (WithOnTurnComplete) and an overflow-observation hook (WithOnUpdateDropped, plus Session.DroppedUpdates()) for cross-cutting observability.
- a cursor-paginated session iterator ([Client.IterSessions]) over opencode's session/list RPC.
- a raw extension-method escape hatch ([Client.CallExtension]) for ACP `_`-prefixed methods the SDK does not yet expose as typed wrappers.
- prompt-capability preflight: Session.Prompt rejects content blocks the agent did not advertise support for with ErrCapabilityUnavailable.
- permission and filesystem callbacks surfaced via WithCanUseTool and WithOnFsWrite, plus cwd-scoped write enforcement (WithStrictCwdBoundary). WithAllowedTools and WithDisallowedTools layer auto-approve / auto-reject filters on top of WithCanUseTool, matching on the opencode tool name (acp.ToolCall.Title).
- agent-initiated elicitation handlers via WithOnElicitation and WithOnElicitationComplete (forward-compat for ACP's unstable elicitation/create; opencode 1.14.20 does not emit it yet).
- per-session MCP-capability preflight: session/new is rejected locally with ErrCapabilityUnavailable when a configured McpServer entry uses a transport the agent did not advertise.
- in-process tools via a loopback HTTP MCP bridge declared in session/new's mcpServers (WithSDKTools + the Tool interface).
- opencode's terminal-auth launch-instruction extraction (WithTerminalAuthCapability, TerminalAuthInstructions, WithAutoLaunchLogin).
- OpenTelemetry metrics and spans under the opencodesdk.* namespace (WithMeterProvider, WithTracerProvider).
- typed errors for diagnostics (CLINotFoundError, ProcessError, TransportError, RequestError) alongside the sentinel errors (ErrCLINotFound, ErrClientClosed, ErrClientAlreadyConnected, ErrRequestTimeout, ErrTransport, ...). All SDK-originated errors satisfy the OpencodeSDKError marker interface. Transport health observable via TransportHealth + Client.GetTransportHealth.
- MCP tool-author conveniences (TextResult, ErrorResult, ImageResult, ParseArguments, SimpleSchema) for building Tool implementations and ToolResult values without hand- rolled literals. WithToolAnnotations forwards read-only / destructive / idempotent / open-world hints to opencode.
- persisted session-cost accounting via CostTracker, LoadSessionCost, and SaveSessionCost — snapshots land under $XDG_DATA_HOME/opencode/sdk/session-costs/.
- client-less session metadata lookup via StatSession and ListSessions reading opencode's local SQLite store ($XDG_DATA_HOME/opencode/opencode.db); both return SessionStat without starting an `opencode acp` subprocess. Use WithCwd to scope by project directory. ListSessions returns rows ordered by UpdatedAt descending and excludes archived sessions by default — use ListSessionsOptions to opt in or to cap the row count. For an ACP-authoritative listing, use [Client.ListSessions] / [Client.IterSessions].
- structured-output decoding via DecodeStructuredOutput and DecodePromptResult, with an agent advisory schema via WithOutputSchema.
- error classification + retry taxonomy via ClassifyError, ErrorClassification, RetryPolicy, EvaluateRetry, and the ResilientQuery wrapper that applies exponential backoff + jitter for rate-limit / overload / transient-connection errors.
- one-shot model discovery via ListModels without hand-rolling a session loop.
- one-shot model-capability discovery via ListModelCapabilities ([reasoning], [tool_call], [attachment], context/[output] limits, …) — spawns a throw-away `opencode serve` subprocess and fetches /config/providers, since ACP's catalogue does not carry capability flags.
- subprocess data-dir isolation via WithOpencodeHome.
- Prometheus metrics via WithPrometheusRegisterer (OTel Prometheus exporter under the hood).
- typed lifecycle hooks via WithHooks covering tool calls, prompt submission, permission requests, session lifecycle, and file-write delegations. Blocking-capable events (UserPromptSubmit, PermissionRequest, FileChanged) abort the triggering action when a hook returns Continue=false.
- tool-side MCP elicitation via Elicit — callable from within [Tool.Execute] to send a server-initiated prompt back through the loopback bridge to opencode's user.
- coordinated shutdown via [Client.CancelAll], fanning session/cancel across every live session on the Client.
- opencode session mode constants (ModeBuild, ModePlan) plus the ACP-terminology option WithInitialMode as a sugar alias for WithAgent, and [Session.AvailableModes] for enumerating the modes opencode advertised at session/new.
- reasoning-effort enum Effort + WithEffort mapping abstract None/Low/Medium/High/Max levels onto opencode's per-model variant strings (probed at session creation; silent no-op when the model exposes no variants).
- client-side per-session turn cap via WithMaxTurns: counts distinct assistant message ids and calls Session.Cancel when the cap is crossed (opencode has no protocol-level turn limit).
- slash-command sugar via [Session.RunCommand] for invoking the commands opencode advertises in [Session.AvailableCommands].
- OTel attribution via WithUser (adds a `user` span attribute + metric label across prompt-scoped instruments).
- map-shaped CLI flags via WithExtraArgs alongside the slice form WithCLIFlags.
- NopLogger — a *slog.Logger that discards output, convenient for tests and for passing to WithLogger when the SDK should stay silent.
Quick start ¶
One-shot:
res, err := opencodesdk.Query(ctx, "Say hello.", opencodesdk.WithCwd(cwd))
Lifecycle helper:
err := opencodesdk.WithClient(ctx, func(c opencodesdk.Client) error {
sess, err := c.NewSession(ctx)
if err != nil { return err }
_, err = sess.Prompt(ctx, acp.TextBlock("Say hello."))
return err
}, opencodesdk.WithCwd(cwd))
Requirements ¶
- opencode CLI >= MinimumCLIVersion available in $PATH
- ACP protocol version ProtocolVersion
- A completed `opencode auth login` (the SDK does not initiate auth on its own; with WithAutoLaunchLogin it can exec the command opencode advertises in _meta["terminal-auth"])
Scope ¶
The SDK is opencode-focused. Because coder/acp-go-sdk is generic, the transport surface would work against any ACP v1 agent, but the opinionated options (agent modes, unstable_* wrappers, _meta.opencode parsers, HTTP MCP bridge port picker) are opencode-shaped.
Intentional omissions vs sister SDKs ¶
Callers coming from claude-agent-sdk-go or codex-agent-sdk-go will notice a handful of deliberate non-features; each tracks a semantic gap in opencode itself rather than an oversight here.
- No WithSystemPrompt / WithSystemPromptFile. opencode 1.14.20's ACP surface does not accept per-session system prompts: its `session/new` advertises only `model` and `mode` as settable config options, and unknown fields are silently dropped. opencode resolves instructions server-side from `AGENTS.md` in the cwd and from agent definitions in `opencode.json`. Use WithAgent / WithInitialMode to pick an agent, and put prompt content in `AGENTS.md` or a custom agent definition.
- No file-rewind / checkpoint API. opencode snapshots files internally (see its `snapshot/` dir) but exposes no ACP method to restore them; the `session.revert` column is TUI-owned.
- No separate thinking-tokens knob. Reasoning effort is baked into the model id itself (e.g. `anthropic/claude-sonnet-4/high`) and surfaced through `_meta.opencode.availableVariants`; WithEffort is the complete control.
- No logout / provider-toggle RPCs. Provider selection collapses into the `model` option; auth lifecycle lives in `opencode auth login` / `logout` at the CLI, not over ACP.
Index ¶
- Constants
- Variables
- func AllowAlways(_ context.Context, req acp.RequestPermissionRequest) (acp.RequestPermissionResponse, error)
- func AllowOnce(_ context.Context, req acp.RequestPermissionRequest) (acp.RequestPermissionResponse, error)
- func BoolPtr(b bool) *bool
- func DeclineElicitation(_ context.Context, _ acp.UnstableCreateElicitationRequest) (acp.UnstableCreateElicitationResponse, error)
- func DecodePromptResult[T any](result *PromptResult) (T, error)
- func DecodeStructuredOutput[T any](result *QueryResult) (T, error)
- func DeleteSessionCost(sessionID string, opts SessionCostOptions) error
- func Float64Ptr(v float64) *float64
- func IntPtr(v int) *int
- func IsRetryable(err error) bool
- func ListModelCapabilities(ctx context.Context, opts ...Option) (map[string]ModelCapabilities, error)
- func NopLogger() *slog.Logger
- func ParseArguments(in map[string]any, dst any) error
- func PromptsFromChannel(ch <-chan []acp.ContentBlock) iter.Seq[[]acp.ContentBlock]
- func PromptsFromSlice(prompts [][]acp.ContentBlock) iter.Seq[[]acp.ContentBlock]
- func PromptsFromStrings(prompts []string) iter.Seq[[]acp.ContentBlock]
- func QueryStream(ctx context.Context, prompts []string, opts ...Option) iter.Seq2[*QueryResult, error]
- func QueryStreamContent(ctx context.Context, prompts iter.Seq[[]acp.ContentBlock], opts ...Option) iter.Seq2[*QueryResult, error]
- func RejectOnce(_ context.Context, req acp.RequestPermissionRequest) (acp.RequestPermissionResponse, error)
- func SaveSessionCost(sessionID string, snap CostSnapshot, opts SessionCostOptions) error
- func SimpleSchema(fields map[string]string) map[string]any
- func SinglePrompt(blocks ...acp.ContentBlock) iter.Seq[[]acp.ContentBlock]
- func WithClient(ctx context.Context, fn func(Client) error, opts ...Option) error
- type BudgetStatus
- type BudgetTracker
- func (t *BudgetTracker) CheckBudget() error
- func (t *BudgetTracker) CostTracker() *CostTracker
- func (t *BudgetTracker) ObserveNotification(sessionID string, n acp.SessionNotification)
- func (t *BudgetTracker) ObservePromptResult(sessionID string, result *PromptResult)
- func (t *BudgetTracker) ObserveUsage(sessionID string) func(ctx context.Context, upd *acp.SessionUsageUpdate)
- func (t *BudgetTracker) Status() BudgetStatus
- type BudgetTrackerOptions
- type CLINotFoundError
- type Client
- type ContentBlock
- func AudioBlock(data, mimeType string) ContentBlock
- func AudioFileInput(path string) (ContentBlock, error)
- func AudioFileInputMime(path, mimeType string) (ContentBlock, error)
- func Blocks(blocks ...ContentBlock) []ContentBlock
- func ImageBlock(data, mimeType string) ContentBlock
- func ImageFileInput(path string) (ContentBlock, error)
- func ImageFileInputMime(path, mimeType string) (ContentBlock, error)
- func PDFFileInput(path string) (ContentBlock, error)
- func PathInput(path string) (ContentBlock, error)
- func ResourceBlock(res acp.EmbeddedResourceResource) ContentBlock
- func ResourceLinkBlock(name, uri string) ContentBlock
- func Text(text string) []ContentBlock
- func TextBlock(text string) ContentBlock
- type CostSnapshot
- type CostTracker
- func (t *CostTracker) LoadSessionCost(sessionID string, opts SessionCostOptions) error
- func (t *CostTracker) ObserveNotification(sessionID string, n acp.SessionNotification)
- func (t *CostTracker) ObservePromptResult(sessionID string, result *PromptResult)
- func (t *CostTracker) ObserveUsage(sessionID string) func(ctx context.Context, upd *acp.SessionUsageUpdate)
- func (t *CostTracker) SaveSessionCost(sessionID string, opts SessionCostOptions) error
- func (t *CostTracker) SessionSnapshot(sessionID string) (CostSnapshot, bool)
- func (t *CostTracker) Snapshot() CostSnapshot
- type Effort
- type ElicitMode
- type ElicitParams
- type ElicitResult
- type ElicitationCallback
- type ElicitationCompleteCallback
- type ErrorClass
- type ErrorClassification
- type ErrorSubClass
- type FsWriteCallback
- type HistoryMessage
- type HookCallback
- type HookEvent
- type HookInput
- type HookMatcher
- type HookOutput
- type ListModelsResponse
- type ListSessionsOptions
- type ModalityCapabilities
- type ModelCapabilities
- type ModelInfo
- type NewToolOption
- type OpencodeSDKError
- type Option
- func WithAddDirs(dirs ...string) Option
- func WithAgent(agent string) Option
- func WithAllowedTools(names ...string) Option
- func WithAutoLaunchLogin(enabled bool) Option
- func WithBudgetTracker(t *BudgetTracker) Option
- func WithCLIFlags(flags ...string) Option
- func WithCLIPath(path string) Option
- func WithCanUseTool(cb PermissionCallback) Option
- func WithCwd(path string) Option
- func WithDisallowedTools(names ...string) Option
- func WithEffort(level Effort) Option
- func WithEnv(env map[string]string) Option
- func WithExtraArgs(args map[string]*string) Option
- func WithHooks(hooks map[HookEvent][]*HookMatcher) Option
- func WithInitialMode(mode string) Option
- func WithInitializeTimeout(d time.Duration) Option
- func WithLogger(l *slog.Logger) Option
- func WithMCPServers(servers ...acp.McpServer) Option
- func WithMaxBudgetUSD(budgetUSD float64) Option
- func WithMaxTurns(n int) Option
- func WithMeterProvider(mp metric.MeterProvider) Option
- func WithModel(id string) Option
- func WithOnElicitation(cb ElicitationCallback) Option
- func WithOnElicitationComplete(cb ElicitationCompleteCallback) Option
- func WithOnFsWrite(cb FsWriteCallback) Option
- func WithOnTurnComplete(cb TurnCompleteCallback) Option
- func WithOnUpdateDropped(cb UpdateDroppedCallback) Option
- func WithOnUserInput(cb UserInputCallback) Option
- func WithOpencodeHome(path string) Option
- func WithOutputSchema(schema map[string]any) Option
- func WithPrometheusRegisterer(reg prometheus.Registerer) Option
- func WithPure() Option
- func WithSDKTools(tools ...Tool) Option
- func WithSkipVersionCheck(skip bool) Option
- func WithStderr(fn func(line string)) Option
- func WithStrictCwdBoundary(enabled bool) Option
- func WithTerminalAuthCapability(enabled bool) Option
- func WithTracerProvider(tp trace.TracerProvider) Option
- func WithTransport(factory TransportFactory) Option
- func WithUpdatesBuffer(n int) Option
- func WithUser(user string) Option
- type PermissionCallback
- type ProcessError
- type PromptResult
- type QueryResult
- func Query(ctx context.Context, prompt string, opts ...Option) (*QueryResult, error)
- func QueryContent(ctx context.Context, blocks []acp.ContentBlock, opts ...Option) (*QueryResult, error)
- func ResilientQuery(ctx context.Context, prompt string, rq ResilientQueryOptions, opts ...Option) (*QueryResult, error)
- type Question
- type QuestionOption
- type RecoveryAction
- type RequestError
- type ResilientQueryOptions
- type RetryDecision
- type RetryPolicy
- type Session
- type SessionCostOptions
- type SessionHistory
- type SessionInfo
- type SessionStat
- type StopReason
- type TerminalAuthLaunch
- type Tool
- type ToolAnnotations
- type ToolCallStatus
- type ToolFunc
- type ToolKind
- type ToolResult
- type Transport
- type TransportError
- type TransportFactory
- type TransportHealth
- type TurnCompleteCallback
- type UpdateDroppedCallback
- type UpdateHandlers
- type UserInputAnswer
- type UserInputCallback
- type UserInputRequest
- type UserInputResponse
- type VariantInfo
- type WatchableTransport
Constants ¶
const ( ToolKindRead = acp.ToolKindRead ToolKindEdit = acp.ToolKindEdit ToolKindDelete = acp.ToolKindDelete ToolKindMove = acp.ToolKindMove ToolKindSearch = acp.ToolKindSearch ToolKindExecute = acp.ToolKindExecute ToolKindThink = acp.ToolKindThink ToolKindFetch = acp.ToolKindFetch ToolKindSwitchMode = acp.ToolKindSwitchMode ToolKindOther = acp.ToolKindOther )
Tool-call kind constants mirror the ACP spec.
const ( ToolCallStatusPending = acp.ToolCallStatusPending ToolCallStatusInProgress = acp.ToolCallStatusInProgress ToolCallStatusCompleted = acp.ToolCallStatusCompleted ToolCallStatusFailed = acp.ToolCallStatusFailed )
Tool-call status constants mirror the ACP spec.
const ( StopReasonEndTurn = acp.StopReasonEndTurn StopReasonMaxTokens = acp.StopReasonMaxTokens StopReasonMaxTurnRequests = acp.StopReasonMaxTurnRequests StopReasonRefusal = acp.StopReasonRefusal StopReasonCancelled = acp.StopReasonCancelled )
Stop-reason constants mirror the ACP spec. opencode currently emits EndTurn on success and surfaces cancellation via ErrCancelled on the Prompt error path.
const ( // ModeBuild is opencode's default mode. It executes tools based // on the configured permission ruleset. ModeBuild = "build" // ModePlan is opencode's read-only planning mode. It denies all // edit tools inline (does NOT route through // session/request_permission). ModePlan = "plan" )
Built-in opencode session modes. These match the values advertised under ACP's `mode` SessionConfigOption in opencode 1.14.20. Users may also configure additional modes in opencode.json.
const AskUserQuestionToolName = "AskUserQuestion"
AskUserQuestionToolName is the MCP tool name the SDK registers when WithOnUserInput is set. Mirrors the tool Claude Code exposes so prompts and host translators that target Claude Code transfer unchanged.
const MinimumCLIVersion = "1.14.20"
MinimumCLIVersion is the minimum required opencode CLI version. The SDK probes `opencode --version` while resolving the binary in Client.Start and fails fast with ErrUnsupportedCLIVersion unless WithSkipVersionCheck(true) is set.
const ProtocolVersion = 1
ProtocolVersion is the ACP protocol version this SDK targets.
const StructuredOutputToolName = "StructuredOutput"
StructuredOutputToolName is the MCP tool name registered by the SDK when WithOutputSchema is set. Mirrors Claude Code's convention and opencode's own JS-SDK implementation (opencode PR #8161).
const Version = "0.0.0-dev"
Version is the opencodesdk library version.
Variables ¶
var ( // ErrAuthRequired is returned when opencode reports that the user is // not authenticated. Instruct the user to run `opencode auth login` // in their terminal and retry. Wraps a *RequestError. ErrAuthRequired = errors.New("opencode authentication required; run `opencode auth login` in a terminal") // ErrCancelled is returned when a prompt turn is cancelled mid-flight. ErrCancelled = errors.New("prompt cancelled") // ErrCLINotFound is returned when the opencode binary cannot be // located in $PATH or at the path supplied via WithCLIPath. ErrCLINotFound = errors.New("opencode CLI not found") // ErrUnsupportedCLIVersion is returned when the discovered opencode // binary is older than MinimumCLIVersion. ErrUnsupportedCLIVersion = errors.New("opencode CLI version is older than MinimumCLIVersion") // ErrClientClosed is returned by Client methods after Close has been called. ErrClientClosed = errors.New("client is closed") // ErrClientNotStarted is returned by Client methods called before Start. ErrClientNotStarted = errors.New("client has not been started") // ErrClientAlreadyConnected is returned by Client.Start when the // client has already been started. Each Client may be Started at // most once — construct a fresh Client via NewClient for a new // subprocess. ErrClientAlreadyConnected = errors.New("client has already been started") // ErrRequestTimeout is returned by Client / Session RPCs whose // context carried a deadline that fired before the agent responded. // Wraps context.DeadlineExceeded so existing callers checking for // that via errors.Is continue to work. ErrRequestTimeout = errors.New("request timed out") // with a content block (image, audio, embedded resource) that the // agent did not advertise support for in its PromptCapabilities. ErrCapabilityUnavailable = errors.New("agent does not advertise required prompt capability") // ErrUpdateQueueOverflow is recorded when a session/update // notification is dropped because the Session.Updates() buffer was // full. It is not returned directly — callers observe the condition // via Session.DroppedUpdates or the `opencodesdk.session.updates.dropped` // metric. ErrUpdateQueueOverflow = errors.New("session updates buffer overflowed; notifications were dropped") // ErrExtensionMethodRequired is returned by Client.CallExtension // when the supplied method name does not begin with an underscore. // The ACP spec reserves `_`-prefixed methods for extensions. ErrExtensionMethodRequired = errors.New("extension method names must begin with \"_\"") // ErrStructuredOutputMissing is returned by DecodeStructuredOutput // when neither the PromptResult.Meta block nor the QueryResult // AssistantText carries a decodable payload for the requested type. ErrStructuredOutputMissing = errors.New("opencodesdk: structured output missing") // ErrTransport is returned when the opencode acp subprocess (or // equivalent transport) terminates unexpectedly, leaving no // in-flight RPC able to complete. See TransportError for the typed // companion carrying the underlying cause. ErrTransport = errors.New("opencodesdk: transport closed unexpectedly") // ErrSessionNotFound is returned by StatSession when the requested // session ID does not exist in opencode's local database (or the // database file is missing entirely). ErrSessionNotFound = errors.New("opencodesdk: session not found") )
Sentinel errors for callers to check against with errors.Is.
var ( // ErrBudgetExceeded is returned from BudgetTracker.CheckBudget and // wrapped by WithMaxBudgetUSD's automatic session cancellation // path when the configured cost/token cap is reached. ErrBudgetExceeded = errors.New("opencodesdk: budget exceeded") )
Sentinel errors surfaced by BudgetTracker.
ErrElicitationUnavailable is returned by Elicit when the ctx does not carry a bridge-bound ToolSession. This happens when Elicit is called outside of a Tool.Execute invocation, or when the client is not running the SDK's loopback MCP bridge (i.e. WithSDKTools was not configured).
var ErrHookRejected = errors.New("opencodesdk: hook rejected")
ErrHookRejected is returned up through the SDK when a hook blocks UserPromptSubmit. The error wraps the hook's Reason.
var ErrSessionCostNotFound = errors.New("opencodesdk: session cost not found")
ErrSessionCostNotFound is returned by LoadSessionCost when no persisted snapshot exists for the requested session id.
Functions ¶
func AllowAlways ¶
func AllowAlways(_ context.Context, req acp.RequestPermissionRequest) (acp.RequestPermissionResponse, error)
AllowAlways selects the first "allow_always" option, falling back to allow_once then first.
func AllowOnce ¶
func AllowOnce(_ context.Context, req acp.RequestPermissionRequest) (acp.RequestPermissionResponse, error)
AllowOnce is a PermissionCallback helper that selects the first "allow_once" option if present. It falls back to the first option on offer, or errors if none exist. Safe default for developer loops.
func BoolPtr ¶
BoolPtr returns a pointer to b. Convenience for populating the pointer-valued fields on ToolAnnotations.
func DeclineElicitation ¶
func DeclineElicitation(_ context.Context, _ acp.UnstableCreateElicitationRequest) (acp.UnstableCreateElicitationResponse, error)
DeclineElicitation is an ElicitationCallback helper returning a Decline response with no content. Useful as an explicit "not implemented" default when wiring the option in tests.
func DecodePromptResult ¶
func DecodePromptResult[T any](result *PromptResult) (T, error)
DecodePromptResult[T] is the companion for callers who interact with Session.Prompt directly and don't have access to the streamed AssistantText. It reads PromptResult.Meta["structuredOutput"] only — no text fallback — so returns ErrStructuredOutputMissing if the agent did not advertise a structured payload via _meta.
func DecodeStructuredOutput ¶
func DecodeStructuredOutput[T any](result *QueryResult) (T, error)
DecodeStructuredOutput[T] extracts a typed T value from a QueryResult. The precedence is:
- A decoded object at QueryResult.Notifications[…].Update containing a PromptResponse-side Meta["structuredOutput"] block. (Opencode does not currently set this out of the box — it's a convention reserved for agents that opt in via _meta.)
- Parsing QueryResult.AssistantText as JSON — possibly wrapped in a fenced code block.
Returns ErrStructuredOutputMissing when neither path yields a decodable payload.
For callers holding a raw PromptResult (not a QueryResult), use DecodePromptResult[T].
func DeleteSessionCost ¶
func DeleteSessionCost(sessionID string, opts SessionCostOptions) error
DeleteSessionCost removes a persisted session-cost file. Returns ErrSessionCostNotFound when the file does not exist.
func Float64Ptr ¶
Float64Ptr returns a pointer to v. Convenience for filling BudgetTrackerOptions inline.
func IsRetryable ¶
IsRetryable reports whether err would be retried by ResilientQuery under the default policy. Thin convenience wrapper around ClassifyError for callers who want a boolean predicate.
func ListModelCapabilities ¶ added in v0.0.3
func ListModelCapabilities(ctx context.Context, opts ...Option) (map[string]ModelCapabilities, error)
ListModelCapabilities enumerates every model opencode knows about and returns its capability flags keyed by "<providerID>/<modelID>" — the same form accepted by WithModel.
Under the hood this spawns a throw-away `opencode serve` subprocess on a loopback ephemeral port, calls its `GET /config/providers` endpoint, and tears the server down. All Option values are honoured where meaningful (logger, cli path, env, cwd, opencode-home) — session-only options such as WithModel or WithEffort are ignored.
Returns an empty map (nil error) when opencode reports no providers.
func NopLogger ¶
NopLogger returns a *slog.Logger that discards all output. It is convenient for tests and for callers that want to silence the SDK without wiring up a real handler. Passing the result to WithLogger is equivalent to not calling WithLogger at all — the SDK is silent by default.
func ParseArguments ¶
ParseArguments decodes a Tool.Execute input map into dst. dst must be a pointer to a struct (or any json-compatible value). The map is round-tripped through JSON so json tags, `omitempty`, and json.Unmarshaler implementations on dst are honored.
Returns a descriptive error when dst is not a pointer or when any individual field fails to decode — callers typically return the error from their Execute as-is.
func PromptsFromChannel ¶
func PromptsFromChannel(ch <-chan []acp.ContentBlock) iter.Seq[[]acp.ContentBlock]
PromptsFromChannel drains prompts sent on ch until the channel is closed. Suitable for long-running consumers that generate prompts dynamically (e.g. from a queue, or in response to earlier results). Closing ch signals end-of-stream to QueryStreamContent.
func PromptsFromSlice ¶
func PromptsFromSlice(prompts [][]acp.ContentBlock) iter.Seq[[]acp.ContentBlock]
PromptsFromSlice adapts a [][]ContentBlock into an iter.Seq[[]ContentBlock] for QueryStreamContent. Use when the full prompt list (multimodal or not) is already materialised.
func PromptsFromStrings ¶
func PromptsFromStrings(prompts []string) iter.Seq[[]acp.ContentBlock]
PromptsFromStrings adapts a []string into an iter.Seq[[]ContentBlock] suitable for QueryStreamContent. Each string becomes a single TextBlock prompt.
func QueryStream ¶
func QueryStream(ctx context.Context, prompts []string, opts ...Option) iter.Seq2[*QueryResult, error]
QueryStream runs a series of prompts against a single opencode session and yields one QueryResult per prompt in input order. The yielded sequence short-circuits on the first error; callers must drain or explicitly break out of the iterator.
The session, subprocess, and any registered SDK tools are torn down when the iterator goroutine returns (either naturally or via break). Cancelling ctx is the supported way to interrupt mid-stream.
For dynamic prompt generation (e.g. feeding prompts from a channel, or building multimodal prompts mid-flight) use QueryStreamContent.
func QueryStreamContent ¶
func QueryStreamContent(ctx context.Context, prompts iter.Seq[[]acp.ContentBlock], opts ...Option) iter.Seq2[*QueryResult, error]
QueryStreamContent is the iterator-backed, multimodal variant of QueryStream. It consumes an iterator of prompts — each prompt being a slice of content blocks — and runs each against the same opencode session, yielding one QueryResult per prompt.
Use the helper constructors to build the input iterator:
- PromptsFromStrings — static slice of text prompts
- PromptsFromSlice — static slice of multimodal prompts
- PromptsFromChannel — channel of prompts generated on the fly
- SinglePrompt — single-prompt iterator (useful for tests)
The yielded sequence short-circuits on the first error. The session, subprocess, and registered SDK tools are torn down when the iterator goroutine returns.
func RejectOnce ¶
func RejectOnce(_ context.Context, req acp.RequestPermissionRequest) (acp.RequestPermissionResponse, error)
RejectOnce selects the first "reject_once" option, falling back to reject_always then first.
func SaveSessionCost ¶
func SaveSessionCost(sessionID string, snap CostSnapshot, opts SessionCostOptions) error
SaveSessionCost persists a CostSnapshot for sessionID under opts.OpencodeHome. Exposed as a free function so callers who build snapshots outside of a tracker can still persist them.
func SimpleSchema ¶
SimpleSchema builds a minimal JSON-schema object from a field-name → type-string map. Supported type strings (case insensitive): "string", "int", "int64", "integer", "float", "float64", "number", "bool", "boolean", "[]string", "object", "any". Every listed field is marked required; for a looser shape, build the schema inline.
Example:
schema := opencodesdk.SimpleSchema(map[string]string{
"path": "string",
"recurse": "bool",
"limit": "int",
})
func SinglePrompt ¶
func SinglePrompt(blocks ...acp.ContentBlock) iter.Seq[[]acp.ContentBlock]
SinglePrompt returns an iter.Seq[[]ContentBlock] yielding exactly one prompt. Handy in tests and for symmetry with sister SDKs.
func WithClient ¶
WithClient manages a Client's lifecycle around a caller-supplied function. It constructs the client with the given options, runs [Client.Start], invokes fn with the ready client, and guarantees [Client.Close] on return regardless of how fn exits.
fn's error is returned verbatim. If Close itself fails, the error is logged via the client's logger but does not override fn's result. If fn is nil, WithClient returns an error immediately without starting a client.
Types ¶
type BudgetStatus ¶
type BudgetStatus struct {
// Cost is the backing CostSnapshot from the embedded CostTracker.
Cost CostSnapshot
// CompletionRatio is the fraction of the tightest cap consumed,
// in [0, +Inf). Zero when no caps are configured.
CompletionRatio float64
// NearCompletion is true once CompletionRatio crosses
// options.CompletionThreshold.
NearCompletion bool
// BudgetExceeded is true once any cap has been crossed.
BudgetExceeded bool
// Reason is a short machine-readable explanation: "within_budget",
// "near_completion", "budget_exceeded".
Reason string
// MaxCostUSD and MaxTotalTokens mirror the configured caps for
// display.
MaxCostUSD *float64
MaxTotalTokens *int
}
BudgetStatus summarises budget progress at a single point in time.
type BudgetTracker ¶
type BudgetTracker struct {
// contains filtered or unexported fields
}
BudgetTracker layers budget-enforcement heuristics over CostTracker. Safe for concurrent use.
Wiring:
budget, _ := opencodesdk.NewBudgetTracker(opencodesdk.BudgetTrackerOptions{
MaxCostUSD: opencodesdk.Float64Ptr(0.25),
})
sess.Subscribe(opencodesdk.UpdateHandlers{
Usage: budget.ObserveUsage(sess.ID()),
})
WithMaxBudgetUSD wires this automatically on every session created by a Client.
func NewBudgetTracker ¶
func NewBudgetTracker(o BudgetTrackerOptions) (*BudgetTracker, error)
NewBudgetTracker constructs a tracker from options.
func (*BudgetTracker) CheckBudget ¶
func (t *BudgetTracker) CheckBudget() error
CheckBudget returns ErrBudgetExceeded when any cap has been crossed. Returns nil otherwise. Useful inside observer callbacks to abort a loop once the budget is gone.
func (*BudgetTracker) CostTracker ¶
func (t *BudgetTracker) CostTracker() *CostTracker
CostTracker returns the underlying CostTracker for callers that want direct access (e.g. to persist snapshots via SaveSessionCost).
func (*BudgetTracker) ObserveNotification ¶
func (t *BudgetTracker) ObserveNotification(sessionID string, n acp.SessionNotification)
ObserveNotification records usage from any session/update notification (non-usage variants are ignored).
func (*BudgetTracker) ObservePromptResult ¶
func (t *BudgetTracker) ObservePromptResult(sessionID string, result *PromptResult)
ObservePromptResult merges usage from a PromptResult.
func (*BudgetTracker) ObserveUsage ¶
func (t *BudgetTracker) ObserveUsage(sessionID string) func(ctx context.Context, upd *acp.SessionUsageUpdate)
ObserveUsage returns a callback suitable for passing as UpdateHandlers.Usage on Session.Subscribe.
func (*BudgetTracker) Status ¶
func (t *BudgetTracker) Status() BudgetStatus
Status returns the current budget snapshot.
type BudgetTrackerOptions ¶
type BudgetTrackerOptions struct {
// MaxCostUSD caps the tracker's accumulated USD spend. When
// observed spend crosses this threshold, BudgetExceeded becomes
// true.
MaxCostUSD *float64
// MaxTotalTokens caps accumulated input+output+cached tokens
// across every session the tracker has observed. Useful when
// cost is not reliably reported (some providers omit pricing).
MaxTotalTokens *int
// CompletionThreshold is the ratio in (0, 1] at which
// NearCompletion flips on. Default: 0.90.
CompletionThreshold float64
}
BudgetTrackerOptions configures a BudgetTracker. Both caps are optional; when nil, the tracker records usage but never flags ShouldStop / ErrBudgetExceeded.
type CLINotFoundError ¶
type CLINotFoundError struct {
// SearchedPaths lists the candidate paths the SDK evaluated, in the
// order they were tried. At minimum this includes "$PATH" when no
// explicit WithCLIPath was supplied.
SearchedPaths []string
// Err is the underlying cause, if any (e.g. the exec.LookPath error).
Err error
}
CLINotFoundError is the typed companion to ErrCLINotFound. It records the paths the SDK searched while trying to locate the opencode binary so callers can produce an actionable diagnostic.
The error chain always includes ErrCLINotFound so `errors.Is(err, ErrCLINotFound)` works on both the typed and sentinel forms.
func (*CLINotFoundError) Error ¶
func (e *CLINotFoundError) Error() string
func (*CLINotFoundError) Is ¶
func (e *CLINotFoundError) Is(target error) bool
Is reports whether target is ErrCLINotFound. This lets callers write `errors.Is(err, ErrCLINotFound)` when they only care about the kind.
func (*CLINotFoundError) Unwrap ¶
func (e *CLINotFoundError) Unwrap() error
type Client ¶
type Client interface {
// Start spawns the opencode subprocess, wires stdio into the ACP
// protocol layer, and runs the initialize handshake. It must be
// called exactly once per Client.
Start(ctx context.Context) error
// Close terminates the subprocess and releases resources. It is
// idempotent and safe to call after Start failures.
Close() error
// Capabilities returns the agent capabilities negotiated during Start.
// Returns the zero value if called before Start.
Capabilities() acp.AgentCapabilities
// AgentInfo returns the agent identity (name + version) reported
// during Start.
AgentInfo() acp.Implementation
// AuthMethods returns the authentication methods the agent
// advertised during initialize. Inspect TerminalAuthInstructions
// on each method if you advertised _meta["terminal-auth"] via
// WithTerminalAuthCapability.
AuthMethods() []acp.AuthMethod
// NewSession creates a new opencode session. If WithModel or
// WithAgent are configured (either as client-level options passed
// to NewClient or as per-call options passed here), they are
// applied via session/set_config_option immediately after creation.
NewSession(ctx context.Context, opts ...Option) (Session, error)
// LoadSession rehydrates a previously-created session by ID.
// opencode replays the session's message history via session/update
// notifications before this method returns — callers that want to
// observe the replay should subscribe to the returned Session's
// Updates() channel before invoking further methods.
//
// Returns a typed error wrapping ErrAuthRequired if opencode cannot
// load the session's associated credentials.
LoadSession(ctx context.Context, id string, opts ...Option) (Session, error)
// LoadSessionHistory loads an existing session and captures the
// replay notifications opencode emits during session/load into a
// typed SessionHistory. Prefer this over LoadSession when the
// caller wants the full historical transcript as a slice rather
// than streaming replay via Updates().
//
// The returned Session is ready for further Prompt/Cancel calls;
// its Updates() channel carries only post-replay notifications.
LoadSessionHistory(ctx context.Context, id string, opts ...Option) (*SessionHistory, error)
// ListSessions enumerates sessions scoped to the configured cwd.
//
// opencode 1.14.20 paginates via a stringified page number ("0",
// "1", "2", …) rather than an opaque token. Pass empty string or
// "0" for the first page. Page size is fixed at 100. The returned
// nextCursor is the opaque echo from the agent; for opencode it is
// always either empty (last page) or the next page number — pass
// it back as-is to fetch the next page. Prefer IterSessions for
// transparent pagination.
ListSessions(ctx context.Context, cursor string) (sessions []SessionInfo, nextCursor string, err error)
// ForkSession creates a new session branched from an existing one
// (ACP's unstable `session/fork` RPC).
ForkSession(ctx context.Context, parentID string, opts ...Option) (Session, error)
// ResumeSession re-attaches to an existing session without the
// history-replay side effects of LoadSession (ACP's unstable
// `session/resume` RPC).
ResumeSession(ctx context.Context, sessionID string, opts ...Option) (Session, error)
// UnstableSetModel issues ACP's unstable `session/set_model` RPC
// directly. Prefer Session.SetModel for normal use.
UnstableSetModel(ctx context.Context, sessionID, modelID string) error
// IterSessions returns an iterator over every session the agent
// exposes in the configured cwd, paginating transparently via the
// cursor opencode returns. The iterator short-circuits on the first
// error. Prefer this over hand-rolling a ListSessions loop.
IterSessions(ctx context.Context) iter.Seq2[SessionInfo, error]
// CallExtension issues a raw JSON-RPC call for an ACP extension
// method. The method name must begin with an underscore per the
// ACP spec's extension convention. Returns the raw JSON response
// from the agent.
//
// Prefer the typed wrappers (ForkSession, ResumeSession,
// UnstableSetModel, etc.) when they cover the RPC you need. Use
// this only for opencode- or agent-specific extensions that the
// SDK does not yet expose.
CallExtension(ctx context.Context, method string, params any) (json.RawMessage, error)
// GetTransportHealth returns a snapshot of the transport-layer
// health observed so far. Cheap to call; intended for dashboards,
// liveness probes, and diagnostics.
GetTransportHealth() TransportHealth
// BudgetTracker returns the tracker installed via
// WithMaxBudgetUSD or WithBudgetTracker. Returns nil when no
// budget policy was configured.
BudgetTracker() *BudgetTracker
// CancelAll sends session/cancel to every live session owned by
// this Client. Returns a joined error when any individual cancel
// RPC fails (unaffected sessions are still signaled). ACP has no
// connection-level interrupt primitive; this is a client-side fan
// out over Session.Cancel, useful for coordinated shutdown or
// panic paths where the caller no longer tracks individual
// Session handles.
CancelAll(ctx context.Context) error
}
Client is a stateful, long-lived handle to an opencode acp subprocess. Obtain one with NewClient, then call Start to spawn the process and negotiate the ACP initialize handshake. Close when done.
type ContentBlock ¶
type ContentBlock = acp.ContentBlock
ContentBlock is the ACP content-block union used in prompt requests and streamed update payloads. Re-exported from coder/acp-go-sdk so callers don't need a direct dependency on the protocol package.
func AudioBlock ¶
func AudioBlock(data, mimeType string) ContentBlock
AudioBlock constructs an audio content block. Same capability guard applies as ImageBlock (PromptCapabilities.Audio).
func AudioFileInput ¶
func AudioFileInput(path string) (ContentBlock, error)
AudioFileInput reads an audio file from disk and returns an AudioBlock with its contents base64-encoded inline. The MIME type is inferred from the file extension; the final fallback is "application/octet-stream". Use AudioFileInputMime to force an explicit MIME type.
Requires the agent to advertise PromptCapabilities.Audio; the SDK rejects the block up front otherwise.
func AudioFileInputMime ¶
func AudioFileInputMime(path, mimeType string) (ContentBlock, error)
AudioFileInputMime is AudioFileInput with an explicit MIME type.
func Blocks ¶
func Blocks(blocks ...ContentBlock) []ContentBlock
Blocks returns a ContentBlock slice built from the supplied blocks. Purely cosmetic — equivalent to []ContentBlock{...} but reads more fluently at call sites:
blocks := opencodesdk.Blocks(
opencodesdk.TextBlock("what is in this image?"),
img,
)
func ImageBlock ¶
func ImageBlock(data, mimeType string) ContentBlock
ImageBlock constructs an image content block. The image bytes must be supplied as a base64-encoded string along with the MIME type (e.g. "image/png"). Prefer checking PromptCapabilities.Image before sending — Session.Prompt will reject image blocks if the agent did not advertise image support.
func ImageFileInput ¶
func ImageFileInput(path string) (ContentBlock, error)
ImageFileInput reads an image file from disk and returns an ImageBlock with its contents base64-encoded inline. The MIME type is inferred from the file extension (fallback: "application/octet-stream"). An explicit MIME type can be forced with ImageFileInputMime.
Prefer ImageBlock when the image data is already in memory.
func ImageFileInputMime ¶
func ImageFileInputMime(path, mimeType string) (ContentBlock, error)
ImageFileInputMime is ImageFileInput with an explicit MIME type. Useful when the file extension is missing or unreliable (e.g. a generic .bin). Empty mimeType falls back to extension-based detection; final fallback is "application/octet-stream".
func PDFFileInput ¶
func PDFFileInput(path string) (ContentBlock, error)
PDFFileInput reads a PDF from disk and returns an embedded-resource ContentBlock whose MIME type is "application/pdf". Gated by the agent's PromptCapabilities.EmbeddedContext at Prompt time.
func PathInput ¶
func PathInput(path string) (ContentBlock, error)
PathInput reads an arbitrary file from disk and returns the ContentBlock variant that matches its MIME type:
- image/* → ImageBlock (base64-encoded inline)
- audio/* → AudioBlock (base64-encoded inline)
- text/* → TextBlock with the file contents
- anything else → ResourceBlock with an inline blob
The MIME type is inferred from the file extension. For content where the extension is unreliable, use the type-specific helpers (ImageFileInputMime / AudioFileInputMime / ResourceFileInput).
PathInput is a convenience wrapper; it loads the file synchronously and holds the entire payload in memory.
func ResourceBlock ¶
func ResourceBlock(res acp.EmbeddedResourceResource) ContentBlock
ResourceBlock constructs an embedded-resource content block. The resource carries its body inline. Gated by PromptCapabilities.EmbeddedContext.
func ResourceLinkBlock ¶
func ResourceLinkBlock(name, uri string) ContentBlock
ResourceLinkBlock constructs a resource_link content block pointing at a named URI. No capability gate — resource links are always allowed.
func Text ¶
func Text(text string) []ContentBlock
Text wraps a string in a one-element ContentBlock slice suitable for passing directly to QueryContent / Session.Prompt. Mirrors the convenience constructor on sister claude/codex SDKs.
func TextBlock ¶
func TextBlock(text string) ContentBlock
TextBlock constructs a text content block. Forwards to acp.TextBlock so callers don't have to import the protocol package for the common case.
type CostSnapshot ¶
type CostSnapshot struct {
// TotalCostUSD is the aggregated monetary cost observed. Only
// USD-denominated costs are summed here; other currencies are
// captured in Currencies for visibility.
TotalCostUSD float64
// Currencies lists the distinct currency codes observed during
// aggregation. When all sessions are USD this contains just
// ["USD"].
Currencies []string
// Sessions is the number of distinct opencode session ids the
// tracker has observed.
Sessions int
// Token aggregates across sessions. Cached tokens and thought
// tokens are optional in ACP; opencode populates them when the
// model reports them.
InputTokens int
OutputTokens int
CachedReadTokens int
CachedWriteTokens int
ThoughtTokens int
TotalTokens int
// ContextWindowSize is the max context window reported across
// sessions (models differ; this is the largest seen).
ContextWindowSize int
// ContextWindowUsed is the sum of context-tokens-used reported
// across sessions. For a per-session snapshot this is the latest
// value.
ContextWindowUsed int
}
CostSnapshot is a point-in-time view of aggregated usage and cost either for a single opencode session (SessionSnapshot) or across every session the tracker has observed (Snapshot).
opencode emits SessionUsageUpdate notifications with CUMULATIVE per-session values. CostTracker tracks the latest per-session value; aggregate snapshots sum across sessions.
func LoadSessionCost ¶
func LoadSessionCost(sessionID string, opts SessionCostOptions) (*CostSnapshot, error)
LoadSessionCost reads a persisted snapshot from disk. Returns ErrSessionCostNotFound when no file exists.
type CostTracker ¶
type CostTracker struct {
// contains filtered or unexported fields
}
CostTracker accumulates per-session cost + usage across one or more opencode sessions. Safe for concurrent use.
Wiring:
tracker := opencodesdk.NewCostTracker()
sess.Subscribe(opencodesdk.UpdateHandlers{
Usage: tracker.ObserveUsage(sess.ID()),
})
Or for a whole-session callback that captures both token usage on UsageUpdate and the final-turn usage on PromptResult:
tracker.ObserveNotification(sess.ID(), n) tracker.ObservePromptResult(sess.ID(), result)
func NewCostTracker ¶
func NewCostTracker() *CostTracker
NewCostTracker constructs an empty tracker.
func (*CostTracker) LoadSessionCost ¶
func (t *CostTracker) LoadSessionCost(sessionID string, opts SessionCostOptions) error
LoadSessionCost reads a persisted snapshot into the tracker's in-memory state. The persisted data overrides any existing session record.
func (*CostTracker) ObserveNotification ¶
func (t *CostTracker) ObserveNotification(sessionID string, n acp.SessionNotification)
ObserveNotification records token + cost state from a session/update notification. Non-usage variants are ignored, so callers can pipe every notification through without filtering.
func (*CostTracker) ObservePromptResult ¶
func (t *CostTracker) ObservePromptResult(sessionID string, result *PromptResult)
ObservePromptResult merges token usage from a PromptResult. Cost is not carried in PromptResult — only in UsageUpdate notifications — so this path updates tokens without touching the cost total.
func (*CostTracker) ObserveUsage ¶
func (t *CostTracker) ObserveUsage(sessionID string) func(ctx context.Context, upd *acp.SessionUsageUpdate)
ObserveUsage returns a callback suitable for passing as UpdateHandlers.Usage. The returned callback records the cumulative values from every UsageUpdate for the supplied sessionID.
func (*CostTracker) SaveSessionCost ¶
func (t *CostTracker) SaveSessionCost(sessionID string, opts SessionCostOptions) error
SaveSessionCost writes the tracker's current snapshot for sessionID to disk. It is safe to call repeatedly — each call overwrites the previous file via an atomic rename.
func (*CostTracker) SessionSnapshot ¶
func (t *CostTracker) SessionSnapshot(sessionID string) (CostSnapshot, bool)
SessionSnapshot returns the latest cumulative snapshot for sessionID, or (zero, false) if the tracker has not observed it.
func (*CostTracker) Snapshot ¶
func (t *CostTracker) Snapshot() CostSnapshot
Snapshot returns an aggregate view across every observed session.
type Effort ¶
type Effort string
Effort selects an opencode model variant by reasoning depth. opencode encodes variants as a `/<variant>` suffix on the model id (e.g. "anthropic/claude-opus-4-7/high"); this enum maps abstract levels onto whatever variant strings the chosen model actually exposes.
The mapping is best-effort:
- EffortNone is preserved when the model exposes a "none" variant (the gpt-5.x family does); other models silently drop the option.
- EffortLow / EffortMedium / EffortHigh map to "low" / "medium" / "high" verbatim when present.
- EffortMax tries "max", then "xhigh", then "high" — falling back to whatever the model offers as its highest tier.
When the model exposes no variants at all (chat-only / embedding / TTS models), WithEffort is a silent no-op: the SDK logs a debug notice and keeps the unsuffixed model id. Callers who want stricter behaviour should inspect Session.CurrentVariant() after session creation.
Variant choice is not persisted in opencode's session DB. After LoadSession the SDK re-applies the configured Effort.
type ElicitMode ¶
type ElicitMode string
ElicitMode discriminates the two elicitation delivery modes defined by MCP. "form" renders a structured input form from RequestedSchema; "url" redirects the user to an external URL and resumes when the ElicitationCompleteNotification arrives.
const ( // ElicitModeForm requests a structured form response shaped by // ElicitParams.RequestedSchema. This is the default and the only // mode currently supported by opencode's MCP client. ElicitModeForm ElicitMode = "form" // ElicitModeURL asks the client to open ElicitParams.URL in a // browser. opencode may or may not honour this mode. ElicitModeURL ElicitMode = "url" )
type ElicitParams ¶
type ElicitParams struct {
// Message is the human-readable prompt displayed to the user.
Message string
// Mode selects between form and url delivery. Empty defaults to
// form.
Mode ElicitMode
// RequestedSchema is a JSON Schema describing the form fields
// expected in the response. Only consulted for form mode.
RequestedSchema map[string]any
// URL is the external URL to open when Mode is url.
URL string
// ElicitationID is an opaque token correlating this request with
// its completion notification. Optional for form mode; required
// for url mode.
ElicitationID string
// Meta passes arbitrary extensibility data through as the MCP
// `_meta` block.
Meta map[string]any
}
ElicitParams is the request a tool sends back through the MCP bridge to ask opencode's user a question. Exactly one of RequestedSchema (for form mode) or URL (for url mode) should be populated.
type ElicitResult ¶
type ElicitResult struct {
// Action is "accept", "decline", or "cancel".
Action string
// Content is the user-supplied form data. Populated when Action
// is "accept" and Mode was form.
Content map[string]any
// Meta mirrors the `_meta` block from the MCP response.
Meta map[string]any
}
ElicitResult is the response the MCP client produced. Action is one of "accept" (user provided Content), "decline" (user refused the prompt), or "cancel" (user dismissed the prompt without answering).
func Elicit ¶
func Elicit(ctx context.Context, params ElicitParams) (*ElicitResult, error)
Elicit sends an MCP elicitation request back to opencode from within a Tool.Execute invocation. The ctx MUST be the same ctx the SDK passed into Execute — it carries the bridge-bound MCP session used to deliver the request.
Returns ErrElicitationUnavailable when the SDK cannot locate a bound session (e.g. Elicit is called outside a Tool handler, or WithSDKTools was not configured).
This is a thin wrapper over modelcontextprotocol/go-sdk's ServerSession.Elicit. If opencode's MCP client implementation does not support elicitation, the call fails with a JSON-RPC error surfaced as a normal Go error.
Example usage inside a tool:
func (t *myTool) Execute(ctx context.Context, in map[string]any) (opencodesdk.ToolResult, error) {
resp, err := opencodesdk.Elicit(ctx, opencodesdk.ElicitParams{
Message: "Proceed with the destructive migration?",
RequestedSchema: opencodesdk.SimpleSchema(map[string]string{
"confirm": "string",
}),
})
if err != nil {
return opencodesdk.ErrorResult("could not ask user"), nil
}
if resp.Action != "accept" || resp.Content["confirm"] != "yes" {
return opencodesdk.TextResult("aborted by user"), nil
}
// proceed…
}
type ElicitationCallback ¶
type ElicitationCallback func(ctx context.Context, req acp.UnstableCreateElicitationRequest) (acp.UnstableCreateElicitationResponse, error)
ElicitationCallback is invoked when the agent issues a `elicitation/create` request (agent → client). The callback returns the user's response: accept with content, decline, or cancel.
This is the agent-initiated counterpart to the tool-side Elicit helper: Elicit lets a Tool ask opencode's MCP client for input, whereas this callback receives requests originating from opencode itself via the unstable ACP `elicitation/create` method.
opencode 1.14.20 does NOT currently emit elicitation/create over ACP — the schema reserves this under the unstable namespace. Wiring this callback is forward-compatible: when opencode (or another ACP agent) starts emitting it, the existing callback handles it. Until then the callback never fires and costs nothing.
If ctx is cancelled the callback MUST return promptly. Returning a non-nil error surfaces as a JSON-RPC error to the agent; prefer returning a structured Decline outcome if the user simply refused.
type ElicitationCompleteCallback ¶
type ElicitationCompleteCallback func(ctx context.Context, params acp.UnstableCompleteElicitationNotification)
ElicitationCompleteCallback is invoked when the agent sends an `elicitation/complete` notification (agent → client, no response expected). opencode uses this to signal that a URL-mode elicitation (where the client opens a browser) has finished on the agent side.
Notification-only: the callback's return path has no effect on the agent. Errors are logged by the SDK but not propagated.
type ErrorClass ¶
type ErrorClass string
ErrorClass is the coarse classification bucket for a failure the SDK surfaces. Parity with the claude/codex sister SDKs; the opencode taxonomy drops a few claude-specific classes that don't map to the ACP transport (compaction, max_output_tokens, etc.).
const ( ErrorClassUnknown ErrorClass = "unknown" ErrorClassAuthentication ErrorClass = "authentication" ErrorClassRateLimit ErrorClass = "rate_limit" ErrorClassOverload ErrorClass = "overload" ErrorClassCancelled ErrorClass = "cancelled" ErrorClassTransientConnection ErrorClass = "transient_connection" ErrorClassCapability ErrorClass = "capability" ErrorClassCLI ErrorClass = "cli" ErrorClassExecution ErrorClass = "execution" )
type ErrorClassification ¶
type ErrorClassification struct {
// Class is the coarse bucket.
Class ErrorClass
// SubClass is a finer-grained diagnostic bucket. ErrorSubClassNone
// when the classifier found no recognisable signal.
SubClass ErrorSubClass
// RecoveryAction is the suggested next step.
RecoveryAction RecoveryAction
// Retryable reports whether ResilientQuery would retry.
Retryable bool
// HTTPStatus is the JSON-RPC error code when the root cause is a
// *RequestError, or nil otherwise.
HTTPStatus *int
// Message is the human-readable failure message the classifier
// inspected.
Message string
}
ErrorClassification is the result of ClassifyError. Fields are best effort: HTTPStatus is populated when the failure is ultimately a *RequestError from the ACP transport.
func ClassifyError ¶
func ClassifyError(err error) ErrorClassification
ClassifyError inspects err and returns a best-effort ErrorClassification. Returns ErrorClassUnknown when err is nil or defies matching.
type ErrorSubClass ¶
type ErrorSubClass string
ErrorSubClass refines ErrorClass with a more specific diagnostic bucket for failures whose coarse class doesn't fully describe the remediation. Empty by default; populated only when the classifier finds a recognisable signal in the message or JSON-RPC code.
Subclass is advisory: existing callers that match on ErrorClass alone continue to work unchanged. Resilience wrappers may use the subclass to pick targeted retry strategies (e.g. strip media on PromptTooLong rather than back-off).
const ( // ErrorSubClassNone is the zero value — no finer classification. ErrorSubClassNone ErrorSubClass = "" // ErrorSubClassPromptTooLong indicates the prompt (or accumulated // context) exceeded the model's context window. Parity with // claude's PromptTooLongDetails. Not retryable without mutating // the prompt (strip media, compact history, switch model). ErrorSubClassPromptTooLong ErrorSubClass = "prompt_too_long" // ErrorSubClassRateLimitTokens indicates a token-per-minute cap was // hit, as opposed to requests-per-minute. ErrorSubClassRateLimitTokens ErrorSubClass = "rate_limit_tokens" // ErrorSubClassRateLimitRequests indicates a requests-per-minute // cap was hit. ErrorSubClassRateLimitRequests ErrorSubClass = "rate_limit_requests" // ErrorSubClassInvalidSchema indicates the agent reported malformed // params (JSON-RPC -32602 / "expected array, received null" / // "invalid_schema"). Typically not retryable; the caller must // correct the payload. ErrorSubClassInvalidSchema ErrorSubClass = "invalid_schema" // ErrorSubClassInvalidModel indicates the supplied model id was // not recognised. Typically surfaces from WithModel / SetModel. ErrorSubClassInvalidModel ErrorSubClass = "invalid_model" // ErrorSubClassProviderError indicates the upstream model provider // returned an opaque failure (not rate-limit, not overload). Often // retryable with back-off but may also be a permanent provider // issue. ErrorSubClassProviderError ErrorSubClass = "provider_error" // ErrorSubClassSubprocessDied indicates the opencode subprocess // exited unexpectedly mid-RPC. The client is degraded; retry // requires a new Client. ErrorSubClassSubprocessDied ErrorSubClass = "subprocess_died" )
type FsWriteCallback ¶
type FsWriteCallback func(ctx context.Context, req acp.WriteTextFileRequest) error
FsWriteCallback is invoked when opencode delegates a file write via fs/write_text_file. opencode emits this after an approved edit to sync client buffers with on-disk state. Return a non-nil error to refuse the write (opencode surfaces the failure to the agent).
When no callback is configured the SDK's default behavior is to write the file through (with absolute-path enforcement and parent directory creation).
type HistoryMessage ¶
type HistoryMessage struct {
// Role is either "user", "assistant", or "thought". Derived from
// the notification variant (UserMessageChunk / AgentMessageChunk /
// AgentThoughtChunk).
Role string
// Text is the concatenated text content of the message. Non-text
// content blocks (image, audio, embedded resource) are ignored when
// building Text — consult the Notifications field on SessionHistory
// for the raw payload.
Text string
}
HistoryMessage is a typed view of a replayed session message, extracted from the session/update notifications that opencode emits during session/load.
type HookCallback ¶
type HookCallback func(ctx context.Context, input HookInput) (HookOutput, error)
HookCallback is the callback signature for every hook. The returned HookOutput is ignored for notification-only events; for blocking events the first hook to return Continue=false wins (the SDK short-circuits subsequent hooks for the same event).
If the callback returns a non-nil error, the event is treated as blocked (for blocking-capable events) or logged (for notification events). The error does NOT propagate up through the SDK call that triggered the hook except via the blocking pathway.
type HookEvent ¶
type HookEvent string
HookEvent is the discriminator for a registered hook. Each event maps to a specific point in the SDK's lifecycle; see the constants below for the supported set.
const ( // HookEventPreToolUse fires when opencode announces a tool call // via a session/update ToolCall notification. Notification-only // in opencode: the agent has already decided to run the tool by // the time the SDK sees it. Use WithCanUseTool or // HookEventPermissionRequest if you need to BLOCK a tool before // execution (requires opencode's permission ruleset to "ask"). HookEventPreToolUse HookEvent = "pre_tool_use" // HookEventPostToolUse fires after a tool call transitions to // status=completed via ToolCallUpdate. HookEventPostToolUse HookEvent = "post_tool_use" // HookEventPostToolUseFailure fires after a tool call transitions // to status=failed via ToolCallUpdate. HookEventPostToolUseFailure HookEvent = "post_tool_use_failure" // HookEventUserPromptSubmit fires as the first step of // Session.Prompt, before the request is sent to opencode. // Returning HookOutput{Continue:false} aborts the prompt with an // error wrapping Reason. HookEventUserPromptSubmit HookEvent = "user_prompt_submit" // HookEventStop fires after Session.Prompt returns successfully. HookEventStop HookEvent = "stop" // HookEventStopFailure fires after Session.Prompt returns an // error. HookEventStopFailure HookEvent = "stop_failure" // HookEventSessionStart fires after a session is created (or // loaded/forked/resumed) and fully configured. HookEventSessionStart HookEvent = "session_start" // HookEventSessionEnd fires when a session is closed, either via // explicit teardown or via Client.Close. HookEventSessionEnd HookEvent = "session_end" // HookEventPermissionRequest fires at the entry of the // session/request_permission callback path, before the // PermissionCallback runs. Returning Continue=false synthesises a // "reject" response — useful for declarative tool blocking. HookEventPermissionRequest HookEvent = "permission_request" // HookEventPermissionDenied fires after the permission callback // returns a reject or cancelled outcome. HookEventPermissionDenied HookEvent = "permission_denied" // HookEventFileChanged fires as the first step of the // fs/write_text_file delegation path, before the FsWriteCallback // runs. Returning Continue=false refuses the write (the error // surfaces to the agent). HookEventFileChanged HookEvent = "file_changed" )
Hook event constants, parity-shaped with claude/codex. Only events with a real opencode backend signal are defined — claude events that don't map (e.g. compaction, subagent, task) are intentionally omitted.
type HookInput ¶
type HookInput struct {
// Event is the hook event. Always set.
Event HookEvent
// SessionID is the opencode session id, or empty for pre-session
// events.
SessionID string
// ToolCall is populated for PreToolUse.
ToolCall *acp.SessionUpdateToolCall
// ToolCallUpdate is populated for PostToolUse and
// PostToolUseFailure.
ToolCallUpdate *acp.SessionToolCallUpdate
// PromptText is populated for UserPromptSubmit and carries the
// concatenated text of every TextBlock in the outgoing prompt.
PromptText string
// PromptResult is populated for Stop.
PromptResult *PromptResult
// PromptError is populated for StopFailure.
PromptError error
// PermissionRequest is populated for PermissionRequest and
// PermissionDenied.
PermissionRequest *acp.RequestPermissionRequest
// PermissionResponse is populated for PermissionDenied with the
// response that triggered the denial.
PermissionResponse *acp.RequestPermissionResponse
// FileWrite is populated for FileChanged.
FileWrite *acp.WriteTextFileRequest
}
HookInput is the discriminated payload delivered to each hook callback. The Event field determines which other pointer fields are populated.
type HookMatcher ¶
type HookMatcher struct {
// Matcher filters which events the hooks run for. Nil matches all.
Matcher *regexp.Regexp
// Hooks is the list of callbacks to invoke for matching events,
// in order.
Hooks []HookCallback
// Timeout caps each callback's execution time. Zero means no
// SDK-imposed timeout (ctx.Deadline still applies).
Timeout time.Duration
// Once causes the matcher to fire at most once across the client
// lifetime. Useful for setup hooks.
Once bool
// contains filtered or unexported fields
}
HookMatcher is a set of callbacks registered for a single event, optionally filtered by a regex match against an event-specific primary string:
- tool events: match against ToolCall.Title
- prompt events: match against PromptText (UserPromptSubmit) or session id (Stop, StopFailure)
- session events: match against session id
- permission events: match against the tool title in PermissionRequest.ToolCall.Title
- file events: match against the absolute path being written
A nil Matcher matches all events.
type HookOutput ¶
type HookOutput struct {
// Continue=false blocks the triggering action on events that
// support blocking (UserPromptSubmit, PermissionRequest,
// FileChanged). Defaults to true.
Continue bool
// Reason is the human-readable explanation for a block. Surfaced
// to the agent as part of the rejection response or as an error
// message on the outgoing RPC.
Reason string
// SuppressOutput is a UI hint indicating that any log/trace
// output for this event should be hidden. The SDK itself does
// not drop anything — consumers implementing their own logging
// should honour the flag.
SuppressOutput bool
}
HookOutput is the result of a hook callback. For notification-only events the fields are ignored; for blocking-capable events (UserPromptSubmit, PermissionRequest, FileChanged) Continue=false blocks the triggering action and Reason is surfaced to the agent or the caller.
func HookAllow ¶
func HookAllow() HookOutput
allow returns a permissive HookOutput for the common case where a hook wants to do work but not block. Convenience constructor to reduce boilerplate in callback bodies.
func HookBlock ¶
func HookBlock(reason string) HookOutput
HookBlock returns a blocking HookOutput with the supplied reason.
type ListModelsResponse ¶
type ListModelsResponse struct {
// Models is the full list of models the opencode agent currently
// advertises for the configured cwd/credentials.
Models []ModelInfo
// CurrentModelID is the id opencode would pick by default if no
// WithModel override were supplied. Empty when opencode did not
// report a default.
CurrentModelID string
}
ListModelsResponse is the aggregate response shape returned by ListModels. It mirrors the claude/codex SDKs so callers can write provider-agnostic model-discovery code.
func ListModelsResponseFor ¶
func ListModelsResponseFor(ctx context.Context, opts ...Option) (*ListModelsResponse, error)
ListModelsResponseFor is the long-form variant of ListModels that also returns the agent's default model id.
type ListSessionsOptions ¶
type ListSessionsOptions struct {
// IncludeArchived, when true, returns sessions with a non-nil
// ArchivedAt alongside live ones. Default false.
IncludeArchived bool
// Limit, when > 0, caps the number of rows returned. Zero means
// no limit.
Limit int
}
ListSessionsOptions tunes the behaviour of the top-level ListSessions. The zero value lists every non-archived session in opencode's local store, newest-updated first.
type ModalityCapabilities ¶ added in v0.0.3
type ModalityCapabilities struct {
Text, Audio, Image, Video, PDF bool
}
ModalityCapabilities enumerates the content kinds a model can handle on a single side (input or output).
type ModelCapabilities ¶ added in v0.0.3
type ModelCapabilities struct {
// ProviderID is the provider key ("lmstudio", "anthropic", …).
ProviderID string
// ModelID is the model key within the provider ("qwen/qwen3.6-27b").
ModelID string
// Name is the human-readable model name opencode advertises.
Name string
// Temperature reports whether the model honors a sampling-temperature
// parameter.
Temperature bool
// Reasoning reports whether opencode will request a reasoning /
// thinking channel from this model and surface the chunks as
// [UpdateHandlers.AgentThought] notifications.
Reasoning bool
// Toolcall reports whether the model supports native function /
// tool calling.
Toolcall bool
// Attachment reports whether prompts to this model may include
// non-text content blocks (image / audio / file).
Attachment bool
// Interleaved reports whether the model supports interleaved
// thinking (reasoning chunks alternating with content chunks).
Interleaved bool
// Input is the set of modalities the model accepts.
Input ModalityCapabilities
// Output is the set of modalities the model emits.
Output ModalityCapabilities
// ContextLimit is the total token window, or 0 when unknown.
ContextLimit int
// OutputLimit is the max tokens per response, or 0 when unknown.
OutputLimit int
}
ModelCapabilities describes per-model feature flags as opencode computes them (from models.dev metadata for known providers, from `opencode.json` for custom providers). ACP's model catalogue does not transmit these; ListModelCapabilities fetches them via `opencode serve`'s HTTP API.
type ModelInfo ¶
ModelInfo is a re-export of acp.ModelInfo. opencode advertises its available model catalogue through the session/new lifecycle response; callers who want a one-shot enumeration without managing a Session can use ListModels below.
func ListModels ¶
ListModels is a one-shot helper that spawns an opencode acp subprocess, opens a throw-away session to read its advertised model catalogue, and tears everything down. All Options supplied to NewClient are honoured (cwd, env, logger, cli path, etc.).
Returns an empty slice (no error) when opencode advertises no models — this happens for agents that haven't finished loading credentials. Wrap with a retry if that matters.
type NewToolOption ¶
type NewToolOption func(*toolConfig)
NewToolOption configures an optional field on a Tool constructed via NewTool.
func WithToolAnnotations ¶
func WithToolAnnotations(ann ToolAnnotations) NewToolOption
WithToolAnnotations attaches ToolAnnotations to a tool registered via NewTool. The SDK forwards the annotations through its loopback MCP bridge so opencode sees them on tools/list.
Example:
t := opencodesdk.NewTool(
"read_file", "...", schema, fn,
opencodesdk.WithToolAnnotations(opencodesdk.ToolAnnotations{
Title: "Read file",
ReadOnlyHint: true,
OpenWorldHint: opencodesdk.BoolPtr(false),
}),
)
type OpencodeSDKError ¶
type OpencodeSDKError interface {
error
// contains filtered or unexported methods
}
OpencodeSDKError is the marker interface implemented by every typed error constructed by opencodesdk. Callers can use errors.As against this interface to distinguish SDK-originated errors from arbitrary Go errors flowing through the same code path without caring about the specific variant.
var sdkErr opencodesdk.OpencodeSDKError
if errors.As(err, &sdkErr) {
// err originated from opencodesdk and carries SDK semantics.
}
type Option ¶
type Option func(*options)
Option configures a Client or a one-shot Query. Options are applied with the functional options pattern: call NewClient(WithCwd(...), ...) or Query(ctx, "hi", WithModel("..."), ...).
func WithAddDirs ¶
WithAddDirs appends additional workspace root directories activated for every session created on this Client. Paths must be absolute.
This forwards to ACP's unstable additionalDirectories field on session/new, session/load, session/fork, and session/resume. It requires the agent to advertise SessionCapabilities.AdditionalDirectories during initialize — when unsupported, the values are ignored and a warning is logged at session-creation time.
Additional per-call entries can be supplied via WithAddDirs as a per-session option override; they extend the Client-level defaults.
func WithAgent ¶
WithAgent selects the opencode agent (a.k.a. session mode) used by new sessions. Valid values map to opencode's agent names — typical defaults are "build", "plan", "general", "explore", "summarize". Applied via session/set_config_option immediately after session/new.
To drive session/request_permission through WithCanUseTool, the user must configure explicit "ask" rules in their opencode.json (see the WithCanUseTool doc). The built-in plan agent denies edits inline rather than asking, so it does not route through the callback path.
WithInitialMode is an alias for this option using ACP terminology ("mode" rather than "agent"). Prefer whichever wording matches the vocabulary already used by your codebase.
func WithAllowedTools ¶
WithAllowedTools names opencode tools that the SDK should auto-approve without invoking the WithCanUseTool callback. Names are matched against acp.ToolCall.Title (opencode emits the tool name there — e.g. "edit", "bash", "read", "write"). Unknown names match nothing.
opencode only emits session/request_permission for tools whose own permission ruleset resolves to "ask" (see WithCanUseTool). WithAllowedTools filters that ask-list further:
- Tool in allow list → pick the first allow_once option and skip the WithCanUseTool callback entirely.
- Tool in disallow list (set via WithDisallowedTools) → pick the first reject_once option. Disallow wins ties.
- Tool in neither list → delegate to WithCanUseTool, or the default dispatcher behavior (auto-reject with warning) if no callback was set.
Multiple calls accumulate. Matching is exact and case-sensitive — pass the opencode tool name as it appears in session/request_permission.
Sister SDK parity: mirrors claude-agent-sdk-go's WithAllowedTools and codex-agent-sdk-go's WithAllowedTools.
func WithAutoLaunchLogin ¶
WithAutoLaunchLogin enables automatic relaunch of the terminal-auth command when opencode reports authRequired (-32000). The SDK spawns the command parsed from the auth method's _meta["terminal-auth"] block with stdio inherited from the parent process, waits for it to exit, then retries the failing session/new or session/load once.
Requires WithTerminalAuthCapability(true) so opencode actually advertises launch instructions. Default: false.
func WithBudgetTracker ¶
func WithBudgetTracker(t *BudgetTracker) Option
WithBudgetTracker installs a caller-supplied BudgetTracker on the Client. Every session created by the Client is auto-subscribed to feed the tracker, but unlike WithMaxBudgetUSD the SDK does NOT auto-cancel sessions — the caller is responsible for acting on tracker.Status() or CheckBudget().
Useful when the caller wants a pre-populated tracker (e.g. restored from persisted CostTracker state) or a token-cap-only policy.
func WithCLIFlags ¶
WithCLIFlags appends extra flags to the `opencode acp` invocation. The SDK always passes `--hostname 127.0.0.1 --port 0` to keep opencode's internal REST server on loopback; those are not overridable.
func WithCLIPath ¶
WithCLIPath pins the path to the opencode binary. If not set, the SDK looks up `opencode` in $PATH.
func WithCanUseTool ¶
func WithCanUseTool(cb PermissionCallback) Option
WithCanUseTool registers a callback for session/request_permission. If unset, the SDK auto-rejects every permission request and logs a warning — opencode surfaces this to the agent as tool rejection.
Important: opencode only emits session/request_permission when its own permission ruleset resolves to "ask" for the tool. The out-of- the-box opencode config has "*": "allow", so no callbacks fire until the user sets explicit rules in their opencode.json, e.g.:
{
"permission": {
"edit": "ask",
"write": "ask",
"bash": "ask"
}
}
The plan agent has its own ruleset that denies edits inline (no ask), so permission prompts from plan mode are not reachable via this callback either.
func WithCwd ¶
WithCwd sets the working directory for the opencode subprocess and the default `cwd` sent with session/new. Absolute paths are required.
func WithDisallowedTools ¶
WithDisallowedTools names opencode tools that the SDK should auto-reject without invoking the WithCanUseTool callback. See WithAllowedTools for the filter semantics. Disallow entries win over allow entries for the same name.
Sister SDK parity: mirrors claude-agent-sdk-go's WithDisallowedTools and codex-agent-sdk-go's WithDisallowedTools.
func WithEffort ¶
WithEffort selects a model variant by reasoning depth. See Effort.
When the caller's WithModel value already carries a `/variant` suffix (e.g. "anthropic/claude-opus-4-7/high"), the explicit suffix wins and WithEffort is ignored — the caller has already pinned a variant and the SDK does not second-guess it.
Applied at session creation: the SDK probes opencode for the model's available variants via session/set_model with the bare model id, then re-applies session/set_model with the chosen `<base>/<variant>`. The probe round-trip happens once per session (NewSession, LoadSession, ForkSession, ResumeSession).
func WithEnv ¶
WithEnv provides additional environment variables for the opencode subprocess. The SDK inherits os.Environ() by default and overlays these values (later entries win).
Useful opencode env toggles:
- OPENCODE_ENABLE_QUESTION_TOOL=1 enables opencode's interactive "question" tool (disabled by default). When set, the agent may call the tool to route free-form questions back to the client, which the SDK surfaces through session/request_permission.
func WithExtraArgs ¶
WithExtraArgs is a map-shaped sister of WithCLIFlags for callers who want to pass `--flag` or `--flag=value` entries by name. Each map entry is rendered as one argv token: a nil value yields `--<name>` (a bare boolean flag), a non-nil value yields `--<name>=<value>`.
Map iteration order is randomised by Go's runtime — callers that care about the order of identical flags should use WithCLIFlags instead. WithExtraArgs is additive: subsequent calls accumulate.
Mirrors the same option on the sister claude/codex SDKs.
func WithHooks ¶
func WithHooks(hooks map[HookEvent][]*HookMatcher) Option
WithHooks registers a set of hook matchers. Multiple WithHooks calls merge: each event's matcher list is appended.
Example — log every tool that is about to run, and block writes to /etc:
opencodesdk.WithHooks(map[opencodesdk.HookEvent][]*opencodesdk.HookMatcher{
opencodesdk.HookEventPreToolUse: {{
Hooks: []opencodesdk.HookCallback{
func(ctx context.Context, in opencodesdk.HookInput) (opencodesdk.HookOutput, error) {
slog.InfoContext(ctx, "tool", "name", in.ToolCall.Title)
return opencodesdk.HookAllow(), nil
},
},
}},
opencodesdk.HookEventFileChanged: {{
Matcher: regexp.MustCompile(`^/etc/`),
Hooks: []opencodesdk.HookCallback{
func(_ context.Context, _ opencodesdk.HookInput) (opencodesdk.HookOutput, error) {
return opencodesdk.HookBlock("refusing to write under /etc"), nil
},
},
}},
})
func WithInitialMode ¶
WithInitialMode is ACP-terminology sugar for WithAgent. Pass one of the ModeBuild / ModePlan constants (or any other mode id advertised under the session's `mode` config option) to select the session's starting mode. Applied via session/set_config_option immediately after session/new.
Exactly equivalent to WithAgent — the two names exist so callers who think in ACP's "mode" vocabulary and callers who think in opencode's "agent" vocabulary both find the option they expect. When both are supplied, the later one wins.
func WithInitializeTimeout ¶
WithInitializeTimeout caps how long Start waits for the ACP initialize handshake. Default: 60s.
func WithLogger ¶
WithLogger sets the structured logger the SDK uses for diagnostics. If not set, the SDK is silent.
func WithMCPServers ¶
WithMCPServers declares external MCP servers to attach to every new session. To expose in-process Go tools to the agent, use WithSDKTools (which lands in M6).
func WithMaxBudgetUSD ¶
WithMaxBudgetUSD caps total USD spend observed across every session on the owning Client. The SDK installs a BudgetTracker, auto- subscribes each new session to its UsageUpdate stream, and — when the cap is crossed — calls Session.Cancel on the in-flight turn. Subsequent Session.Prompt calls return a wrapped ErrBudgetExceeded.
The tracker is accessible via Client.BudgetTracker() for callers that want to inspect the running totals or near-completion state.
Caveats:
- Budget observation is cumulative across all sessions on the Client. Each NewClient starts a fresh tally.
- Cost is reported by opencode's provider layer; when a provider omits pricing, the USD cap has no effect. Use WithBudgetTracker + MaxTotalTokens for providers without pricing metadata.
- Cancellation is best-effort: an in-flight Prompt observes ErrCancelled (wrapped with ErrBudgetExceeded) but a turn that has already emitted its final response lands normally.
func WithMaxTurns ¶
WithMaxTurns caps the number of agent turns observed on each session created by the Client. opencode has no protocol-level turn limit, so the cap is enforced client-side: every assistant_message_chunk notification with start==true bumps a counter, and once the limit is crossed the SDK calls Session.Cancel on the in-flight turn. Subsequent Prompt calls on the same session run normally (opencode itself does not track the cap).
A value of 0 (the default) disables the cap. Counts are per-session, not per-Client. Useful as a backstop against runaway agent loops.
func WithMeterProvider ¶
func WithMeterProvider(mp metric.MeterProvider) Option
WithMeterProvider sets the OTel MeterProvider for SDK metrics. When nil, the OTel global provider is used (which is a noop unless the application has installed one).
func WithModel ¶
WithModel selects the model used by new sessions. The value must match one of the options exposed by opencode in the session/new configOptions (e.g. "anthropic/claude-sonnet-4-6" or "anthropic/claude-sonnet-4/high"). Applied via session/set_config_option immediately after session/new.
func WithOnElicitation ¶
func WithOnElicitation(cb ElicitationCallback) Option
WithOnElicitation registers a callback for agent-initiated elicitation/create requests. Leave unset if the agent you target does not issue them (opencode 1.14.20 does not).
When unset the SDK returns a Decline response automatically so the agent gracefully recovers rather than blocking on a missing handler.
func WithOnElicitationComplete ¶
func WithOnElicitationComplete(cb ElicitationCompleteCallback) Option
WithOnElicitationComplete registers a callback for elicitation/complete notifications. Notification-only; errors from the callback do not surface to the agent.
func WithOnFsWrite ¶
func WithOnFsWrite(cb FsWriteCallback) Option
WithOnFsWrite registers a callback for fs/write_text_file delegations. If unset, the SDK writes the file to disk.
opencode does NOT use fs/write_text_file as its primary write path — the built-in write and edit tools write directly to the local filesystem via Node fs. fs/write_text_file is a secondary sync notification opencode sends after an approved "edit" permission, so editor clients (VS Code, Zed, …) can update their in-memory buffer. That means this callback only fires after:
- opencode's ruleset is configured with permission.edit = "ask" (see WithCanUseTool for config example), and
- the WithCanUseTool callback allows the edit.
The write has already happened on opencode's side by the time this callback runs; returning an error from it does not undo the write, it only surfaces the error back over JSON-RPC.
func WithOnTurnComplete ¶
func WithOnTurnComplete(cb TurnCompleteCallback) Option
WithOnTurnComplete registers a callback that fires after every Session.Prompt completes, whether it succeeded or errored. Useful for centralised logging, metrics, or pushing the final assistant message into an external store without wrapping every call site.
The callback runs synchronously after Prompt returns to its caller. Long-running work should be dispatched off the callback goroutine.
func WithOnUpdateDropped ¶
func WithOnUpdateDropped(cb UpdateDroppedCallback) Option
WithOnUpdateDropped registers a callback invoked whenever a session/update notification is dropped because the Session.Updates() buffer was full. The callback receives the session ID and the new cumulative drop count.
Use this to detect that the consumer of Updates() is falling behind — consider increasing WithUpdatesBuffer or offloading the drain loop to a goroutine.
func WithOnUserInput ¶
func WithOnUserInput(cb UserInputCallback) Option
WithOnUserInput registers a callback that handles AskUserQuestion invocations from the agent. When set, the SDK registers an implicit in-process MCP tool named AskUserQuestion via the loopback bridge (the same path WithSDKTools uses) so the agent can ask the user structured, multi-option clarifying questions and receive typed answers.
Example:
cb := func(ctx context.Context, req *opencodesdk.UserInputRequest) (*opencodesdk.UserInputResponse, error) {
answers := map[string]*opencodesdk.UserInputAnswer{}
for _, q := range req.Questions {
if len(q.Options) > 0 {
answers[q.ID] = &opencodesdk.UserInputAnswer{Answers: []string{q.Options[0].Label}}
}
}
return &opencodesdk.UserInputResponse{Answers: answers}, nil
}
c, _ := opencodesdk.NewClient(opencodesdk.WithOnUserInput(cb))
The tool cannot coexist with a user-supplied WithSDKTools entry of the same name; Client.Start returns an error when both are registered.
func WithOpencodeHome ¶
WithOpencodeHome overrides the XDG_DATA_HOME-derived data directory opencode uses for session storage, credentials, and persisted SDK artifacts (e.g. session-cost snapshots from CostTracker). The path is exported to the subprocess as $XDG_DATA_HOME so opencode picks it up on launch, and the SDK uses it as the base for LoadSessionCost / SaveSessionCost.
Useful for test isolation and for running multiple opencode environments side by side.
func WithOutputSchema ¶
WithOutputSchema requests structured JSON output matching schema.
Enforcement mechanism (matches opencode's JS-SDK PR #8161 and Claude Code's approach): when set, the SDK registers an implicit MCP tool named StructuredOutput with schema as its input schema via the loopback bridge. The model's provider (Anthropic, OpenAI, etc.) validates tool_use inputs against that schema at the API boundary, so any tool call opencode routes back to the SDK is shape-guaranteed. Session.Prompt also prepends a system-style instruction block telling the model to deliver its final answer by calling StructuredOutput exactly once. The captured payload is surfaced via PromptResult.Meta["structuredOutput"] and on QueryResult.Notifications so DecodeStructuredOutput[T] returns it at priority 0.
schema may be either form:
- The bare JSON Schema object, e.g. {"type": "object", "properties": {...}}.
- The provider-agnostic envelope used by Claude Code / Codex and by opencode's JS SDK session.prompt format: {"type": "json_schema", "schema": {...}}. The SDK unwraps this automatically so callers can pass the same value to claude-agent-sdk-go, codex-agent-sdk-go, and this SDK without adapter shims.
See SimpleSchema for the common bare-object case. The SDK also embeds the inner schema in session/new's _meta["structuredOutputSchema"] for downstream consumers; opencode itself does not enforce the meta-level hint. Pass nil (or an envelope with no inner schema) to clear any previously set schema.
Known gaps vs. opencode's JS-SDK session.prompt({format: ...}):
- No tool_choice: "required". opencode constructs the provider request below the ACP surface, so we cannot force the model to call the tool; we can only instruct via prompt. Frontier models (Opus 4.7, Sonnet 4.6, GPT-5) comply reliably; smaller models in opencode's catalog may emit prose instead. When that happens DecodeStructuredOutput returns ErrStructuredOutputMissing.
- No in-agent-loop retry. opencode's JS SDK retries within the same turn on validation failure (default 2). ACP does not expose that primitive, so this SDK surfaces failures and lets callers decide whether to re-prompt (which starts a new turn and doubles cost).
- Single-flight capture per Client. Concurrent Session.Prompt calls on the same Client that both trigger StructuredOutput may clobber each other's captured payloads. Serialize prompts or use one Client per concurrent schema.
Returns an Option usable with NewClient / NewSession / Query.
func WithPrometheusRegisterer ¶
func WithPrometheusRegisterer(reg prometheus.Registerer) Option
WithPrometheusRegisterer wires SDK metrics to the supplied Prometheus registerer via the official go.opentelemetry.io/otel/exporters/prometheus bridge. The SDK creates a Prometheus-backed MeterProvider at Client.Start time and installs it as the MeterProvider for the client's Observer.
Callers who already supply an MeterProvider through WithMeterProvider take precedence — that MeterProvider wins and the registerer is ignored. Callers who want both a direct MeterProvider AND Prometheus scraping should register the Prometheus exporter themselves.
The registered metrics are scraped in OpenMetrics format with whatever HTTP handler the caller wires up against reg (typically `promhttp.HandlerFor(reg, ...)`).
func WithPure ¶
func WithPure() Option
WithPure disables opencode's external plugins, matching the CLI's `--pure` flag. Plugins installed via `opencode plugin` are skipped for the spawned process, yielding a reproducible runtime surface (no hook-injection from user-installed plugins).
Sugar for WithCLIFlags("--pure").
func WithSDKTools ¶
WithSDKTools registers in-process tools that opencode can invoke. The SDK starts a loopback HTTP MCP server when Client.Start is called, protects it with a random bearer token, and declares it in every session/new's mcpServers list.
If no tools are registered (WithSDKTools is never called or called with zero tools), no MCP bridge is started.
func WithSkipVersionCheck ¶
WithSkipVersionCheck disables the MinimumCLIVersion assertion during Start. Useful for local development against unreleased opencode builds.
func WithStderr ¶
WithStderr registers a callback that receives each line written to opencode's stderr. If not set, stderr is forwarded to the configured logger at debug level.
func WithStrictCwdBoundary ¶
WithStrictCwdBoundary rejects fs/write_text_file delegations for paths outside the configured cwd. When enabled without a configured cwd, every write is rejected. Default: false (writes are allowed anywhere the process has filesystem access to).
func WithTerminalAuthCapability ¶
WithTerminalAuthCapability advertises _meta["terminal-auth"]=true in the initialize handshake's ClientCapabilities. On opencode this causes AuthMethod entries to include a _meta["terminal-auth"] block with launch instructions (Command, Args, Env, Label). Use TerminalAuthInstructions to extract them, and AgentInfo + AuthMethods accessors to inspect them.
This is a no-op for agents that don't honor the capability. Default: false.
func WithTracerProvider ¶
func WithTracerProvider(tp trace.TracerProvider) Option
WithTracerProvider sets the OTel TracerProvider for SDK spans.
func WithTransport ¶
func WithTransport(factory TransportFactory) Option
WithTransport registers a custom TransportFactory, bypassing the default `opencode acp` subprocess. When set, [Client.Start] skips CLI discovery, version checks, subprocess spawn, and stderr wiring; the factory is called instead and is expected to return a working Transport.
The primary use case is test doubles: wire an acp.ClientSideConnection against an in-memory acp.AgentSideConnection so the SDK can be exercised without a live `opencode` binary on the box. See `transport_test.go` for an example.
Version check behaviour: callers using WithTransport should also supply WithSkipVersionCheck(true) unless their factory arranges its own CLI-version story.
func WithUpdatesBuffer ¶
WithUpdatesBuffer sets the buffer size of each Session.Updates() channel. If notifications arrive faster than the consumer drains, updates beyond this buffer are dropped and logged as a warning. Default: 128.
func WithUser ¶
WithUser tags the SDK's OpenTelemetry spans and metrics with the supplied user identifier. The value is exported as the `user` span attribute and metric label on every operation that records OTel data (initialize, prompt, tool call, permission, fs delegation, session/update, transport health). Useful for multi-tenant hosts that want per-user dashboards / cost attribution.
The value is not sent to opencode; it lives entirely in the SDK's observability layer.
type PermissionCallback ¶
type PermissionCallback func(ctx context.Context, req acp.RequestPermissionRequest) (acp.RequestPermissionResponse, error)
PermissionCallback is invoked when opencode asks the client to authorize a tool call (session/request_permission). The callback returns the outcome to send back to the agent.
If the callback blocks and ctx is cancelled, the callback MUST return promptly so the SDK can respond to opencode with outcome=cancelled. The returned error is sent to opencode as a JSON-RPC internal error — prefer returning a structured PermissionResponse with a reject option over returning err unless something catastrophic happened.
type ProcessError ¶
type ProcessError struct {
// ExitCode is the subprocess exit code. -1 when unavailable (e.g.
// signal-terminated before a status was recorded).
ExitCode int
// Stderr, when non-empty, is the final tail of the subprocess's
// stderr as captured by the SDK's stderr forwarder.
Stderr string
// Err is the underlying os/exec error (typically *exec.ExitError).
Err error
}
ProcessError is the typed companion surfaced when the opencode subprocess terminates with a non-zero exit status. The SDK constructs this in the watchSubprocess path for callers that want to inspect exit code / stderr rather than match on a sentinel.
func (*ProcessError) Error ¶
func (e *ProcessError) Error() string
func (*ProcessError) Unwrap ¶
func (e *ProcessError) Unwrap() error
type PromptResult ¶
type PromptResult struct {
// StopReason is the reason the agent stopped producing output for
// this turn. opencode currently only returns "end_turn" on success;
// cancel paths surface as ErrCancelled.
StopReason acp.StopReason
// Usage is the token accounting for this turn. The field is marked
// unstable in ACP and may be absent for some agents; opencode
// populates it reliably.
Usage *acp.Usage
// Meta is the _meta block from the PromptResponse. Typically nil.
Meta map[string]any
}
PromptResult is the final outcome of Session.Prompt.
type QueryResult ¶
type QueryResult struct {
// SessionID is the opencode session the prompt ran against.
SessionID string
// AssistantText is the concatenated text of every
// agent_message_chunk emitted during the turn. Tool-call output,
// thoughts, and structured content are not included here; consult
// Notifications for the raw stream.
AssistantText string
// StopReason is the final stop reason reported by opencode
// (typically "end_turn").
StopReason acp.StopReason
// Usage is the token accounting for the turn, if the provider
// reported it.
Usage *acp.Usage
// Notifications is the ordered list of session/update notifications
// received during the turn. Useful for callers that want to
// introspect tool calls, thoughts, or plan updates after the fact.
Notifications []acp.SessionNotification
}
QueryResult is the aggregated result of a single prompt turn. It is what Query returns and what QueryStream yields per input.
func Query ¶
Query is a one-shot convenience entry point. It spawns opencode, creates a new session, runs a single prompt to completion, and tears the subprocess down. The full set of [Option]s is honored, including WithSDKTools, WithCanUseTool, and WithOnFsWrite. For longer- lived interactions use NewClient or WithClient.
For multimodal prompts (text + image + embedded resource) use QueryContent.
func QueryContent ¶
func QueryContent(ctx context.Context, blocks []acp.ContentBlock, opts ...Option) (*QueryResult, error)
QueryContent is the multimodal variant of Query. It accepts a slice of content blocks — built via Text, Blocks, TextBlock, ImageBlock, ImageFileInput, ResourceBlock, etc. — allowing a single one-shot prompt to carry text, images, and embedded resources.
Non-text blocks require the agent to advertise the matching [PromptCapabilities] bit (Image, Audio, EmbeddedContext) during the ACP initialize handshake. Blocks whose capability isn't advertised are rejected up front with ErrCapabilityUnavailable.
blocks must be non-empty.
func ResilientQuery ¶
func ResilientQuery(ctx context.Context, prompt string, rq ResilientQueryOptions, opts ...Option) (*QueryResult, error)
ResilientQuery wraps Query with an automatic retry loop governed by a RetryPolicy and ClassifyError. Transient failures (rate limit, overload, transient connection errors) are retried with exponential back-off + jitter. Authentication, capability, and CLI-not-found errors surface immediately because no retry can recover them.
Example:
res, err := opencodesdk.ResilientQuery(ctx, "hello",
opencodesdk.ResilientQueryOptions{
RetryPolicy: opencodesdk.RetryPolicy{MaxRetries: 3},
},
opencodesdk.WithCwd("/repo"),
)
type Question ¶
type Question struct {
ID string
Header string
Question string
MultiSelect bool
IsOther bool
IsSecret bool
Options []QuestionOption
}
Question is a single prompt the agent wants the user to answer.
type QuestionOption ¶
QuestionOption represents a selectable choice in a user-input question.
type RecoveryAction ¶
type RecoveryAction string
RecoveryAction is the SDK's suggested next step for a classified failure. Callers are free to ignore the suggestion.
const ( RecoveryActionNone RecoveryAction = "none" RecoveryActionRefreshAuth RecoveryAction = "refresh_auth" RecoveryActionRetryWithBackoff RecoveryAction = "retry_with_backoff" RecoveryActionFallback RecoveryAction = "fallback" RecoveryActionStop RecoveryAction = "stop" )
type RequestError ¶
RequestError is the typed JSON-RPC error surface exposed to callers. It wraps *acp.RequestError from the protocol layer so callers can match on ACP error codes with errors.As without depending on the coder SDK.
func UnwrapRequestError ¶
func UnwrapRequestError(err error) *RequestError
UnwrapRequestError returns the underlying *RequestError when err wraps one, or nil otherwise. Provided as a convenience alongside errors.As for callers who want a one-liner.
func (*RequestError) Error ¶
func (e *RequestError) Error() string
type ResilientQueryOptions ¶
type ResilientQueryOptions struct {
// RetryPolicy controls the per-attempt back-off schedule. Leave as
// zero value to use DefaultRetryPolicy().
RetryPolicy RetryPolicy
// OnRetry, when set, is invoked before each retry sleep with the
// attempt number (1-based), the retry decision, and the underlying
// error. Useful for logging and metric emission.
OnRetry func(ctx context.Context, attempt int, decision RetryDecision, err error)
// Logger receives debug-level retry notices. Nil is acceptable.
Logger *slog.Logger
}
ResilientQueryOptions configures ResilientQuery.
type RetryDecision ¶
type RetryDecision struct {
Class ErrorClass
Retryable bool
Attempt int
MaxRetries int
RecommendedDelay time.Duration
}
RetryDecision is the output of EvaluateRetry, summarising whether a retry should occur and how long to wait.
func EvaluateRetry ¶
func EvaluateRetry(err error, attempt int, policy RetryPolicy) RetryDecision
EvaluateRetry combines ClassifyError with the supplied policy and attempt count to produce a retry decision. attempt is 1-based: pass 1 for the first retry consideration (after the initial call failed).
type RetryPolicy ¶
type RetryPolicy struct {
// MaxRetries caps the number of retry attempts. Original call +
// MaxRetries retries = MaxRetries+1 total attempts.
MaxRetries int
// BaseDelay is the base back-off window. Attempt N uses
// BaseDelay * 2^(N-1), clamped to MaxDelay.
BaseDelay time.Duration
// MaxDelay caps the computed delay.
MaxDelay time.Duration
// JitterRatio is the fraction of BaseDelay to use as random
// jitter. 0.0–1.0.
JitterRatio float64
}
RetryPolicy configures the per-attempt delay schedule used by ResilientQuery and EvaluateRetry. A zero-value policy resolves to DefaultRetryPolicy().
func DefaultRetryPolicy ¶
func DefaultRetryPolicy() RetryPolicy
DefaultRetryPolicy returns conservative defaults: 5 retries, 500ms base, 30s cap, 25% jitter.
type Session ¶
type Session interface {
// ID returns the opencode session ID (e.g. "ses_24d2fc1e0ffe5YxDJSq64vW9LD").
ID() string
// Prompt submits a user turn and blocks until the turn completes.
// It returns the final PromptResult (stop reason + optional usage)
// or an error. Cancel the ctx to abort the turn; the error returned
// in that case wraps ErrCancelled.
Prompt(ctx context.Context, blocks ...acp.ContentBlock) (*PromptResult, error)
// RunCommand invokes one of opencode's slash commands as a prompt
// turn. Equivalent to Prompt with a single TextBlock built from
// "/<name> <arg> <arg>..." — opencode interprets leading-slash text
// as a command invocation. The command list available for this
// session is exposed via AvailableCommands().
//
// Per the opencode 1.14.20 ACP probe, slash commands are not a
// distinct content-block kind; sending plain text with a leading
// slash is the supported invocation path. /undo and /redo are
// explicitly unsupported over ACP.
RunCommand(ctx context.Context, name string, args ...string) (*PromptResult, error)
// Cancel sends a session/cancel notification for the current turn.
// This is advisory — the turn's pending Prompt call returns with
// an error. Cancel is safe to call when no turn is in flight; it
// becomes a no-op.
Cancel(ctx context.Context) error
// Updates returns a channel that delivers every session/update
// notification for this session. The channel is buffered
// (WithUpdatesBuffer, default 128). If the buffer fills, excess
// notifications are dropped and logged at warn level.
//
// The channel remains open for the lifetime of the session and is
// closed when the owning Client is closed.
Updates() <-chan acp.SessionNotification
// SetModel changes the model used for subsequent prompts. Sugar for
// SetConfigOption(ctx, "model", modelID).
SetModel(ctx context.Context, modelID string) error
// SetMode changes the agent ("mode") used for subsequent prompts.
// Sugar for SetConfigOption(ctx, "mode", modeID).
SetMode(ctx context.Context, modeID string) error
// SetConfigOption routes a session/set_config_option RPC with a
// string value. configID must match one of the option ids reported in
// InitialConfigOptions (e.g. "model", "mode", "provider"). The value
// must be one of the valid value ids for that option.
//
// Prefer SetModel / SetMode for the two common cases.
SetConfigOption(ctx context.Context, configID, value string) error
// SetConfigOptionBool routes a session/set_config_option RPC with a
// boolean value. Applicable to opencode config options whose
// SessionConfigOption variant is a boolean (opencode currently does
// not expose any via ACP; included for forward compatibility with
// agents that do).
SetConfigOptionBool(ctx context.Context, configID string, value bool) error
// InitialModels returns the SessionModelState reported by opencode
// at session creation (or the last loadSession/resume). May be nil
// if the agent did not advertise model state.
InitialModels() *acp.SessionModelState
// InitialModes returns the SessionModeState reported at creation.
// May be nil.
InitialModes() *acp.SessionModeState
// InitialConfigOptions returns the configOptions snapshot from
// session creation.
InitialConfigOptions() []acp.SessionConfigOption
// Meta returns the raw _meta block from session creation. opencode
// exposes variant info as `_meta.opencode.variant`; use
// CurrentVariant for a typed accessor.
Meta() map[string]any
// AvailableModels returns the list of models advertised by opencode
// for this session. Derived from InitialModels; returns nil if the
// agent did not advertise any.
AvailableModels() []acp.ModelInfo
// AvailableModes returns the list of session modes advertised by
// opencode for this session (e.g. the built-in ModeBuild /
// ModePlan plus any user-configured modes). Derived from
// InitialModes; returns nil if the agent did not advertise any.
AvailableModes() []acp.SessionMode
// AvailableCommands returns a snapshot of the slash commands the
// agent currently advertises. opencode emits these once per session,
// ~1 tick after the lifecycle response, so this accessor may be
// empty immediately after NewSession and populated shortly after.
// Callers that need the up-to-the-moment list should observe the
// Updates() channel for acp.AvailableCommandsUpdate notifications.
AvailableCommands() []acp.AvailableCommand
// CurrentVariant returns the opencode-specific model-variant state
// for this session. If the SDK has observed a session/set_model
// response (via WithEffort's variant-resolution probe or an
// UnstableSetModel call) the returned value reflects that latest
// state; otherwise it falls back to parsing `_meta.opencode` from
// session creation. Returns nil when neither source carries
// variant state.
CurrentVariant() *VariantInfo
// Subscribe installs a set of typed session/update callbacks and
// returns an unsubscribe function. Handlers fire synchronously in
// the SDK's dispatcher goroutine alongside delivery to Updates(),
// so they must not block. Multiple subscribers are supported and
// fire in registration order.
Subscribe(handlers UpdateHandlers) (unsubscribe func())
// DroppedUpdates returns the cumulative count of session/update
// notifications dropped because the Updates() buffer was full since
// the session was created.
DroppedUpdates() int64
}
Session is a stateful opencode conversation. Obtain one via Client.NewSession, Client.LoadSession, or (in M7) Client.ForkSession / Client.ResumeSession.
Session is safe for concurrent Prompt/Cancel calls from different goroutines, but a single in-flight Prompt serializes all tool calls and updates on the session.
type SessionCostOptions ¶
type SessionCostOptions struct {
// OpencodeHome is the opencode data directory. When empty the SDK
// falls back to $XDG_DATA_HOME, then $HOME/.local/share.
OpencodeHome string
}
SessionCostOptions controls persisted session-cost file locations.
type SessionHistory ¶
type SessionHistory struct {
// Session is the loaded opencode session. It is ready for further
// Prompt/Cancel calls. The session's Updates() channel has been
// drained of the replay notifications captured below; subsequent
// activity flows through it as usual.
Session Session
// Notifications is the raw session/update notifications opencode
// emitted while replaying the session's history. Preserves
// original order, including non-message updates (plan, tool_call,
// available_commands_update, usage_update, etc.).
Notifications []acp.SessionNotification
// Messages is a convenience projection of Notifications that
// collapses user/assistant/thought text chunks into single
// HistoryMessage entries. Adjacent chunks with the same role are
// concatenated. Non-text updates do not appear here.
Messages []HistoryMessage
// Usage is the last UsageUpdate observed during replay (opencode
// emits these cumulatively). Nil if the session had no usage
// events.
Usage *acp.SessionUsageUpdate
}
SessionHistory is the replay of a loaded opencode session. Returned by Client.LoadSessionHistory.
type SessionInfo ¶
type SessionInfo = acp.SessionInfo
SessionInfo is a lightweight handle returned by Client.ListSessions.
type SessionStat ¶
type SessionStat struct {
// SessionID is the opencode session identifier (`ses_...`).
SessionID string
// ProjectID is the opencode project this session belongs to.
// "global" is used for sessions not tied to a specific project.
ProjectID string
// ParentID is the parent session ID for forked sessions, empty
// when the session was created directly rather than forked.
ParentID string
// Slug is the short human-friendly identifier opencode assigns
// (e.g. "eager-planet").
Slug string
// Directory is the absolute path opencode associated with the
// session when it was created (its `cwd`).
Directory string
// Title is the session title opencode derives (typically a short
// summary of the opening prompt).
Title string
// Version is the opencode CLI version recorded at session creation.
Version string
// sharing is not configured.
ShareURL string
// SummaryAdditions is the cumulative lines added across file edits
// opencode attributes to this session (nil when not recorded).
SummaryAdditions *int64
// SummaryDeletions is the cumulative lines removed across file
// edits opencode attributes to this session (nil when not recorded).
SummaryDeletions *int64
// SummaryFiles is the number of distinct files touched (nil when
// not recorded).
SummaryFiles *int64
// CreatedAt is when opencode created the session (UTC).
CreatedAt time.Time
// UpdatedAt is when opencode last wrote to the session (UTC).
UpdatedAt time.Time
// CompactingAt, when non-nil, indicates opencode started a
// compaction pass at this time and has not yet finished.
CompactingAt *time.Time
// ArchivedAt, when non-nil, is when the session was archived by
// the user (sessions archive rather than delete).
ArchivedAt *time.Time
// WorkspaceID is the opencode workspace the session is pinned to,
// empty for sessions not tied to a workspace.
WorkspaceID string
// MessageCount is the total number of messages persisted for this
// session in opencode's `message` table.
MessageCount int64
}
SessionStat carries metadata about an opencode session read from the local SQLite database at `$XDG_DATA_HOME/opencode/opencode.db`. It is populated by StatSession and does not require an open Client.
Nullable fields (ParentID, ShareURL, WorkspaceID, CompactingAt, ArchivedAt, SummaryAdditions, SummaryDeletions, SummaryFiles) mirror opencode's own column nullability — absence is represented as a zero value for strings and a nil pointer for the rest.
func ListSessions ¶
func ListSessions(ctx context.Context, listOpts ListSessionsOptions, opts ...Option) ([]SessionStat, error)
ListSessions enumerates opencode sessions from the local SQLite store without starting an `opencode acp` subprocess. It mirrors the client-less pattern established by StatSession: use WithCwd to scope the listing to a project directory, WithOpencodeHome to override the XDG_DATA_HOME lookup, and ListSessionsOptions for archive / limit controls.
Results are ordered by UpdatedAt descending (most-recent first) and carry the same SessionStat shape that StatSession returns.
Returns ErrSessionNotFound when the database file is missing — consistent with StatSession. An empty slice with a nil error means the database exists but holds no matching sessions.
This function reads the same SQLite store used by opencode itself; it does not go through the ACP `session/list` RPC. For a live, agent-authoritative listing (including sessions the SDK cannot see because the cwd differs), use [Client.ListSessions] or [Client.IterSessions] instead.
func StatSession ¶
StatSession reads metadata for a single opencode session directly from the local SQLite store without starting an `opencode acp` subprocess.
The session ID follows opencode's `ses_...` format. Use WithCwd to scope the lookup to a specific project directory (the session row is additionally filtered by exact `directory` match); this is useful when the same session ID could exist across overlapping opencode homes. WithOpencodeHome overrides the XDG_DATA_HOME lookup used to locate opencode.db.
Returns ErrSessionNotFound when the session row does not exist or the database file is missing. All other errors surface wrapped with context.
func (*SessionStat) Archived ¶
func (s *SessionStat) Archived() bool
Archived reports whether the session has been archived.
type TerminalAuthLaunch ¶
TerminalAuthLaunch describes how a client can spawn an interactive login flow for the user. opencode populates this via its _meta["terminal-auth"] extension on AuthMethodAgent when the client declared _meta["terminal-auth"]=true in ClientCapabilities at initialize time (see WithTerminalAuthCapability).
A typical shape on opencode 1.14.20:
TerminalAuthLaunch{
Command: "opencode",
Args: []string{"auth", "login"},
Label: "OpenCode Login",
}
func TerminalAuthInstructions ¶
func TerminalAuthInstructions(m acp.AuthMethod) (*TerminalAuthLaunch, bool)
TerminalAuthInstructions extracts the opencode-specific _meta["terminal-auth"] block from an AuthMethod if present. Returns (nil, false) if the method does not advertise a terminal launch.
Callers can use the returned TerminalAuthLaunch to offer the user an interactive login UX (exec the command in a PTY, wait, retry the failing ACP call). The SDK does not do this automatically — auth is always user-initiated out of band.
type Tool ¶
type Tool interface {
// Name is the unique identifier for this tool. Must be a valid MCP
// tool name (alphanumeric + underscore/hyphen). The name is used
// verbatim on the wire; opencode typically prefixes it with the
// MCP server name before presenting to the agent.
Name() string
// Description is a human-readable explanation of what the tool
// does, shown to the agent model.
Description() string
// InputSchema is a JSON Schema (2020-12 draft) describing the
// expected input shape. Type must be "object". See
// https://json-schema.org for the schema syntax.
InputSchema() map[string]any
// Execute runs the tool against the supplied arguments and returns
// a result. Return a non-nil error to mark the call as failed;
// opencode surfaces the error message to the agent.
Execute(ctx context.Context, input map[string]any) (ToolResult, error)
}
Tool is an in-process tool that the opencode agent can invoke. Tools are registered via WithSDKTools and served to opencode through a loopback HTTP MCP server spun up by the Client at Start time. The server name opencode sees is prefixed with `opencodesdk_`.
Implementations must be safe for concurrent Execute calls — opencode may invoke the same tool from parallel tool-call chains.
func NewTool ¶
func NewTool(name, description string, schema map[string]any, fn ToolFunc, opts ...NewToolOption) Tool
NewTool constructs a Tool from a name, description, JSON schema, and a handler function. Optional NewToolOption values (e.g. WithToolAnnotations) customise non-essential metadata.
Example:
t := opencodesdk.NewTool(
"sum",
"Add two numbers",
map[string]any{
"type": "object",
"properties": map[string]any{
"a": map[string]any{"type": "number"},
"b": map[string]any{"type": "number"},
},
"required": []string{"a", "b"},
},
func(ctx context.Context, in map[string]any) (opencodesdk.ToolResult, error) {
a := in["a"].(float64)
b := in["b"].(float64)
return opencodesdk.ToolResult{Text: fmt.Sprintf("%v", a+b)}, nil
},
)
type ToolAnnotations ¶
type ToolAnnotations struct {
// Title is a human-readable display title for the tool (falls back
// to the tool name when empty).
Title string
// ReadOnlyHint indicates the tool does not modify its environment.
// Default: false.
ReadOnlyHint bool
// DestructiveHint indicates the tool may perform destructive
// updates. Only meaningful when ReadOnlyHint == false. Default
// (per MCP spec) is true — pass BoolPtr(false) to explicitly mark
// a non-destructive tool.
DestructiveHint *bool
// IdempotentHint indicates repeated calls with the same arguments
// are a no-op beyond the first. Only meaningful when ReadOnlyHint
// == false. Default: false.
IdempotentHint bool
// OpenWorldHint indicates the tool interacts with an open world
// of external entities (e.g. web search). Default (per MCP spec)
// is true — pass BoolPtr(false) for closed-domain tools.
OpenWorldHint *bool
}
ToolAnnotations is a set of MCP tool annotation hints the SDK forwards through the loopback bridge to opencode. They are advisory: opencode may display them or use them to build its permission UI, but they do not alter invocation semantics.
All fields are optional. Pointer-typed fields (DestructiveHint, OpenWorldHint) distinguish "unset" from "explicitly false" per the MCP spec defaults — use BoolPtr to set them.
type ToolCallStatus ¶
type ToolCallStatus = acp.ToolCallStatus
ToolCallStatus is the lifecycle state of a streamed tool call.
type ToolFunc ¶
ToolFunc is a convenience shape for simple tools that don't need state beyond a closure.
type ToolKind ¶
ToolKind categorises a streamed tool call for UI treatment (icons, follow-along highlighting). Re-exported for caller ergonomics.
type ToolResult ¶
type ToolResult struct {
// Text is the primary textual response shown to the agent. Usually
// the only field callers need.
Text string
// Structured, when non-nil, is returned as structuredContent in the
// MCP CallToolResult — useful for agents that can parse JSON.
Structured any
// IsError marks the result as an error. The MCP spec treats this
// as semantic: the call "succeeded" at the transport layer but the
// tool encountered an application-level problem. Use this for
// recoverable errors that the agent should see and adapt to.
IsError bool
}
ToolResult is the structured output of a Tool.Execute call.
func ErrorResult ¶
func ErrorResult(message string) ToolResult
ErrorResult returns a ToolResult flagged as an application-level error. The agent sees the message as a failed tool call but the transport call itself succeeded — use this for recoverable errors the agent should adapt to. For catastrophic failures, return an error from the Tool.Execute instead.
func ImageResult ¶
func ImageResult(data []byte, mimeType string) ToolResult
ImageResult returns a ToolResult whose text payload is a human-readable placeholder and whose Structured payload carries the image bytes base64-encoded alongside the mime type. opencode's MCP bridge forwards the Structured block as structuredContent and agents that understand image content negotiate from there.
The mimeType must be a full image/* type, e.g. "image/png".
func TextResult ¶
func TextResult(text string) ToolResult
TextResult returns a ToolResult whose primary payload is text. The equivalent of building `ToolResult{Text: text}` inline, kept for parity with the claude/codex sister SDKs so tool authors can write `return opencodesdk.TextResult("ok"), nil`.
type Transport ¶
type Transport interface {
// Conn returns the ACP client-side connection. Non-nil once the
// transport is ready to carry traffic. The SDK invokes Initialize
// itself immediately after the factory returns, then drives the
// rest of the lifecycle through this connection.
Conn() *acp.ClientSideConnection
// Close terminates the transport and releases all resources.
// Idempotent.
Close() error
}
Transport is the minimal abstraction the Client uses to talk to an opencode (or ACP-compatible) agent. The default Client uses a subprocess-backed implementation that spawns `opencode acp`; alternative transports can be supplied via WithTransport for testing or embedded integrations.
Implementations must be safe for concurrent use: the SDK issues RPCs (session/new, session/prompt, etc.) from its own goroutines while the transport delivers agent-initiated notifications back to the handler supplied via TransportFactory.
type TransportError ¶
type TransportError struct {
// Reason is a short label describing which transport layer
// observed the failure ("subprocess", "custom", ...).
Reason string
// Err is the underlying cause, if any (e.g. *exec.ExitError,
// io.EOF). May be nil when the transport reported a graceful close
// with no Go-level error.
Err error
}
TransportError is the typed companion to ErrTransport. It is returned when the opencode acp subprocess (or equivalent transport) closes unexpectedly — callers blocked on an RPC observe this instead of a silent context cancellation.
The error chain always includes ErrTransport so callers can write `errors.Is(err, ErrTransport)` when they only care about the kind, or `errors.As(err, &te)` when they want the underlying cause.
func (*TransportError) Error ¶
func (e *TransportError) Error() string
func (*TransportError) Is ¶
func (e *TransportError) Is(target error) bool
Is reports whether target is ErrTransport. Callers matching on the sentinel observe the typed error regardless of Reason / cause.
func (*TransportError) Unwrap ¶
func (e *TransportError) Unwrap() error
type TransportFactory ¶
TransportFactory constructs a Transport. The SDK invokes it once at [Client.Start] time (or at one-shot Query time) after resolving all options.
handler is the SDK-supplied agent-facing dispatcher; implementations must wire it as the acp.Client on their acp.ClientSideConnection. Handler methods route agent-initiated RPCs (session/update, session/request_permission, fs/read_text_file, fs/write_text_file, terminal/*) back into the SDK.
The factory owns the full lifecycle of the returned Transport — Client.Close invokes Transport.Close, but any construction-time resources (e.g. an in-memory pipe, a network dial) are the factory's responsibility to clean up on early return.
type TransportHealth ¶
type TransportHealth struct {
// Degraded is true once the subprocess has exited unexpectedly or
// the Client has been Closed. It does not un-set itself.
Degraded bool
// ConsecutiveFailures is the number of transport errors observed
// since the last success. opencode's SDK currently increments this
// only on subprocess crash, which also flips Degraded.
ConsecutiveFailures int
// SendFailures counts outbound RPC errors classified as transport
// failures (connection closed, broken pipe, subprocess dead). JSON-
// RPC application errors do NOT count here.
SendFailures int
// ReadFailures counts inbound-stream read failures.
ReadFailures int
// LastError is the most recent transport-layer error observed, or
// nil if none. Points at a stable string owned by the health
// tracker.
LastError *string
// LastFailureAt is the timestamp of the most recent failure, or
// nil if none has been observed.
LastFailureAt *time.Time
}
TransportHealth is a point-in-time snapshot of the transport-layer health observed by the Client. It is cheap to fetch and safe for diagnostic dashboards or liveness probes.
Parity with the claude/codex sister SDKs. Unlike those, opencode's transport is an ACP JSON-RPC subprocess — failures are counted for subprocess crashes and ACP read/send errors surfaced through coder/acp-go-sdk.
type TurnCompleteCallback ¶
type TurnCompleteCallback func(ctx context.Context, sessionID string, result *PromptResult, err error)
TurnCompleteCallback fires after every Session.Prompt call returns, regardless of success. On error, result is nil and err is non-nil; on success, both are set. Registered via WithOnTurnComplete.
type UpdateDroppedCallback ¶
UpdateDroppedCallback fires when a session/update notification could not be delivered because Session.Updates() was full. count is the new cumulative drop count for the session. Registered via WithOnUpdateDropped.
type UpdateHandlers ¶
type UpdateHandlers struct {
// UserMessage fires for user_message_chunk notifications. These are
// only emitted during LoadSession history replay.
UserMessage func(ctx context.Context, chunk *acp.SessionUpdateUserMessageChunk)
// AgentMessage fires for each agent_message_chunk streamed during a
// turn. Concatenate `.Content` text across chunks to assemble the
// assistant's reply.
AgentMessage func(ctx context.Context, chunk *acp.SessionUpdateAgentMessageChunk)
// AgentThought fires for thinking/reasoning chunks. Not all models
// emit these; opencode surfaces them when the model advertises a
// thinking channel.
AgentThought func(ctx context.Context, chunk *acp.SessionUpdateAgentThoughtChunk)
// ToolCall fires the first time the agent announces a tool call.
ToolCall func(ctx context.Context, tc *acp.SessionUpdateToolCall)
// ToolCallUpdate fires on every subsequent update to a tool call
// (status transitions, streaming content, final output).
ToolCallUpdate func(ctx context.Context, tcu *acp.SessionToolCallUpdate)
// Plan fires when the agent publishes or replaces its execution
// plan. opencode emits these from the `todowrite` tool. The agent
// always sends the full plan; treat it as a replace.
Plan func(ctx context.Context, plan *acp.SessionUpdatePlan)
// AvailableCommands fires when the set of slash commands the agent
// advertises changes. opencode typically emits this once shortly
// after session creation.
AvailableCommands func(ctx context.Context, upd *acp.SessionAvailableCommandsUpdate)
// CurrentMode fires when the agent's current mode changes. Note
// that calls to Session.SetMode emit this update.
CurrentMode func(ctx context.Context, upd *acp.SessionCurrentModeUpdate)
// ConfigOption fires when a session/set_config_option call completes
// and opencode broadcasts the new value.
ConfigOption func(ctx context.Context, upd *acp.SessionConfigOptionUpdate)
// SessionInfo fires when the agent updates session metadata (e.g.
// title).
SessionInfo func(ctx context.Context, upd *acp.SessionSessionInfoUpdate)
// Usage fires when the agent reports cumulative token or cost usage
// for the session.
Usage func(ctx context.Context, upd *acp.SessionUsageUpdate)
}
UpdateHandlers is a set of typed callbacks invoked for each variant of a session/update notification. Every field is optional; nil handlers are skipped.
Handlers run synchronously in the SDK's dispatcher goroutine before the notification is forwarded to Session.Updates(). They therefore share backpressure with that channel — long-running work should be dispatched off the handler goroutine, not performed inline. The ctx passed in is the dispatcher context; it is cancelled when the Client closes.
Subscribers supplement, rather than replace, the Session.Updates() channel. Callers can use either, both, or neither.
type UserInputAnswer ¶
type UserInputAnswer struct {
Answers []string
}
UserInputAnswer is the response for a single question keyed by Question.ID.
type UserInputCallback ¶
type UserInputCallback func(ctx context.Context, req *UserInputRequest) (*UserInputResponse, error)
UserInputCallback handles AskUserQuestion invocations. Implementations receive the parsed questions and return the user's answers keyed by Question.ID.
Sister SDK parity: mirrors claude-agent-sdk-go's user_input.Callback. Hosts that already translate UserInputRequest for Claude Code reuse the same handler verbatim.
type UserInputRequest ¶
type UserInputRequest struct {
Questions []Question
}
UserInputRequest is the payload delivered to a UserInputCallback when the agent invokes AskUserQuestion.
type UserInputResponse ¶
type UserInputResponse struct {
Answers map[string]*UserInputAnswer
}
UserInputResponse is returned by a UserInputCallback. Answers is keyed by Question.ID; entries whose ID does not match a question in the original request are ignored.
type VariantInfo ¶
type VariantInfo struct {
// ModelId is the base model id (e.g. "anthropic/claude-sonnet-4").
ModelId string
// Variant is the selected variant (e.g. "high") or empty.
Variant string
// AvailableVariants lists the variant ids the model supports.
AvailableVariants []string
}
VariantInfo describes the opencode-specific model variant state carried in a session's _meta.opencode block.
func OpencodeVariant ¶
func OpencodeVariant(meta map[string]any) (*VariantInfo, bool)
OpencodeVariant extracts _meta.opencode.{modelId, variant, availableVariants} from a session's meta block. Returns (nil, false) if absent.
type WatchableTransport ¶
type WatchableTransport interface {
Transport
// Exited is closed when the transport has died. It is safe to call
// before or after the transport has died.
Exited() <-chan struct{}
// ExitErr returns the exit error observed by the transport, or nil
// if the transport exited cleanly (or has not yet exited).
ExitErr() error
}
WatchableTransport is an optional extension to Transport. Transports that wrap a process, TCP connection, or similar resource can implement it to let the SDK detect unexpected death (and close live sessions accordingly). Subprocess-backed transports implement this.
Source Files
¶
- auth.go
- budget_tracker.go
- capabilities.go
- client.go
- client_impl.go
- content.go
- cost_tracker.go
- doc.go
- effort.go
- elicit.go
- elicit_handler.go
- error_classification.go
- errors.go
- health.go
- hooks.go
- load_history.go
- logger.go
- maxturns.go
- mcp.go
- mcp_helpers.go
- model_capabilities.go
- models.go
- options.go
- permissions.go
- query.go
- resilient.go
- retry_policy.go
- session.go
- session_impl.go
- session_stat.go
- stat_session.go
- structured_output.go
- structured_output_tool.go
- tool_filters.go
- transport.go
- unstable.go
- updates.go
- user_input.go
- version.go
- with_client.go
Directories
¶
| Path | Synopsis |
|---|---|
|
contrib
|
|
|
prometheus
Package prometheus provides a convenience helper for wiring Prometheus metrics into the opencode Agent SDK without pulling the OTel SDK's Prometheus exporter dependency into every consumer that only wants OTel OTLP export.
|
Package prometheus provides a convenience helper for wiring Prometheus metrics into the opencode Agent SDK without pulling the OTel SDK's Prometheus exporter dependency into every consumer that only wants OTel OTLP export. |
|
examples
|
|
|
add_dirs
command
Demonstrates opencodesdk.WithAddDirs — forwarding ACP's unstable `additionalDirectories` field to opencode.
|
Demonstrates opencodesdk.WithAddDirs — forwarding ACP's unstable `additionalDirectories` field to opencode. |
|
cancellation
command
Demonstrates cancelling an in-flight opencode turn via [Session.Cancel].
|
Demonstrates cancelling an in-flight opencode turn via [Session.Cancel]. |
|
cost_tracker
command
Example: per-session cost tracking via CostTracker, persisted to $XDG_DATA_HOME/opencode/sdk/session-costs/<id>.json.
|
Example: per-session cost tracking via CostTracker, persisted to $XDG_DATA_HOME/opencode/sdk/session-costs/<id>.json. |
|
custom_logger
command
Demonstrates routing opencodesdk's internal logs through a custom slog.Handler.
|
Demonstrates routing opencodesdk's internal logs through a custom slog.Handler. |
|
custom_transport
command
Demonstrates opencodesdk.WithTransport — injecting a custom Transport in place of the default `opencode acp` subprocess.
|
Demonstrates opencodesdk.WithTransport — injecting a custom Transport in place of the default `opencode acp` subprocess. |
|
effort
command
Demonstrates WithEffort: opencode encodes reasoning depth as a `/<variant>` suffix on a model id (e.g.
|
Demonstrates WithEffort: opencode encodes reasoning depth as a `/<variant>` suffix on a model id (e.g. |
|
elicitation
command
Example: a tool that asks the user to confirm a destructive action via MCP elicitation.
|
Example: a tool that asks the user to confirm a destructive action via MCP elicitation. |
|
elicitation_callback
command
Example elicitation_callback demonstrates the agent-initiated elicitation path: WithOnElicitation receives elicitation/create requests from the agent and returns an Accept / Decline / Cancel response.
|
Example elicitation_callback demonstrates the agent-initiated elicitation path: WithOnElicitation receives elicitation/create requests from the agent and returns an Accept / Decline / Cancel response. |
|
error_handling
command
Demonstrates the typed errors opencodesdk surfaces and how to branch on them with errors.Is / errors.As.
|
Demonstrates the typed errors opencodesdk surfaces and how to branch on them with errors.Is / errors.As. |
|
external_mcp
command
Demonstrates WithMCPServers: attach an external MCP server to every new session.
|
Demonstrates WithMCPServers: attach an external MCP server to every new session. |
|
fork_resume
command
Demonstrates Client.ForkSession and Client.ResumeSession.
|
Demonstrates Client.ForkSession and Client.ResumeSession. |
|
fs_intercept
command
Demonstrates WithOnFsWrite: intercept opencode's fs/write_text_file delegations and redirect them into an in-memory map rather than the real filesystem.
|
Demonstrates WithOnFsWrite: intercept opencode's fs/write_text_file delegations and redirect them into an in-memory map rather than the real filesystem. |
|
hooks
command
Example: WithHooks wires typed callbacks into opencode's session/update stream + lifecycle + permission path.
|
Example: WithHooks wires typed callbacks into opencode's session/update stream + lifecycle + permission path. |
|
iter_sessions
command
Demonstrates Client.IterSessions — a cursor-paginated iterator over every opencode session in the configured cwd.
|
Demonstrates Client.IterSessions — a cursor-paginated iterator over every opencode session in the configured cwd. |
|
load_session
command
Demonstrates Client.LoadSession — rehydrate a previous opencode session by id.
|
Demonstrates Client.LoadSession — rehydrate a previous opencode session by id. |
|
max_budget_usd
command
Example: cap total session spend with WithMaxBudgetUSD.
|
Example: cap total session spend with WithMaxBudgetUSD. |
|
max_turns
command
Demonstrates WithMaxTurns: a client-side cap on the number of assistant messages observed per session.
|
Demonstrates WithMaxTurns: a client-side cap on the number of assistant messages observed per session. |
|
model_variant
command
Demonstrates opencode-specific model variant handling: OpencodeVariant, Session.CurrentVariant, and Client.UnstableSetModel.
|
Demonstrates opencode-specific model variant handling: OpencodeVariant, Session.CurrentVariant, and Client.UnstableSetModel. |
|
multimodal_input
command
Demonstrates multimodal prompt input via the opencodesdk.QueryContent one-shot helper.
|
Demonstrates multimodal prompt input via the opencodesdk.QueryContent one-shot helper. |
|
parallel_queries
command
Demonstrates running multiple opencode queries concurrently — each in its own subprocess + session — and aggregating the answers in Go.
|
Demonstrates running multiple opencode queries concurrently — each in its own subprocess + session — and aggregating the answers in Go. |
|
permission_callback
command
Demonstrates WithCanUseTool: a stdin-based permission prompt that asks the operator to approve each tool call interactively.
|
Demonstrates WithCanUseTool: a stdin-based permission prompt that asks the operator to approve each tool call interactively. |
|
pipeline
command
Demonstrates a multi-step LLM pipeline with Go-side gating.
|
Demonstrates a multi-step LLM pipeline with Go-side gating. |
|
plan_mode
command
Demonstrates WithInitialMode(ModePlan).
|
Demonstrates WithInitialMode(ModePlan). |
|
query_stream
command
Demonstrates opencodesdk.QueryStream for running a series of prompts against a single, long-lived opencode session and iterating results as they arrive.
|
Demonstrates opencodesdk.QueryStream for running a series of prompts against a single, long-lived opencode session and iterating results as they arrive. |
|
query_stream_iter
command
Demonstrates opencodesdk.QueryStreamContent — the iterator-backed multimodal variant of QueryStream.
|
Demonstrates opencodesdk.QueryStreamContent — the iterator-backed multimodal variant of QueryStream. |
|
quick_start
command
Quick-start example for opencode-agent-sdk-go.
|
Quick-start example for opencode-agent-sdk-go. |
|
resilient_query
command
Example: ResilientQuery applies exponential backoff + jitter for retryable errors (rate limit, overload, transient connection).
|
Example: ResilientQuery applies exponential backoff + jitter for retryable errors (rate limit, overload, transient connection). |
|
run_command
command
Demonstrates Session.RunCommand: invoke one of opencode's slash commands (advertised via session/update's available_commands_update notification) as a prompt turn.
|
Demonstrates Session.RunCommand: invoke one of opencode's slash commands (advertised via session/update's available_commands_update notification) as a prompt turn. |
|
sdk_tools
command
Demonstrates in-process tools exposed to opencode via the loopback HTTP MCP bridge built into the SDK.
|
Demonstrates in-process tools exposed to opencode via the loopback HTTP MCP bridge built into the SDK. |
|
session_list
command
Enumerates prior opencode sessions scoped to the working directory and prints their IDs and titles.
|
Enumerates prior opencode sessions scoped to the working directory and prints their IDs and titles. |
|
session_mutations
command
Demonstrates intra-session mutations: Session.SetModel and Session.SetMode.
|
Demonstrates intra-session mutations: Session.SetModel and Session.SetMode. |
|
set_config_option
command
Example: Session.SetConfigOption routes session/set_config_option for arbitrary config ids reported by opencode at session creation.
|
Example: Session.SetConfigOption routes session/set_config_option for arbitrary config ids reported by opencode at session creation. |
|
stderr_callback
command
Demonstrates WithStderr for capturing opencode's stderr output.
|
Demonstrates WithStderr for capturing opencode's stderr output. |
|
typed_subscribers
command
Demonstrates Session.Subscribe — typed per-variant callbacks for session/update notifications.
|
Demonstrates Session.Subscribe — typed per-variant callbacks for session/update notifications. |
|
internal
|
|
|
cli
Package cli discovers the opencode binary and validates its version.
|
Package cli discovers the opencode binary and validates its version. |
|
handlers
Package handlers provides a Dispatcher that implements acp.Client so the coder/acp-go-sdk ClientSideConnection can dispatch agent→client RPCs and notifications into opencodesdk.
|
Package handlers provides a Dispatcher that implements acp.Client so the coder/acp-go-sdk ClientSideConnection can dispatch agent→client RPCs and notifications into opencodesdk. |
|
mcp/bridge
Package bridge runs a loopback HTTP MCP server that exposes user- supplied in-process tools to opencode.
|
Package bridge runs a loopback HTTP MCP server that exposes user- supplied in-process tools to opencode. |
|
observability
Package observability defines the OTel metric and span instruments the SDK records.
|
Package observability defines the OTel metric and span instruments the SDK records. |
|
serve
Package serve manages a short-lived `opencode serve` subprocess and exposes the base URL of its HTTP API.
|
Package serve manages a short-lived `opencode serve` subprocess and exposes the base URL of its HTTP API. |
|
session
Package session provides read-only SQLite access to opencode's local session store at $XDG_DATA_HOME/opencode/opencode.db.
|
Package session provides read-only SQLite access to opencode's local session store at $XDG_DATA_HOME/opencode/opencode.db. |
|
subprocess
Package subprocess manages the opencode acp child process and wires its stdio into the coder/acp-go-sdk protocol layer.
|
Package subprocess manages the opencode acp child process and wires its stdio into the coder/acp-go-sdk protocol layer. |
|
tuimodel
Package tuimodel reads the opencode TUI's persisted model selection from $XDG_STATE_HOME/opencode/model.json so the SDK can default new sessions to whatever model the user last picked interactively.
|
Package tuimodel reads the opencode TUI's persisted model selection from $XDG_STATE_HOME/opencode/model.json so the SDK can default new sessions to whatever model the user last picked interactively. |