All SDKs
Go

Go SDK

go.vadyl.dev/sdk
Available
The Go SDK is idiomatic, generic, and dependency-light. Native context.Context cancellation. Go 1.21+. No CGo, no native deps.

Install

go get
go get go.vadyl.dev/sdk
import
import sdk "go.vadyl.dev/sdk"
Read the documentation
1. Initialize

Create the client

Configure the client once. Same object reaches every product surface — entities, workflows, agents, realtime.

main.goGo
package main

import (
    "context"
    "log"
    "os"

    sdk "go.vadyl.dev/sdk"
)

func main() {
    vadyl := sdk.New(sdk.Options{
        APIURL:  "https://api.vadyl.app/v1",
        Token:   os.Getenv("VADYL_TOKEN"),
        Tenant:  "acme",
        Project: "billing",
        Branch:  os.Getenv("VADYL_BRANCH"), // optional
    })

    ctx := context.Background()
    me, err := vadyl.Identity.Me(ctx)
    if err != nil { log.Fatal(err) }
    _ = me
}
2. Read

List, filter, paginate

Typed filter expressions, cursor pagination, eager relation loading.

list_orders.goGo
// Typed filter, sort, pagination, and relation expansion
recent, err := vadyl.Orders.List(ctx, sdk.OrderListReq{
    Filter: sdk.OrderFilter{
        Status:    sdk.In("paid", "fulfilled"),
        Total:     sdk.Gt(100),
        CreatedAt: sdk.Gte("now-30d"),
    },
    Sort:     []sdk.Sort{{Field: "createdAt", Direction: "desc"}},
    PageSize: 50,
    Include:  []string{"customer", "items.product"},
})
if err != nil { return err }

// recent.Data: []Order
// recent.Page: { Number, Size, TotalCount, Next, Prev }
fmt.Printf("%d orders, next: %s\n", len(recent.Data), recent.Page.Next)
3. Write

Create, update, delete with idempotency

Every mutation supports idempotency keys. Retries are safe by default.

create_customer.goGo
// Idempotent create — safe to retry
customer, err := vadyl.Customers.Create(ctx, sdk.CustomerCreateInput{
    Email: "ada@example.com",
    Name:  "Ada Lovelace",
}, sdk.WithIdempotencyKey(fmt.Sprintf("signup:%s", session.ID)))
if err != nil { return err }

// Update with optimistic concurrency
updated, err := vadyl.Customers.Update(ctx, customer.ID,
    sdk.CustomerUpdate{Name: sdk.Ptr("Ada L.")},
    sdk.WithIfMatch(customer.ConcurrencyToken))

// Delete (soft-delete on entities with that lifecycle)
err = vadyl.Customers.Delete(ctx, customer.ID)
4. Realtime

Subscribe to entity changes

Field names only — never values. Re-read for values through CRUD with proper access enforcement.

subscribe.goGo
// Channel-based subscription with the same filter AST as queries
sub, err := vadyl.Orders.Subscribe(ctx,
    sdk.OrderFilter{Status: sdk.Eq("paid")},
    sdk.WithKinds(sdk.KindCreated, sdk.KindUpdated))
if err != nil { return err }
defer sub.Close()

for evt := range sub.Events() {
    // evt.Kind, evt.EntityID, evt.ChangedFields, evt.OccurredAt
    // Field NAMES only — re-read for values
    order, err := vadyl.Orders.Read(ctx, evt.EntityID)
    if err != nil { continue }
    log.Printf("paid: %v\n", order)
}
5. Workflows

Start and signal durable workflows

Long-running product behavior that survives process restart. Same client interface; canonical durability underneath.

workflow_client.goGo
// Start a durable workflow
run, err := vadyl.Workflows.FulfillOrder.Start(ctx, sdk.FulfillOrderInput{
    OrderID: "ord_abc",
})
if err != nil { return err }

// Send a signal (e.g. from a webhook)
err = vadyl.Workflows.FulfillOrder.Signal(ctx, run.ID, "shipped",
    map[string]any{"trackingNumber": "1Z..."})

// Query run state
state, err := vadyl.Workflows.FulfillOrder.Query(ctx, run.ID)
6. Agents

Run agents against the product model

