Skip to main content

DecisionKit

CI PyPI version Python versions License: MIT

DecisionKit is a lightweight explainable scoring and ranking engine for Python backends.

Describe criteria, weights, constraints, penalties, and bonuses — in code or config — then get ranked alternatives with scores, human-readable explanations, and audit-ready output.

No machine learning. No database. No web UI. Core has zero runtime dependencies.

Project status

Beta (v0.3.1) — useful for real backend workflows; API aims to stay stable across minor releases. See CHANGELOG.md.

Installation

pip install decisionkit

Optional YAML support:

pip install "decisionkit[yaml]"

From source:

pip install -e ".[dev]"

Quick start

from decisionkit import DecisionModel, Criterion

model = DecisionModel(
    criteria=[
        Criterion("relevance", weight=0.5, direction="max"),
        Criterion("rating", weight=0.3, direction="max"),
        Criterion("workload", weight=0.2, direction="min"),
    ],
    method="weighted_sum",
    explain=True,
)

result = model.rank([
    {"id": "reviewer_1", "relevance": 0.92, "rating": 4.8, "workload": 7},
    {"id": "reviewer_2", "relevance": 0.81, "rating": 4.5, "workload": 2},
])

print(result.best.id)
print(result.explain())

Config-driven usage

from decisionkit import DecisionModel

config = {
    "method": "weighted_sum",
    "explain": True,
    "criteria": [
        {"name": "relevance", "weight": 0.5, "direction": "max"},
        {"name": "rating", "weight": 0.3, "direction": "max"},
        {"name": "workload", "weight": 0.2, "direction": "min"},
    ],
    "constraints": [
        {
            "name": "available_only",
            "field": "available",
            "operator": "eq",
            "value": True,
            "reason": "Reviewer must be available",
        }
    ],
    "penalties": [
        {
            "name": "high_workload_penalty",
            "field": "workload",
            "operator": "gt",
            "value": 5,
            "amount": 0.1,
        }
    ],
    "bonuses": [
        {
            "name": "exact_topic_bonus",
            "field": "topic_match",
            "operator": "gte",
            "value": 0.9,
            "amount": 0.05,
        }
    ],
}

model = DecisionModel.from_dict(config)
result = model.rank(
    [
        {
            "id": "reviewer_1",
            "relevance": 0.92,
            "rating": 4.8,
            "workload": 7,
            "available": True,
            "topic_match": 0.95,
        },
        {
            "id": "reviewer_2",
            "relevance": 0.81,
            "rating": 4.5,
            "workload": 2,
            "available": True,
            "topic_match": 0.8,
        },
    ],
    context={"max_workload": 5},
)

print(result.best.id)
print(result.to_audit_dict(include_hash=True)["audit_hash"])

JSON and optional YAML helpers:

model = DecisionModel.from_json(model.to_json())
# pip install "decisionkit[yaml]"
# model = DecisionModel.from_yaml(model.to_yaml())

Rules: constraints, penalties, bonuses

Operators: eq, ne, gt, gte, lt, lte, in, not_in, contains, between.

Context-aware rule:

{
    "name": "within_capacity",
    "field": "workload",
    "operator": "lte",
    "context": "max_workload",
}

Compound rule (all = AND, any = OR):

{
    "name": "eligible",
    "all": [
        {"field": "available", "operator": "eq", "value": True},
        {"field": "workload", "operator": "lte", "context": "max_workload"},
    ],
}

Audit export and hash

audit = result.to_audit_dict(
    decision_id="req-123",
    metadata={"tenant": "acme"},
    timestamp="2026-07-10T10:00:00Z",
    include_hash=True,
)
digest = result.audit_hash()  # sha256 of canonical decision payload

The digest covers method, model, context, inputs, exclusions, ranking, and best alternative. It excludes decision_id, metadata, and timestamp by default. Details: docs/audit.md.

FastAPI integration

from fastapi import FastAPI, HTTPException
from decisionkit import DecisionModel, ValidationError

