Snippets
Minimal copy-paste blocks for flags, configs, kill switches, experiments and i18n.
Minimal copy-paste blocks, grouped by the registry taxonomy. These are the same leaves the docs get op returns.
release
release / flags
Read a feature flag on a user-bound client. Assumes configure() ran at
startup — see Installation.
Basic check
import shipeasy
# construct once per callsite (cheap; binds the user)
client = shipeasy.Client(current_user)
# name flag name (required)
# default=False returned ONLY when the flag can't be evaluated
# (client not ready / flag absent) — never when it
# simply resolves off
if client.get_flag("{{FLAG_KEY}}", default=False):
...Why it resolved that way — get_flag_detail
import shipeasy
client = shipeasy.Client(current_user)
# returns FlagDetail(value, reason); reason ∈ RULE_MATCH / DEFAULT / OFF /
# OVERRIDE / FLAG_NOT_FOUND / CLIENT_NOT_READY
detail = client.get_flag_detail("{{FLAG_KEY}}")
log.info("flag=%s value=%s reason=%s", "{{FLAG_KEY}}", detail.value, detail.reason)React to flag changes (long-running server)
import shipeasy
# requires configure(poll=True); fires after a poll fetches NEW data (200, not 304)
unsubscribe = shipeasy.on_change(lambda: rebuild_local_cache())
# ... later: unsubscribe()release / configs
Read a dynamic config on a user-bound client. Assumes configure() ran at
startup — see Installation.
Raw value
import shipeasy
# construct once per callsite (cheap; binds the user)
client = shipeasy.Client(current_user)
# name config name (required)
# default={} returned when the key is absent (or decode raises)
config = client.get_config("{{CONFIG_KEY}}", default={})Typed decode
import shipeasy
client = shipeasy.Client(current_user)
# decode=lambda v: ... transform the raw JSON value into the shape you want;
# applied on top of overrides — if it raises, default is returned
max_items = client.get_config("{{CONFIG_KEY}}", decode=lambda v: v["max"], default=0)release / killswitches
Check a kill switch on a user-bound client. Assumes configure() ran at
startup — see Installation.
Top-level guard
import shipeasy
# construct once per callsite (cheap; binds the user)
client = shipeasy.Client(current_user)
# name kill switch name (required)
if client.get_killswitch("{{KILLSWITCH_KEY}}"): # True == engaged (feature killed)
return fallback()Named switch — check one configured per-key switch
import shipeasy
client = shipeasy.Client(current_user)
# switch_key the variable you check against the switches
# CONFIGURED on the kill switch (dashboard "switches");
# if that key isn't configured, falls back to the
# top-level value above
provider = "stripe"
if client.get_killswitch("{{KILLSWITCH_KEY}}", provider):
return use_backup_processor() # the "stripe" switch is engagedrelease / experiments
Read an experiment, log exposure where you present the treatment, then track its
success event. Assumes configure() ran at startup — see Installation.
import shipeasy
# construct once per callsite (cheap; binds the user)
client = shipeasy.Client(current_user)
# name experiment name (required)
# default_params={...} params returned when the user isn't enrolled
# decode=lambda p: ... optional: transform the params bag (typed)
result = client.get_experiment("{{EXPERIMENT_KEY}}", default_params={"color": "blue"})
# call where you actually render the treatment (server is stateless — no auto-log)
client.log_exposure("{{EXPERIMENT_KEY}}") # experiment name (required)
if result.params["color"] == "green":
...
# track the conversion on the same bound client; unit is the bound user
# event_name success event (required)
# properties={...} optional event properties bag
client.track("{{SUCCESS_EVENT}}", {"amount": 49})metrics
metrics / track
Track a metric/conversion event from the bound client. Metrics in the dashboard
are computed from these events. Assumes configure() ran at startup — see
Installation.
Track an event
import shipeasy
# construct once per callsite (cheap; binds the user)
client = shipeasy.Client(current_user)
# event_name the event your metric is built on (required)
# properties={...} optional payload; numeric/string fields you can
# sum/filter on in a metric (private attributes are
# stripped before the event leaves the process)
client.track("{{EVENT_NAME}}", {"amount": 49, "currency": "usd"})Fire-and-forget (never blocks your response) and a no-op under
configure_for_testing / configure_for_offline. The unit is the bound user
(user_id, else anonymous_id); with no unit the call is a no-op.
Track without properties
import shipeasy
client = shipeasy.Client(current_user)
client.track("{{EVENT_NAME}}") # properties are optionali18n
i18n / setup
This is a server SDK: it has no t(). During SSR, emit the i18n loader tag
(public CLIENT key) so the browser SDK boots against the {{PROFILE}} profile.
Assumes configure() ran at startup — see Installation.
i18n loader tag only
import shipeasy
# Package-level helper — delegates to the engine configured at startup.
# client_key PUBLIC client key (sdk_client_...) — NOT the server key
# profile="en:prod" locale profile to boot the browser SDK against
# base_url=... optional: override the CDN origin (default cdn.shipeasy.ai)
head = shipeasy.i18n_script_tag(client_key, "{{PROFILE}}") # goes in <head>Flags bootstrap + i18n together
import shipeasy
user = {"user_id": "u_123"}
# bootstrap_script_tag carries the evaluated flags (NO key); i18n_script_tag adds
# the loader (public client key). Both go in <head>.
# anon_id=... the request's __se_anon_id, so the browser buckets identically
# i18n_profile=... fold the i18n profile into the bootstrap tag instead
head = shipeasy.bootstrap_script_tag(user, anon_id=anon_id) \
+ shipeasy.i18n_script_tag(client_key, "{{PROFILE}}")i18n / render
Labels render in the browser, via the Shipeasy client SDK's t() — the
Python server SDK has no render helper. Once the loader tag (see setup) is in
<head>, the client renders translated text:
// browser (Shipeasy client SDK), profile {{PROFILE}}
t("checkout.cta");ops
ops / see
Report a caught, handled error (or a non-exception "violation") to Shipeasy with
see() — fire-and-forget, never re-raises. Package-level, so it reports against
the engine from configure(). Assumes configure() ran at startup — see
Installation.
Report a handled exception
from shipeasy import see
try:
charge(order)
except PaymentError as e:
# .causes_the(subject) what the error affects (e.g. "checkout")
# .to(outcome) the terminal — what you do about it; builds + fires
see(e).causes_the("checkout").to("use the backup processor")
fallback_charge(order)Attach context with .extras(...)
from shipeasy import see
try:
charge(order)
except PaymentError as e:
# .extras(mapping) structured fields attached to the report
see(e).causes_the("checkout").extras({"order_id": oid}).to("use cached prices")Report a non-exception violation
from shipeasy import see_violation
# a bad state that isn't an exception — same chain, .to() is the terminal
see_violation("missing_invoice").causes_the("billing").to("skip the dunning email")Mark an expected exception — report NOTHING
from shipeasy import control_flow_exception
try:
parse(token)
except StopIteration as e:
# transmits nothing; .because(...) / .extras() are local-debug only
control_flow_exception(e).because("end of stream is expected")Admin API client (optional) — `shipeasy.admin`
The base SDK evaluates flags, configs, and experiments (configure() + shipeasy.Client(user)). The Admin API client is a separate, optional surface for…
Agent skill
Installable LLM skill for the Python SDK (configure() + Client(user), evaluate, experiment + track, testing).