Typed plan IR, capability-aware model routing, token accounting — all behind one method.

run_agent.goGo
// Run an agent — typed plan IR, capability-aware model routing
run, err := vadyl.Agents.SupportAgent.Run(ctx, sdk.AgentRunInput{
    Prompt: "Refund order #12345 due to defect",
    UserID: session.UserID,
    Budget: sdk.AgentBudget{MaxTokens: 50000, MaxToolCalls: 30},
})
if err != nil { return err }

// Stream the run
for step := range run.Stream(ctx) {
    log.Printf("%s: %s\n", step.Kind, step.Summary)
}

// Recall memory
facts, err := vadyl.Agents.SupportAgent.Memory.Recall(ctx, sdk.RecallReq{
    Kind:    "preference",
    Subject: session.UserID,
})
7. Errors

Typed error contract

Stable error codes, stable reason codes, correlation IDs, and explainability links.

errors.goGo
import "errors"

_, err := vadyl.Orders.Update(ctx, id,
    sdk.OrderUpdate{Status: sdk.Ptr("refunded")})

var (
    accessErr   *sdk.AccessDeniedError
    conflictErr *sdk.ConflictError
    validErr    *sdk.ValidationError
    quotaErr    *sdk.QuotaExceededError
)

switch {
case errors.As(err, &accessErr):
    log.Printf("denied: %s (%s)", accessErr.ReasonCode, accessErr.CorrelationID)
case errors.As(err, &conflictErr):
    // optimistic-concurrency mismatch — re-read and retry
case errors.As(err, &validErr):
    for _, fe := range validErr.FieldErrors { log.Printf("%s: %s", fe.Field, fe.ReasonCode) }
case errors.As(err, &quotaErr):
    log.Printf("quota %s exceeded; resets %s", quotaErr.Kind, quotaErr.ResetAt)
}
8. Authoring runtime

Define handlers, workflows, agents

The same package you use as a client also powers your authored runtime — defineCoreHandler, defineWorkflow, defineAgent.

handlers/orders/charge.goGo
package orders

import "go.vadyl.dev/sdk/handler"

type ChargeInput  struct{ OrderID string `json:"orderId"` }
type ChargeResult struct{ OK bool; ChargeID string }

var Charge = handler.Core(func(ctx *handler.Ctx, in ChargeInput) (ChargeResult, error) {
    order, err := ctx.Entities.Order.Read(in.OrderID)
    if err != nil { return ChargeResult{}, err }

    charge, err := ctx.Connections.Stripe.CreateCharge(handler.StripeChargeInput{
        Amount:         order.Total,
        Currency:       order.Currency,
        IdempotencyKey: fmt.Sprintf("charge:%s", order.ID),
    })
    if err != nil { return ChargeResult{}, err }

    if err := ctx.Entities.Order.Update(order.ID, handler.OrderUpdate{
        Status:   handler.Ptr("paid"),
        ChargeID: handler.Ptr(charge.ID),
    }); err != nil { return ChargeResult{}, err }

    _ = ctx.Events.Emit("order.paid", map[string]any{"orderId": order.ID})
    return ChargeResult{OK: true, ChargeID: charge.ID}, nil
})

What you get

Generated typed clients

Per-entity typed methods, struct types for every field. go-vet clean. errcheck clean.

Manifest verification

The SDK refuses to talk to a server whose generated-format version it does not support. Fail closed.

Realtime built-in

WebSocket and SSE subscriptions through nhooyr/websocket. Channel-based event delivery. Reconnect-safe.

Context-first

Every method takes context.Context. Graceful cancellation, deadline propagation, request-scoped values throughout.

Zero CGo

Pure Go. Cross-compiles cleanly to Linux, macOS, Windows, FreeBSD on amd64 and arm64.

Branch-aware

Set Options.Branch or VADYL_BRANCH env. Sandbox testing without leaving prod.

OpenTelemetry

Built-in OTel tracing and metrics. Spans on every canonical operation.

Agent primitives

client.Agents exposes the Agent plane: definitions, runs, memory, MCP exposure.

Connections

Typed governed-connection clients per registered governed connection.

Build with the Go SDK in minutes.

Install the package and work with your product model through typed entities, workflows, agents, and events.