Metadata-Version: 2.5
Name: fluxrules
Version: 0.1.0
Summary: Backend-first rules engine library with optional API adapters
Project-URL: Homepage, https://saurabh2mishra.github.io/fluxrules/
Project-URL: Repository, https://github.com/saurabh2mishra/fluxrules
Project-URL: Documentation, https://saurabh2mishra.github.io/fluxrules/
Project-URL: Changelog, https://github.com/saurabh2mishra/fluxrules/blob/main/CHANGELOG.md
Project-URL: Bug Tracker, https://github.com/saurabh2mishra/fluxrules/issues
Author: FluxRules Contributors
Author-email: Saurabh Mishra <saurabh2.mishra@gmail.com>
License: MIT
License-File: LICENSE
Keywords: business-rules,inference,phreak,rule-evaluation,rules-engine
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Typing :: Typed
Requires-Python: >=3.10
Requires-Dist: pydantic>=2.8
Provides-Extra: all
Requires-Dist: alembic>=1.13; extra == 'all'
Requires-Dist: bcrypt>=4.0; extra == 'all'
Requires-Dist: click>=8.0; extra == 'all'
Requires-Dist: email-validator>=2.0; extra == 'all'
Requires-Dist: fastapi<1.0,>=0.142.1; extra == 'all'
Requires-Dist: opentelemetry-api>=1.26; extra == 'all'
Requires-Dist: opentelemetry-sdk>=1.26; extra == 'all'
Requires-Dist: prometheus-client>=0.25.0; extra == 'all'
Requires-Dist: pydantic-settings>=2.14.0; extra == 'all'
Requires-Dist: pydantic>=2.8; extra == 'all'
Requires-Dist: pyjwt[crypto]>=2.10.1; extra == 'all'
Requires-Dist: python-multipart>=0.0.20; extra == 'all'
Requires-Dist: pyyaml>=6.0; extra == 'all'
Requires-Dist: redis>=5.0; extra == 'all'
Requires-Dist: rich>=13.0; extra == 'all'
Requires-Dist: sqlalchemy>=2.0; extra == 'all'
Requires-Dist: starlette<2.0,>=1.3.1; extra == 'all'
Requires-Dist: typer>=0.12; extra == 'all'
Requires-Dist: uvicorn>=0.30; extra == 'all'
Provides-Extra: api
Requires-Dist: bcrypt>=4.0; extra == 'api'
Requires-Dist: email-validator>=2.0; extra == 'api'
Requires-Dist: fastapi<1.0,>=0.142.1; extra == 'api'
Requires-Dist: prometheus-client>=0.25.0; extra == 'api'
Requires-Dist: pydantic-settings>=2.14.0; extra == 'api'
Requires-Dist: pydantic>=2.8; extra == 'api'
Requires-Dist: pyjwt[crypto]>=2.10.1; extra == 'api'
Requires-Dist: python-multipart>=0.0.20; extra == 'api'
Requires-Dist: sqlalchemy>=2.0; extra == 'api'
Requires-Dist: starlette<2.0,>=1.3.1; extra == 'api'
Requires-Dist: uvicorn>=0.30; extra == 'api'
Provides-Extra: cli
Requires-Dist: click>=8.0; extra == 'cli'
Requires-Dist: rich>=13.0; extra == 'cli'
Requires-Dist: typer>=0.12; extra == 'cli'
Provides-Extra: dev
Requires-Dist: alembic>=1.13; extra == 'dev'
Requires-Dist: bandit>=1.7; extra == 'dev'
Requires-Dist: bcrypt>=4.0; extra == 'dev'
Requires-Dist: click>=8.0; extra == 'dev'
Requires-Dist: email-validator>=2.0; extra == 'dev'
Requires-Dist: fastapi<1.0,>=0.142.1; extra == 'dev'
Requires-Dist: httpx2>=0.1; extra == 'dev'
Requires-Dist: httpx>=0.27; extra == 'dev'
Requires-Dist: hypothesis>=6.100; extra == 'dev'
Requires-Dist: mkdocs-material>=9.4; extra == 'dev'
Requires-Dist: mkdocs>=1.5; extra == 'dev'
Requires-Dist: mkdocstrings[python]>=0.24; extra == 'dev'
Requires-Dist: mypy>=1.11; extra == 'dev'
Requires-Dist: pip-audit>=2.7; extra == 'dev'
Requires-Dist: pydantic-settings>=2.14.0; extra == 'dev'
Requires-Dist: pydantic>=2.8; extra == 'dev'
Requires-Dist: pyjwt[crypto]>=2.10.1; extra == 'dev'
Requires-Dist: pytest-asyncio>=0.23; extra == 'dev'
Requires-Dist: pytest-cov>=4.0; extra == 'dev'
Requires-Dist: pytest-xdist>=3.6; extra == 'dev'
Requires-Dist: pytest>=8; extra == 'dev'
Requires-Dist: pyyaml>=6.0; extra == 'dev'
Requires-Dist: redis>=5.0; extra == 'dev'
Requires-Dist: rich>=13.0; extra == 'dev'
Requires-Dist: ruff==0.16.6; extra == 'dev'
Requires-Dist: sqlalchemy>=2.0; extra == 'dev'
Requires-Dist: starlette<2.0,>=1.3.1; extra == 'dev'
Requires-Dist: typer>=0.12; extra == 'dev'
Requires-Dist: uvicorn>=0.30; extra == 'dev'
Provides-Extra: docs
Requires-Dist: mkdocs-material>=9.4; extra == 'docs'
Requires-Dist: mkdocs>=1.5; extra == 'docs'
Requires-Dist: mkdocstrings[python]>=0.24; extra == 'docs'
Provides-Extra: otel
Requires-Dist: opentelemetry-api>=1.26; extra == 'otel'
Requires-Dist: opentelemetry-sdk>=1.26; extra == 'otel'
Provides-Extra: redis
Requires-Dist: redis>=5.0; extra == 'redis'
Provides-Extra: sql
Requires-Dist: alembic>=1.13; extra == 'sql'
Requires-Dist: sqlalchemy>=2.0; extra == 'sql'
Provides-Extra: yaml
Requires-Dist: pyyaml>=6.0; extra == 'yaml'
Description-Content-Type: text/markdown

