Shipeasy
ReferenceGo

Agent skill

Installable LLM skill for the Go SDK (configure() + Client(user), evaluate, experiment + track, testing).

An installable agent skill for the Go SDK. Fetch it with shipeasy docs skill --sdk go (--install writes it to your agent skills dir), or copy it below — the YAML frontmatter installs with it.

---
name: shipeasy-go
description: Use Shipeasy (feature flags, configs, kill switches, A/B experiments, i18n) from Go. Covers Configure() + NewClient(user), GetFlag/GetConfig/GetExperiment/GetKillswitch, Track, testing, OpenFeature.
---

# Shipeasy Go SDK

Server-side Go SDK for Shipeasy. Evaluation is local against a cached blob — no
network on the hot path. Min Go 1.21.

> The documented surface is exactly **`Configure()`** (setup) and the bound
> **`NewClient(user)`** (use), plus the package-level helpers below. For deeper
> docs, fetch any page/snippet from the manifest at
> <https://shipeasy-ai.github.io/sdk-go/manifest.json> (raw URLs below).

## Install

```bash
go get github.com/shipeasy-ai/sdk-go
```

```go
import shipeasy "github.com/shipeasy-ai/sdk-go"
```

## Configure once, bind per request

```go
// Once at process start. The api key lives here.
shipeasy.Configure(shipeasy.Options{
    APIKey: os.Getenv("SHIPEASY_SERVER_KEY"),
    // Optional: map YOUR user type → the Shipeasy attribute map.
    Attributes: func(u any) shipeasy.User {
        acct := u.(*Account)
        return shipeasy.User{"user_id": acct.ID, "plan": acct.Plan}
    },
    // Poll: true,  // long-running server: keep flags fresh with a background poll
})

// Per request: bind the user once, call with NO user argument.
c := shipeasy.NewClient(acct)            // or NewClient(shipeasy.User{"user_id": "u_123"})
```

`Configure` is first-config-wins and owns the fetch lifecycle (one-shot by
default; `Poll: true` for a background refresh — you never call `Init` yourself).
`NewClient` panics if called before `Configure`. Reference:
<https://shipeasy-ai.github.io/sdk-go/pages/configuration.md>

## Evaluate

```go
c := shipeasy.NewClient(acct)                        // construct once per callsite
on := c.GetFlag("new_checkout")                      // bool
on = c.GetFlagOr("new_checkout", true)               // fallback only when UNEVALUATABLE
d := c.GetFlagDetail("new_checkout")                 // d.Value, d.Reason

cfg, ok := c.GetConfig("billing_copy")               // (any, bool)
fallback := c.GetConfigOr("billing_copy", map[string]any{"cta": "Buy"})

paused := c.GetKillswitch("payments_paused")         // true = killed
// Named switch: GetKillswitch(name, switchKey) — an unconfigured key falls back
// to the kill switch's top-level value.
```

`GetFlagOr` returns the fallback only on reason `CLIENT_NOT_READY` /
`FLAG_NOT_FOUND` — a gate that evaluates to `false` returns `false`. Reference:
<https://shipeasy-ai.github.io/sdk-go/pages/flags.md> ·
<https://shipeasy-ai.github.io/sdk-go/pages/killswitches.md>

## Experiments + track (Client-only, end to end)

```go
c := shipeasy.NewClient(acct)                        // construct once per callsite
r := c.GetExperiment("checkout_button", map[string]any{"color": "blue"})
// r.InExperiment bool, r.Group string, r.Params any (defaultParams when not enrolled)

c.LogExposure("checkout_button")                     // record where you present the treatment
c.Track("purchase", map[string]any{"amount": 49})    // conversion for the bound user
```

Reference: <https://shipeasy-ai.github.io/sdk-go/pages/experiments.md> · track
snippet <https://shipeasy-ai.github.io/sdk-go/snippets/metrics/track.md>

## Anonymous traffic

```go
http.ListenAndServe(":8080", shipeasy.Middleware(mux)) // mints __se_anon_id cookie
// in a handler:
c := shipeasy.NewClient(shipeasy.User{"anonymous_id": shipeasy.AnonID(r)})
```

## Error reporting — See()

```go
if err := chargeCard(o); err != nil {
    shipeasy.See(err).CausesThe("checkout").
        Extras(map[string]any{"order_id": o.ID}).
        To("use the backup processor")   // .To(...) is the terminal — sends the report
}
// Expected control flow reports NOTHING:
shipeasy.ControlFlowException(err).Because("because empty-state path")
```

Reference: <https://shipeasy-ai.github.io/sdk-go/pages/error-reporting.md> · snippet
<https://shipeasy-ai.github.io/sdk-go/snippets/ops/see.md>

## Testing (zero network)

```go
// Seed values up front; reads go through the ordinary NewClient(user). Replaces
// prior config, so each test can reconfigure freely.
shipeasy.ConfigureForTesting(shipeasy.TestOptions{
    Flags:       map[string]bool{"new_checkout": true},
    Configs:     map[string]any{"billing_copy": map[string]any{"cta": "Buy now"}},
    Experiments: map[string]shipeasy.ExperimentOverride{"checkout_button": {Group: "treatment", Params: map[string]any{"color": "green"}}},
})
c := shipeasy.NewClient(shipeasy.User{"user_id": "u_1"})
c.GetFlag("new_checkout") // true

shipeasy.OverrideFlag("new_checkout", false) // flip on the spot
shipeasy.ClearOverrides()                    // drop every override (incl. the seed)

// Offline: evaluate the REAL rules from a snapshot or JSON file, no network.
_, _ = shipeasy.ConfigureForOffline(shipeasy.OfflineOptions{Path: "shipeasy-snapshot.json"})
```

Reference: <https://shipeasy-ai.github.io/sdk-go/pages/testing.md>

## OpenFeature (separate nested module)

```bash
go get github.com/shipeasy-ai/sdk-go/openfeature
```

```go
import shipeasyof "github.com/shipeasy-ai/sdk-go/openfeature"

// Assumes shipeasy.Configure(...) ran — the global provider resolves it.
_ = openfeature.SetProviderAndWait(shipeasyof.NewGlobalProvider())
// boolean flags → gates; string/float/int/object → dynamic configs.
```

Reference: <https://shipeasy-ai.github.io/sdk-go/pages/openfeature.md>

## i18n

Server-side only: emit `shipeasy.I18nScriptTag(clientKey, "en:prod", opts)` in the
page `<head>` (public client key). The browser client SDK's `t()` renders the
labels. There is no server-side `t()` in Go. Reference:
<https://shipeasy-ai.github.io/sdk-go/pages/i18n.md>

## Change listeners

`shipeasy.OnChange(func(){ /* reloaded */ })` fires after a background poll
fetches new data — requires `Configure(shipeasy.Options{Poll: true})`. Reference:
<https://shipeasy-ai.github.io/sdk-go/pages/advanced.md>
Was this page helpful?
✎ Edit this page