Skip to content

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.

python
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.

python
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.

python
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.

python
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

python
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

python
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.

python
# 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

python
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).

python
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

python
await client.flags.delete("checkout-v2")
# or:  await checkout.delete()

Sync Client (Python)

For synchronous applications, use SmplClient instead of AsyncSmplClient:

python
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