[![MIT License](https://img.shields.io/badge/license-MIT-brightgreen.svg)](LICENSE)
[![Python 3.10+](https://img.shields.io/badge/python-3.10%2B-blue.svg)](https://www.python.org/)
[![CI](https://github.com/saurabh2mishra/fluxrules/actions/workflows/ci.yml/badge.svg)](https://github.com/saurabh2mishra/fluxrules/actions/workflows/ci.yml)
[![codecov](https://codecov.io/gh/fluxrules/fluxrules/branch/main/graph/badge.svg)](https://codecov.io/gh/fluxrules/fluxrules)

# FluxRules

FluxRules is a Python library for authoring rules and evaluating them against facts. It is loosely based on the concepts from Drools’ Phreak engine and provides optional FastAPI endpoints.

Use FluxRules to keep decision logic separate from application control flow and evaluate rules consistently across tests, services, and APIs.

## Core Capabilities

- Evaluate a ruleset against facts using the top-level Python API.
- Run rule evaluation through FluxRules’ Phreak engine in stateless or streaming mode.
- Validate rulesets before evaluation.
- Retrieve evaluation explanations by execution ID.
- Use optional HTTP endpoints for evaluation, validation, explanations, and health checks.

## Requirements

- Python 3.10+

## Installation

For local development, clone the repository and install the project with uv:

```bash
git clone https://github.com/fluxrules/fluxrules.git
cd fluxrules
uv sync --extra dev
```

This creates the project environment and installs FluxRules with its development
tools. To install the published package in a virtual environment managed by uv:

```bash
uv venv
uv pip install fluxrules
```

Install an optional extra in the checkout with `uv sync`, for example:

```bash
uv sync --extra api
uv sync --extra sql
uv sync --extra redis
uv sync --extra otel
uv sync --extra yaml
uv sync --extra cli
uv sync --extra docs
uv sync --extra all
```

For a published package, use `uv pip install 'fluxrules[api]'` (replace `api`
with the extra you need). Pip is also supported; see the
[installation guide](docs/installation.md) for its virtual-environment commands.
The `all` extra combines the API, SQL, Redis, OpenTelemetry, YAML, CLI, and
documentation integrations. The core install includes the dependencies needed
for `import fluxrules`, the canonical `Rule`, and the top-level evaluation API.

## Your First Rule

```python
from fluxrules import Rule, evaluate

rule = Rule(
    name="high_value_transaction",
    condition_dsl={"type": "condition", "field": "amount", "op": ">", "value": 5000},
    action="manual_review",
)

result = evaluate(rule, {"amount": 6000})

print(f"Fired rules: {result.fired_rules}")
print(f"Actions: {result.actions}")
```

**Output:**
```
Fired rules: [1]
Actions: ['manual_review']
```

Constructing a `Rule` does no I/O and `evaluate()` takes rules directly, so
there is nothing to configure to get an answer. `evaluate()` also accepts a list
of rules, or a named `Ruleset`.

Every evaluation path returns the same `EvaluationResult`, whose `fired_rules`
is the list of rules that matched.

## Using the engine directly

Load rules once and evaluate many facts against them. This is the path to reach
for in a service, and it exposes the engine's diagnostics.

```python
from fluxrules import PhreakEngine, Rule

rule = Rule(
    name="high_value_transaction",
    domain="payments",
    condition_dsl={"type": "condition", "field": "amount", "op": ">", "value": 5000},
    action="manual_review",
    priority=100,
)

engine = PhreakEngine()
engine.load_rules([rule])

for fact in ({"amount": 6000}, {"amount": 10}):
    result = engine.evaluate(fact)
    print(fact, "->", result.fired_rules, result.actions)
```

To persist a rule, call `rule.save()`, or pass `persist=True` when constructing
it. See the [persistence guide](docs/persistence.md).

## API Server (Optional)

```bash
uv sync --extra api
uvicorn fluxrules.api.app:create_app --factory --reload
```

Core always-on routes include:

- `GET /health`
- `GET /v1/health`
- `POST /evaluate`
- `POST /validate`
- `GET /v1/executions/{execution_id}`
- `POST /v1/rulesets/{ruleset_id}/simulate`

Additional routers are loaded when optional dependencies are available.

## CLI (Optional)

```bash
uv sync --extra cli
fluxrules --help
```

## Documentation

- Docs index: [docs/index.md](docs/index.md)
- MkDocs config: [mkdocs.yml](mkdocs.yml)

Local docs preview:

```bash
uv sync --extra dev
uv run mkdocs serve
```

## Contributing

See [CONTRIBUTING](CONTRIBUTING.md) and [CODE_OF_CONDUCT](CODE_OF_CONDUCT.md).

## Security

See [SECURITY](SECURITY.md).

## License

See [LICENSE](LICENSE).