Konditional¶
Konditional is a Kotlin-first feature-flag library for teams that want typed
evaluation, deterministic runtime behavior, and explicit trust boundaries.
You declare features as Kotlin properties inside a Namespace, evaluate them
against typed Context values, and add JSON loading later without turning the
core model into a string-key registry.
Why teams reach for it¶
Konditional is a good fit when feature flags are part of real product logic and you want the compiler, the type system, and the runtime model to stay aligned.
- Typed values stay typed. Built-in primitives, enums, and
Konstrainedcustom types evaluate to the same Kotlin types you declared. - Evaluation stays deterministic. The same context and the same namespace snapshot produce the same result.
- Ownership stays local. Namespaces keep one team's flags out of another team's runtime surface until sharing is intentional.
- Runtime updates stay atomic. Loading, rollback, disable, and enable operate on whole namespace snapshots.
- Boundary failures stay explicit. JSON loading returns
ParseResultvalues with typedParseErrorfailures instead of silent coercion.
A small typed example¶
The fastest way to see the difference is with a typed eligibility result instead of another boolean.
import io.amichne.konditional.api.evaluate
import io.amichne.konditional.context.Context
import io.amichne.konditional.context.axis.AxisValue
import io.amichne.konditional.context.axis.axes
import io.amichne.konditional.core.Namespace
import io.amichne.konditional.core.dsl.rules.targeting.scopes.constrain
enum class Product : AxisValue<Product> {
PAYMENTS,
LENDING,
REPORTING,
}
enum class ProductEligibility {
NOT_ELIGIBLE,
ELIGIBLE,
MANUAL_REVIEW,
}
data class CommerceContext(
val product: Product,
) : Context {
override val axes = axes(product)
}
object CheckoutFlags : Namespace("checkout") {
val productEligibility by enum<ProductEligibility, CommerceContext>(
default = ProductEligibility.NOT_ELIGIBLE,
) {
rule(ProductEligibility.ELIGIBLE) {
constrain(Product.PAYMENTS, Product.REPORTING)
}
rule(ProductEligibility.MANUAL_REVIEW) {
constrain(Product.LENDING)
}
}
}
val eligibility =
CheckoutFlags.productEligibility.evaluate(
CommerceContext(Product.PAYMENTS),
)
The result is a ProductEligibility, not a string lookup or an untyped
payload. Callers can keep their domain states explicit and exhaustive.
Choose your path¶
This documentation set is organized around the questions evaluators usually ask first.
- Start here if you want to decide whether Konditional fits your team and constraints.
- Quickstart if you want the smallest working path from install to safe JSON loading.
- Concepts if you want the mental model before coding.
- Guides if you need targeted recipes beyond the first run.
- Guarantees if you want the trust contracts backed by the current test suite.
- Reference if you need terse API and format lookup.
What this documentation covers¶
The current repo is the source of truth for this site. The pages map to the published modules and the behaviors they expose today.
konditional-typescovers shared identifiers, contexts, parse results, and custom value contracts.konditional-enginecovers namespaces, rule evaluation, diagnostics, and runtime registry behavior.konditional-jsoncovers snapshot export, strict decode, and safe namespace loading throughParseResult.smoke-testis a verification module, not a published dependency surface.
Next steps¶
The evaluator hub gives the clearest decision support. If you already know you want to try the library, jump straight to the guided install and first namespace.