Flags and rules
One primitive underneath everything: a typed value with rules. A feature flag is just the boolean case of remote config.
Types
A flag holds a boolean, a string, a number, or arbitrary JSON. The type is fixed when the flag is created, and every value it serves is checked against it: a number flag can never publish a string.
Environments
A flag is defined once for the project and configured separately in each environment. That split is what makes promoting a change from development to production a value change rather than a create.
Rules
Rules are ordered and matched top to bottom. The first rule whose conditions all match wins; anyone matching none gets the default. A rule with no conditions matches everyone who reaches it, which makes it a useful catch-all at the bottom.
iOS 2.4 and above, half of them -> true
Anyone whose email ends @aurora.app -> true
Otherwise -> falseAttributes
Conditions match against the context you pass to the provider. userId and deviceId are reserved; everything else comes from attributes. platform, appVersion, osVersion, country and locale are conventions, not special cases; you can match on anything you attach.
An attribute you did not send never matches, including with is not. Klor cannot prove a user is not on iOS when it was never told what they are on.
Percentage rollouts
A rule can apply to a share of the users who match it. Everyone else falls through to the next rule, so “roll out to 25% of iOS users” reads the way it sounds.
Bucketing is a stable hash of the flag key, a per-flag salt, and the attribute you bucket by. Three consequences worth relying on:
Stableper userThe same person lands in the same bucket on every launch and on every platform. Nobody flickers between variants.
Monotonicper rolloutRaising 10% to 20% only ever adds people. Anyone already seeing the feature keeps seeing it.
Independentper flagTwo flags at 10% hit different users, so the same unlucky tenth is not the only group ever seeing anything new.
A user with no value for the bucketing attribute falls through instead of being assigned at random; otherwise an anonymous user would get a different answer on every launch.
Sensitive flags
Marking a flag sensitive removes it from the payload public keys receive. This is the only confidentiality boundary Klor has: a public key ships inside your app and can be extracted, so everything else in that payload should be considered readable by anyone.