Shipeasy
ReferenceJava

Agent skill

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

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

---
name: shipeasy-java
description: Use Shipeasy (feature flags, configs, kill switches, A/B experiments, i18n) from Java. Covers configure() + Client(user), getFlag/getConfig/getExperiment, track, testing, OpenFeature.
---

# Shipeasy Java SDK

Server-side Java SDK for Shipeasy. Evaluate feature flags, dynamic configs, kill
switches, and A/B experiments locally against a cached rules blob. Java 11+.

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

## Install

Maven (`ai.shipeasy:shipeasy`):

```xml
<dependency>
  <groupId>ai.shipeasy</groupId>
  <artifactId>shipeasy</artifactId>
  <version>0.10.0</version>
</dependency>
```

## Configure once, bind per user

```java
import ai.shipeasy.Shipeasy;
import ai.shipeasy.Client;
import ai.shipeasy.ExperimentResult;
import java.util.Map;

// Once, at startup. Builds the global engine + kicks off the initial fetch.
// Map your own user object with a one-time attributes transform (optional).
Shipeasy.configure(Shipeasy.options(System.getenv("SHIPEASY_SERVER_KEY"))
    .attributes((Object u) -> {
        MyUser my = (MyUser) u;
        return Map.of("user_id", my.id(), "plan", my.plan());
    }));
// Long-running server: .poll(true) keeps flags fresh with a background poll —
// you never call init() yourself.

// Per user / per request — user bound at construction, no user arg per call.
Client c = new Client(myUser);                              // construct once per callsite
boolean enabled = c.getFlag("new_checkout");               // bool gate
boolean withDef = c.getFlag("new_checkout", true);         // default only when unresolvable
Object cfg      = c.getConfig("billing_copy", Map.of());   // dynamic config (+ fallback)
boolean killed  = c.getKillswitch("panic_button");         // kill switch
// Named switch: getKillswitch(name, switchKey) — an unconfigured key falls back
// to the kill switch's top-level value.
```

`Shipeasy.configure` is first-config-wins; `new Client(user)` throws if called
before it. Reference:
<https://shipeasy-ai.github.io/sdk-java/pages/configuration.md> ·
<https://shipeasy-ai.github.io/sdk-java/pages/flags.md>

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

```java
Client c = new Client(myUser);                             // construct once per callsite
ExperimentResult r = c.getExperiment("checkout_button", Map.of("color", "blue"));
if (r.inExperiment && "treatment".equals(r.group)) { /* render variant from r.params */ }

c.logExposure("checkout_button");                          // record where you present it
c.track("purchase", Map.of("amount", 49));                 // conversion for the bound user
```

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

## Error reporting — see()

```java
import static ai.shipeasy.See.see;
try {
    chargeCard(order);
} catch (Exception e) {
    see(e).causesThe("checkout").extras(Map.of("order_id", order.id()))
          .to("use the backup processor");
}
```

`.to(outcome)` is the terminal (fire-and-forget POST). Use
`controlFlowException(e).because("...")` to mark expected control flow (reports
nothing); `violation("name")...to("...")` for non-throwable problems. Reference:
<https://shipeasy-ai.github.io/sdk-java/pages/error-reporting.md> · snippet
<https://shipeasy-ai.github.io/sdk-java/snippets/ops/see.md>

## Testing (no network, no key)

```java
import ai.shipeasy.Shipeasy;
import ai.shipeasy.Client;
import java.util.Map;

// Seed values up front; reads go through the ordinary new Client(user). Replaces
// prior config, so each test can reconfigure freely.
Shipeasy.configureForTesting(Shipeasy.testOptions()
    .flags(Map.of("new_checkout", true))
    .configs(Map.of("billing_copy", Map.of("title", "Hello")))
    .experiments(Map.of("checkout_button", Shipeasy.Variant.of("treatment", Map.of("color", "green")))));
boolean on = new Client(Map.of("user_id", "u_1")).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-java/pages/testing.md>

## OpenFeature

```java
import dev.openfeature.sdk.OpenFeatureAPI;
import ai.shipeasy.openfeature.ShipeasyProvider;

// Assumes Shipeasy.configure(...) ran — the no-arg provider resolves it.
OpenFeatureAPI.getInstance().setProviderAndWait(new ShipeasyProvider());
```

Booleans → gates; strings/numbers/objects → dynamic configs. `targetingKey`
`user_id`. Reference:
<https://shipeasy-ai.github.io/sdk-java/pages/openfeature.md>

## Advanced

- **Anonymous bucketing:** register `AnonIdFilter` (servlet `Filter`) — mints the
  `__se_anon_id` cookie.
- **Private attributes / sticky bucketing:** `Shipeasy.options(key)
.privateAttributes(List.of("email")).stickyStore(new InMemoryStickyStore())`.
- **SSR:** package-level `Shipeasy.bootstrapScriptTag(user, anonId, profile, baseUrl)`
  - `Shipeasy.i18nScriptTag(clientKey, "en:prod")`.
- **Change listeners:** `Shipeasy.onChange(() -> ...)` (requires `.poll(true)`;
  returns a cancel `Runnable`).

Reference: <https://shipeasy-ai.github.io/sdk-java/pages/advanced.md> ·
<https://shipeasy-ai.github.io/sdk-java/pages/i18n.md>

## i18n

This is a **server** SDK — it has **no `t()`**. It emits the loader `<script>` tag
(`Shipeasy.i18nScriptTag(clientKey, profile)`, using the PUBLIC client key) so the
**browser** client SDK renders translations.
Was this page helpful?
✎ Edit this page