app = FastAPI()

@app.post("/rank")
def rank(payload: dict):
    try:
        model = DecisionModel.from_dict(payload["model"])
        result = model.rank(
            payload["alternatives"],
            context=payload.get("context", {}),
        )
        return result.to_audit_dict(
            decision_id=payload.get("decision_id"),
            include_hash=True,
        )
    except ValidationError as exc:
        raise HTTPException(status_code=400, detail=str(exc)) from exc

See examples/fastapi_example.py.

Django service-layer integration

Keep DecisionKit in a service module; store config in settings/admin/DB:

from decisionkit import DecisionModel

def rank_reviewers(candidates: list[dict], model_config: dict) -> dict:
    model = DecisionModel.from_dict(model_config)
    result = model.rank(candidates, context={"max_workload": 5})
    return result.to_audit_dict(decision_id="editorial-assign", include_hash=True)

See examples/django_service_example.py.

How DecisionKit compares

Approach Fit
Ad-hoc if / spreadsheet scoring Fast to start, hard to explain, test, or reuse
Generic rule engines Great for branching logic; weaker at weighted ranking + score breakdowns
Academic MCDA toolkits Broad method coverage; often awkward for backend APIs and audits
DecisionKit Backend-friendly weighted ranking with rules, explanations, and audit hashes

DecisionKit is not trying to replace every MCDA method. It focuses on explainable scoring you can ship in Django/FastAPI services.

Supported methods

Method Key Notes
Weighted sum weighted_sum Min-max normalization relative to the evaluated alternatives; min criteria inverted
TOPSIS topsis Vector normalization + closeness to ideal

Scores and “strong/weak” explanation labels are relative to the current alternative set, not absolute universal grades.

Examples

python examples/reviewer_selection.py
python examples/vendor_ranking.py
python examples/task_prioritization.py
python examples/risk_scoring.py
python examples/django_service_example.py

More: docs/examples.md

Documentation

Development

pip install -e ".[dev]"
python -m ruff check src tests examples
python -m mypy src
python -m pytest --cov=decisionkit --cov-report=term-missing

CI runs on Python 3.11 and 3.12 (see .github/workflows/ci.yml).

Release steps: RELEASE.md

Roadmap

v0.4.0

  • AHP method (optional, still backend-friendly)
  • Nested boolean rule trees (beyond flat all/any)
  • Signed / hashed decision record helpers for long-term storage

Later

  • ELECTRE / PROMETHEE (only if API stays simple)
  • decisionkit-django integration package
  • Optional CLI for batch ranking

License

MIT — see LICENSE.

Metadata

Release files for decisionkit 0.3.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for decisionkit 0.3.1
File Size Uploaded
decisionkit-0.3.1.tar.gz 31.4 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for decisionkit 0.3.1
File Interpreter ABI Platform
decisionkit-0.3.1-py3-none-any.whl Python 3 none any Details

Total release size: 57.9 kB

Release files / decisionkit-0.3.1.tar.gz

Download URL decisionkit-0.3.1.tar.gz
Size 31.4 kB
Tags Source
SHA-256 checksum
How to use checksums
1080c1c30e53910a411b90b608b988fe2d886065dc8df1586ae39d04fa7d5764
BLAKE2b-256 checksum
How to use checksums
617c2a55c1c83c1e0e229087713f0e7fadac66dea1c3d622c7bd5074ee87d21c
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.14.0

Release files / decisionkit-0.3.1-py3-none-any.whl

Download URL decisionkit-0.3.1-py3-none-any.whl
Size 26.5 kB
Tags Python 3
SHA-256 checksum
How to use checksums
3530718999d9f89e43ee85ea4d0572c2498b6103b17be64fe69538ea759f19ad
BLAKE2b-256 checksum
How to use checksums
62ffb2bd8970d1e3e6f7c3ded4df0bd55cd372521479d844e77d4b265b254b77
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.14.0

Release history Release notifications | RSS feed

This release

0.3.1 This release

2 release files

0.3.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page