RuleBox RuleBox
Star
ColdBox BoxLang The rules engine for ColdBox and BoxLang

Business rules,
without the business logic mess!

RuleBox turns tangled if/else blocks into named rules you can read, test and audit. Given some facts, when a condition holds, then act. Write them in BoxLang, YAML, JSON or even the database and your business rules can change without a deploy.

$ box install rulebox
BoxLang 1.18+ColdBox 8+Apache 2.0
LoanApproval.bx
class extends="rulebox.models.RuleBook" {

  function defineRules(){
    addRule(
      newRule( "declineLowScores" )
        .withPriority( 20 )
        .when( ( facts ) => facts.creditScore < 580 )
        .then( ( facts, result ) => result.setValue( "DECLINED" ) )
        .stop()
    )
    addRule(
      newRule( "autoApprove" )
        .when( ( facts ) => facts.creditScore >= 680 )
        .except( ( facts ) => facts.requestedAmount > 500000 )
        .then( ( facts, result ) => result.setValue( "APPROVED" ) )
    )
  }
}
// in any handler
ruleBook( "loan" )
  .run( { creditScore: 720, requestedAmount: 250000 } )
  .getResult().getValue() // "APPROVED"
One-minute tour

See the Rule Visualizer in action

Dashboard, chain view, dry runs, rule health, errors with stack traces and the live tracker, recorded against the RuleBox test app.

How a rule runs

Facts in. A decision out. Every step recorded.

Rules run in priority order. Each one checks its condition, acts or skips, and can stop the chain. The audit trail shows exactly what happened.

Facts

run( facts )

A struct of name and value pairs: the data you decide on, declared and checked if you want.

When

.when( ... )

Each rule tests its condition, in priority order.

Except

.except( ... )

An exception skips the rule even when the condition holds.

Then

.then( ... )

Actions run, set the result, and can stop the chain.

Result

.getResult()

One answer, plus an audit trail of every rule.

Code or data

The same rule, two ways.

Keep logic that rarely changes in BoxLang. Move thresholds that change often into JSON, YAML or a database table, and load them at runtime.

In BoxLangLoanApproval.bx
newRule( "declineLowScores" )
  .withDescription( "Declines a score under 580" )
  .withPriority( 20 )
  .when( ( facts ) => facts.creditScore < 580 )
  .then( ( facts, result ) =>
    result.setValue( "DECLINED" )
  )
  .stop()
As data
config/rules/loan.json
- name: declineLowScores
  description: Declines a score under 580
  priority: 20
  when:
    lt: [ creditScore, 580 ]
  then:
    - action: decide
      params: { decision: DECLINED }
  stop: true
{
  "name": "declineLowScores",
  "description": "Declines a score under 580",
  "priority": 20,
  "when": { "lt": [ "creditScore", 580 ] },
  "then": [ { "action": "decide",
    "params": { "decision": "DECLINED" } } ],
  "stop": true
}
Rule Visualizer

See your rules. Watch them fire.

A built-in admin UI: browse every rulebook, view its chain in run order, dry-run any facts, find the rules that fail or run slow, read each error with its stack trace, and stream evaluations live.

Turn it on in one setting
Tutorial Course

Learn RuleBox in ten short lessons.

Build a loan decision from a single if statement to rules in a file, running inside ColdBox and showing up in the Visualizer.

Start lesson 1
  1. 01 What is RuleBox?
  2. 02 Your First Rule
  3. 03 Facts and Results
  4. 04 More Rules
  5. 05 See What Happened
  6. 06 Rules from JSON
  7. 07 RuleBooks in ColdBox
  8. 08 When Things Go Wrong
  9. 09 The Visualizer
  10. 10 Where to Go Next
Built on the Ortus stack