Drools-equivalent business rule engine reference implementation
Project description
sparkrules
The business rule engine that Python was missing. Drools-style DRL syntax, explainable decisions, regulatory-grade audit trails - from laptop to lakehouse, no JVM required.
Design scope and known gaps: docs/KNOWN_LIMITATIONS.md (Spark vs Python regex, strategy limits, production checklist).
from sparkrules.executor import RuleExecutor
result = RuleExecutor().run(
{"amount": 1500, "region": "US"},
'rule "high-value" when $f : Fact( amount > 1000 ) then result.risk = "high"; end',
)
print(result.fired) # True
print(result.action_output) # {'risk': 'high'}
Install
pip install sparkrules # core engine only
pip install sparkrules[api] # + FastAPI server and Workbench UI
pip install sparkrules[spark] # + PySpark cluster integration
pip install sparkrules[all] # everything
Running uvicorn sparkrules.api.app:create_app without [api] installed raises a clear ImportError pointing at pip install 'sparkrules[api]'. See also docs/KNOWN_LIMITATIONS.md.
Who is this for?
| If you are... | SparkRules gives you... |
|---|---|
| Migrating from Drools | Same DRL syntax, no JVM, Python-native - drop your .drl files in and go |
| Building a decisioning service | FastAPI server + browser Workbench + versioned rules in one package |
| Running rules on Spark | apply_drl(df, drl) distributes evaluation across your cluster - same rules, distributed execution |
| In a regulated industry | Adverse-action reason aggregation (ECOA/FCRA/GDPR Art 22), audit trails, deterministic replay |
| Tired of if/else chains | Externalized business logic that business analysts can read, version, and govern |
Why SparkRules over alternatives?
| SparkRules | Drools (JVM) | Custom if/else | Great Expectations | |
|---|---|---|---|---|
| Language | Python | Java/Kotlin | Any | Python |
| DRL rules | ✅ | ✅ | ❌ | ❌ |
| Decision tables | ✅ | ✅ | ❌ | ❌ |
| Explainable outputs | ✅ bound fields + reason codes | ✅ | Manual | ❌ |
| Rule governance | ✅ versioning, promotion, deprecation | Partial (KIE) | ❌ | ❌ |
| Data quality | ✅ built-in + profiling | ❌ | ❌ | ✅ (DQ only) |
| Adverse-action notices | ✅ ECOA/FCRA/GDPR | ❌ | Manual | ❌ |
| Spark integration | ✅ optional | ❌ | Manual | ❌ |
| Browser Workbench | ✅ Monaco + LSP | ✅ (Business Central) | ❌ | ❌ |
| Infrastructure | pip install |
JVM + app server | N/A | pip install |
SparkRules' unique position: governance + DQ + business rules + adverse-action reasons in one versioned, auditable package - from laptop to lakehouse.
What's inside
Rule engine
Write rules in Drools-style DRL. Evaluate facts. Get explainable results with bound fields, action outputs, and reason codes. Supports salience priority, agenda groups, activation groups, and multi-pattern rules.
Decision tables
Define rules as spreadsheet-style tables with hit policies (UNIQUE, FIRST, PRIORITY, COLLECT). Import/export XLSX. Business analysts can author rules without writing DRL.
Regulatory compliance (new in 1.0.1)
build_adverse_action_notice() aggregates reason codes from rule evaluations into structured notices for ECOA/FCRA (US) and GDPR Article 22 (EU). Up to 4 principal reasons per ECOA standard, deduplicated and priority-ordered.
from sparkrules.executor import RuleExecutor, build_adverse_action_notice
results = [executor.run(applicant, drl) for drl in credit_rules]
notice = build_adverse_action_notice(results, decision="decline", fact_id="app-123")
# notice.principal_reasons = ("CR001", "CR002", "IN001")
Data quality + profiling (new in 1.0.1)
Built-in DQ checks (not-null, range, in-set, regex, uniqueness, freshness) plus statistical profiling - completeness, uniqueness, mean/stddev/percentiles, top-N values. Run DQ checks before rules, governed by the same versioning and namespace system.
from sparkrules.dq import profile_rows
profile = profile_rows(batch_of_facts)
# profile.fields[0].completeness = 0.98
# profile.fields[0].numeric_stats.mean = 45000.0
API + Rules Workbench
FastAPI server with OpenAPI docs, health endpoint, rule CRUD, and a browser-based Rules Workbench with Monaco DRL editor, real-time LSP diagnostics, simulation, and interactive Chart.js dashboards.
Simulation modes
Test rules before deploying: default, shadow (compare two rule sets), coverage (which rules fire?), counterfactual (what-if analysis), and chain (ordered multi-rule evaluation with stop-on-fire).
DMN (minimal Camunda-style decision tables)
Evaluate a small DMN 1.3 XML subset (decision tables with hit policies including COLLECT variants) without the JVM.
- HTTP:
POST /dmn/evaluateandPOST /dmn/counterfactual(XML plus JSON environment; see OpenAPI when the API is running). - CLI:
sparkrules-cli dmn-evaluateandsparkrules-cli dmn-counterfactual(in-process, no server). - Python:
sparkrules.dmn.evaluate_dmn_decision_table_xml/counterfactual_dmn_decision_table_xml, orSreClient.dmn_evaluate/dmn_counterfactualover HTTP.
In-process simulation CLI (same behavior as HTTP chain/shadow/coverage): sparkrules-cli simulate-chain, sparkrules-cli simulate-shadow, and sparkrules-cli simulate-coverage (see sparkrules-cli --help for flags). Over HTTP, use SreClient.simulate_chain, simulate_shadow, and simulate_coverage.
AI, Ranger, and compliance notice templates
- AI: By default the API uses offline structural suggestions (no generative model). For OpenAI-compatible Chat Completions, set
SPARKRULES_AI_PROVIDER=openaiandSPARKRULES_OPENAI_API_KEYon the server (optional:SPARKRULES_OPENAI_BASE_URL,SPARKRULES_OPENAI_MODEL,SPARKRULES_OPENAI_TIMEOUT_SECONDS). - Ranger-style HTTP policy: When
SPARKRULES_RANGER_BASE_URLis set,ranger_allow_stub()delegates toquery_ranger_allowed()(optionalSPARKRULES_RANGER_EVAL_PATH,SPARKRULES_RANGER_RESULT_FIELD). Without it, the function keeps the local dev behavior (deny empty user; otherwise allow). - Adverse-action (compliance):
build_adverse_action_notice()emits jurisdiction-framed templates for legal review; useappendix_lines=...for institution-specific paragraphs.
Time-travel debug
Capture rule execution snapshots. Replay them later with different facts. Deterministic re-runs for audit and debugging.
Governance
Version every rule. Scope by namespace. Promote through dev → stage → prod. Deprecate with propose → approve → enforce workflow. Full audit trail.
Spark integration (optional)
Pure Python by default. When you need cluster scale, wire apply_drl(df, drl) into your PySpark job - same rules, distributed via mapPartitions. Compatible with Spark 3.x+. Deploy on AWS Glue, Databricks, GCP Dataproc, Azure Synapse, or Kubernetes - config-driven, no code changes.
Scope and trade-offs are documented in docs/KNOWN_LIMITATIONS.md.
Performance (new in 1.0.1)
DRL parse caching (LRU 256) gives 5-10x throughput boost on repeated evaluations.
| Scenario | Throughput |
|---|---|
Raw evaluate_rule |
~199,000 evals/sec |
| 10-rule chain | ~12,000 chains/sec |
Spark apply_drl local[4] |
~16,000 rows/sec |
Quick start
From PyPI
pip install sparkrules[api]
python -m uvicorn sparkrules.api.app:create_app --factory --port 8042
# → http://127.0.0.1:8042/workbench/
From source
git clone https://github.com/vaquarkhan/sparkrules.git
cd sparkrules
pip install -e ".[test]"
pytest tests/ -q
Docker
docker compose up --build
# → http://127.0.0.1:8042/workbench/
Use cases
| Domain | Scenario | What SparkRules does |
|---|---|---|
| Lending | Loan underwriting | Evaluate credit rules, generate adverse-action notices for declines |
| Payments | POS end-of-day | Batch-evaluate transaction rules, flag exceptions |
| Insurance | Claims adjudication | Decision tables for coverage determination |
| Healthcare | Clinical trial eligibility | Screen patients against inclusion/exclusion criteria |
| Fraud | Transaction authorization | Real-time rule evaluation with explainable decline reasons |
| Compliance | Settlement replay | Deterministic re-run of historical decisions for audit |
5 complete end-to-end examples with DRL, sample data, and Spark jobs: examples/usecases/
Jupyter notebooks
| # | Notebook | What you'll learn |
|---|---|---|
| 01 | Getting Started | DRL rules, evaluation, explainable results, rule chains |
| 02 | Decision Tables | Hit policies, XLSX-style tables, JSON export |
| 03 | API & Simulation | REST API, validate, simulate, counterfactual, LSP |
| 04 | Credit Underwriting | Lending pipeline, adverse-action notices, data profiling |
| 05 | Fraud Detection | Real-time auth, risk scoring, OPA Rego export |
| 06 | How SparkRules Works | Architecture tutorial: parsing, compilation, alpha network, governance |
Start with notebook 06 for the architecture overview, then 01 for hands-on basics.
Platform support
| Platform | How | Docs |
|---|---|---|
| Local / CI | pip install sparkrules |
This README |
| Docker | docker compose up --build |
Dockerfile |
| Kubernetes | Helm-ready manifests | deploy/k8s/ |
| AWS Glue | Config-driven | deploy/aws-glue/ |
| Databricks | Config-driven | deploy/databricks/ |
| GCP Dataproc | Config-driven | deploy/gcp-dataproc/ |
| Azure Synapse | Config-driven | deploy/azure-synapse/ |
How it works
- Author rules in DRL or decision-table form
- Parse and validate with LSP diagnostics
- Simulate with shadow, counterfactual, and chain modes
- Deploy with versioning, namespace scoping, and promotion pins
- Evaluate facts and get explainable, auditable results
- Replay any historical decision deterministically
Documentation
Full docs: sparkrules.readthedocs.io
| Topic | Link |
|---|---|
| V2 bug register (forensics) | SPARKRULES_BUG_REPORT.md |
| Benchmarks & positioning | BENCHMARK_3WAY.md, BENCHMARK_LATENCY.md, OPTIMIZED_BENCHMARK.md |
| Engine comparison (13-way) | RULE_ENGINE_COMPARISON.md |
| Spark V1 vs V2 design | DESIGN_REVIEW.md, DESIGN_OPTIMAL.md |
| dbt clinical mapping | dbt_mapping_sheet.md |
| Full feature list | docs/FEATURES.md |
| Architecture | docs/HOW_IT_WORKS.md |
| Developer guide | docs/DEVELOPER_GUIDE.md |
| Use cases | docs/USE_CASES.md |
| Spark integration | docs/SPARK_INTEGRATION.md |
| Governance | docs/GOVERNANCE.md |
| Benchmarks | docs/BENCHMARKS.md |
| Architecture scope | docs/KNOWN_LIMITATIONS.md |
| Comparison vs Drools/GoRules/Flink/ODM | docs/SPARKRULES_VS_THE_WORLD.md |
| Roadmap | docs/ROADMAP.md |
| Publishing / CI | docs/PUBLISHING.md |
| Changelog | CHANGELOG.md |
| Contributing | CONTRIBUTING.md |
| Jupyter notebooks (6) | examples/notebooks/ |
| AI agent guide | AGENTS.md |
Quality
- 840+ tests - unit, property-based (Hypothesis), integration, cross-path equivalence, performance
- 100% line coverage enforced in CI (
fail_under=100) - Python 3.11 / 3.12 / 3.13 tested in CI matrix
- Ruff lint + format enforced
- pip-audit dependency security scanning
- Apache 2.0 license - use it anywhere, commercially or otherwise
License
Licensed under the Apache License, Version 2.0.
Copyright 2026 Vaquar Khan. See CITATION.cff for citation details.
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file sparkrules-1.1.0.tar.gz.
File metadata
- Download URL: sparkrules-1.1.0.tar.gz
- Upload date:
- Size: 199.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
31d91215f55c3073f602d06b233afa19b14b9246d1d0d32b665b362d9419a574
|
|
| MD5 |
c4246a3494764a426156165bef238aad
|
|
| BLAKE2b-256 |
5182ae37c26be55a37ec9ae3ab2f1230c487546d0f0cc565e0c13c85d7be64cc
|
Provenance
The following attestation bundles were made for sparkrules-1.1.0.tar.gz:
Publisher:
pypi-release.yml on vaquarkhan/sparkrules
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
sparkrules-1.1.0.tar.gz -
Subject digest:
31d91215f55c3073f602d06b233afa19b14b9246d1d0d32b665b362d9419a574 - Sigstore transparency entry: 1436161581
- Sigstore integration time:
-
Permalink:
vaquarkhan/sparkrules@3fb834ec5047c57f3022705431138862ba96e1af -
Branch / Tag:
refs/heads/main - Owner: https://github.com/vaquarkhan
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
pypi-release.yml@3fb834ec5047c57f3022705431138862ba96e1af -
Trigger Event:
workflow_dispatch
-
Statement type:
File details
Details for the file sparkrules-1.1.0-py3-none-any.whl.
File metadata
- Download URL: sparkrules-1.1.0-py3-none-any.whl
- Upload date:
- Size: 227.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
6ff30d53054e9966c74438183a146614dc8d145ef5730b6dff8a9df3b3b5d064
|
|
| MD5 |
9c1055ac170a23fc048d0dac5172761a
|
|
| BLAKE2b-256 |
85fd08a9008195372a67f1596573e1df732a7860427302b3d1810ba41c5f5fb4
|
Provenance
The following attestation bundles were made for sparkrules-1.1.0-py3-none-any.whl:
Publisher:
pypi-release.yml on vaquarkhan/sparkrules
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
sparkrules-1.1.0-py3-none-any.whl -
Subject digest:
6ff30d53054e9966c74438183a146614dc8d145ef5730b6dff8a9df3b3b5d064 - Sigstore transparency entry: 1436161588
- Sigstore integration time:
-
Permalink:
vaquarkhan/sparkrules@3fb834ec5047c57f3022705431138862ba96e1af -
Branch / Tag:
refs/heads/main - Owner: https://github.com/vaquarkhan
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
pypi-release.yml@3fb834ec5047c57f3022705431138862ba96e1af -
Trigger Event:
workflow_dispatch
-
Statement type: