Flags Management
Most customers create and configure flags via the Console UI. The management API is for infrastructure-as-code, CI/CD pipelines, setup scripts, and automated testing.
Management runs through the flags surface of the smplkit client (SmplClient, or AsyncSmplClient for async) — client.flags (Python, TypeScript, Java), client.Flags (C#), or client.Flags() (Go).
Create a Boolean Flag
The flag is created locally — nothing hits the server until save() is called.
import asyncio
from smplkit import AsyncSmplClient
async with AsyncSmplClient() as client:
checkout = client.flags.new_boolean_flag(
"checkout-v2",
default=False,
description="Controls rollout of the new checkout experience.",
)
await checkout.save()Create a String Flag
String flags can be constrained (closed set of allowed values) or unconstrained. The values parameter defines the allowed set — the Console UI shows a dropdown for value selection.
from smplkit import FlagValue
banner = client.flags.new_string_flag(
"banner-color",
default="red",
name="Banner Color",
description="Controls the banner color shown to users.",
values=[
FlagValue(name="Red", value="red"),
FlagValue(name="Green", value="green"),
FlagValue(name="Blue", value="blue"),
],
)
await banner.save()Create a Number Flag
Omit values for an unconstrained number flag — any number is valid. Useful for tunables like thresholds, retry counts, and timeouts.
retries = client.flags.new_number_flag(
"max-retries",
default=3,
description="Maximum number of API retries before failing.",
)
await retries.save()Create a JSON Flag
JSON flags serve complex configuration objects. Like string flags, they can be constrained to a set of predefined values.
from smplkit import FlagValue
theme = client.flags.new_json_flag(
"ui-theme",
default={"mode": "light", "accent": "#0066cc"},
description="Controls the UI theme configuration.",
values=[
FlagValue(name="Light", value={"mode": "light", "accent": "#0066cc"}),
FlagValue(name="Dark", value={"mode": "dark", "accent": "#66ccff"}),
FlagValue(name="High Contrast",
value={"mode": "dark", "accent": "#ffffff"}),
],
)
await theme.save()Targeting Rules
Rules define conditions under which a flag serves a specific value. Build rules with the fluent Rule builder. The environment is required — it scopes the rule to a single environment. Multiple .when() calls within a rule are AND-ed together.
Supported operators: ==, !=, >, <, >=, <=, in, contains. Python and TypeScript also expose them as Op.EQ, Op.NEQ, etc.
Single-condition rule
from smplkit import Op, Rule
checkout.add_rule(
Rule("Enable for enterprise users", environment="staging")
.when("user.plan", Op.EQ, "enterprise")
.serve(True)
)
await checkout.save()Multi-condition rule
checkout.add_rule(
Rule("Enable for enterprise users in US region", environment="staging")
.when("user.plan", Op.EQ, "enterprise")
.when("account.region", Op.EQ, "us")
.serve(True)
)
await checkout.save()Per-Environment Defaults and Kill Switch
Each environment has its own default value (falls back to the flag default if unset) and an enabled flag (the kill switch). When enabled is false, rules are skipped and the per-environment default is served.
# Per-environment default — wins over the base flag default in this env.
checkout.set_default(False, environment="production")
# Kill switch — bypass all targeting rules in production.
checkout.disable_rules(environment="production")
checkout.enable_rules(environment="staging")
# Revert overrides:
checkout.clear_default(environment="production")
checkout.clear_rules(environment="staging") # remove every rule on staging
await checkout.save()List and Get Flags
all_flags = await client.flags.list()
for f in all_flags:
envs = list(f.environments.keys()) if f.environments else []
print(f" {f.id} ({f.type}) — default={f.default}, environments={envs}")
fetched = await client.flags.get("checkout-v2")
print(f"id={fetched.id}, type={fetched.type}, default={fetched.default}")Update a Flag
Fetch a flag, mutate, save. Constrained-flag values can be added with add_value/addValue/AddValue and removed wholesale with clear_values/clearValues/ClearValues (which makes the flag unconstrained).
banner.add_value("Purple", "purple")
banner.default = "blue"
banner.description = "Controls the banner color — updated"
banner.add_rule(
Rule("Purple for enterprise users", environment="production")
.when("user.plan", Op.EQ, "enterprise")
.serve("purple")
)
await banner.save()Delete a Flag
await client.flags.delete("checkout-v2")
# or: await checkout.delete()Sync Client (Python)
For synchronous applications, use SmplClient instead of AsyncSmplClient:
from smplkit import SmplClient, Op, Rule
with SmplClient() as client:
flag = client.flags.new_boolean_flag("my-flag", default=False)
flag.save()
flag = client.flags.get("my-flag")
flag.add_rule(
Rule("...", environment="staging")
.when("user.plan", Op.EQ, "enterprise")
.serve(True)
)
flag.save()
client.flags.delete("my-flag")Next Steps
- Flags Runtime — Declare flags in code, evaluate locally, react to changes
- Smpl Logging — Control log verbosity without redeploying
- API Reference — Flags — Full REST API documentation

