A policy should be something you can show a person, save in a database, and ask a question of. Give the rule a language instead of burying it in an if-statement.
The rule starts as a small conditional. Then support needs to explain it, an administrator needs to change it, and a second service needs to make the same decision. A callback can compute an answer, but it does not give those consumers a representation they can inspect or edit.
Predicates makes the condition an explicit tree. You define the allowed leaves with Effect Schema and provide their domain meaning. The library handles Boolean composition, validation, normalization, and folding. A rule can keep the same structure while different interpreters evaluate it or turn it into an explanation.
02 What it unlocks
What it unlocks
01
Explain the answer in the vocabulary of the product
A refund policy can say finance, team lead, and maximum amount rather than exposing implementation details. Write a fold that renders those leaves and their Boolean structure into a readable explanation.
02
Build an editor with a finite language
A schema describes which conditions are allowed and what inputs they require. An admin UI can offer supported fields and operators instead of accepting arbitrary code.
03
Store the rule beside its history
JSON-shaped conditions can be versioned and reviewed with the rest of your configuration. Keep the interpreter's meaning and the condition format versioned together so an old rule remains understandable.
03 How to use it
How to use it
Start with one policy that people repeatedly ask engineers to explain. Define its leaves, test a few representative inputs, and add a readable view of the same stored rule before building a full policy editor.
Choose a small domain vocabulary
Define tagged leaf schemas such as Role and MaxAmount. Prefer concepts that a product user can recognize. Decide explicitly what each leaf means in your evaluation context.
Build and decode the condition tree
Create a language with Predicate.nested, then compose it with and/or constructors. Decode stored or externally supplied conditions through that language before using them.
Supply an interpreter for each consumer
Use evaluate with a pure leaf callback for decisions and fold for another representation. A query compiler or explanation renderer is your interpreter, not an automatically generated integration.
Interactive simulation loads when this panel comes into view.
The interactive panel is a Foldkit/Foldworks simulation of the behavior, not an execution of this package. The definition above is an API excerpt; supply your application's domain values and contracts.
04 In practice
In practice
One refund policy answers three audiences.
Finance may approve any refund. A team lead may approve up to $500. Everyone else must escalate. Keep that rule as one tree rather than three disconnected implementations.
Decide
The application evaluates role and amount against the stored condition when a refund is requested.
Explain
A support screen renders the same condition in domain language, so a denied $700 refund has an understandable rule behind it.
Review
A change to the threshold is a change to the rule data. Test representative roles and amounts before accepting the new policy.
05 How it composes
How it composes
Each library owns one kind of meaning. Combine the ones your application needs, with an explicit boundary between their jobs.
If a condition names an entity in configuration, annotate the relevant schema field with a relation and validate its target separately. A well-formed condition can still contain a dangling domain reference.
Use the condition's result at an action boundary or translate supported leaves into action expressions. A rule decides whether something is allowed; an action defines the writes and events that follow. The generic leaf tree needs an interpreter or adapter.
Conditions can inform a process branch after the host records its inputs. The workflow prototype's portable expression API is a separate contract: arbitrary leaf callbacks cannot be serialized into a checkpoint.
The experimental portable-definition API uses core to carry an input contract and expression body together. The published nested-leaf API shown here instead takes a host interpreter. Choose the API and artifact format for your pinned version.
The filesystem design could store policy documents and validate their schema and links with the rest of a project. Cross-document policy constraints are proposed work, not a shipped validator.
These are application composition patterns, not a promise of automatic adapters. Align Effect peers and artifact formats before combining runtimes; source prototypes can differ from published releases.
A Role leaf does not fetch a user or authorize an HTTP request by itself. Evaluate it using the correct context at the actual application boundary; keep leaf callbacks pure.
Normalization does not replace domain tests
The library validates and simplifies Boolean structure. You still define what leaves mean and test the business cases that matter, including changes to those meanings over time.
All libraries are pre-1.0. Pin exact versions and plan for changes to APIs and artifact formats.