Some mix of product, support and eng decides how refunds work. It lives in a Notion doc. Then Slack. Then hardcoded as a bunch of if statements. No tests. No trace. No version control.
decision-layer is a small framework to clean that up.
You write the logic in YAML. Run it like code. Test it. Trace it.
What it does: - Versioned YAML policies - CLI to run and test them - Trace output with every rule fired - Examples: refunds, escalation, tiering
All in plain Python. No weird dependencies. Just testable logic defined clearly.
⸻
Would love to hear what confuses, breaks or annoys you. (Or what would make this usable where you work.)
emt00•6mo ago
I built this after one too many rounds of debugging refund logic that lived partly in code, partly in Slack/Notion and in human HDD.
What it is: A minimal framework to define decisions (refunds, escalation, tiering) in YAML, run them in Python, and trace exactly what rule fired.
Not trying to be: - A full-blown policy engine - A DSL replacement - A product
Just something useful for when your business logic needs versioning, traceability, and tests but you don’t want to build all that infra from scratch.
Trace output → shows you exactly which rule fired and why Versioning → write your policies like code, diff them, roll back Testable → run them with real inputs, locally or in CI
Happy to answer: Why YAML? (it’s config, not code) How this fits in a real app What I’d add next if people use it
Use it. Abuse it. Feedback very welcome.
zahlman•6mo ago
In particular, the apparent logic for determining whether the example order "is_late" a) is in the "Order" model (in entities.py), not in the YAML; b) apparently just checks whether the customer claims the order was late, rather than actually comparing the order and delivery dates. It appears that everything is hard-coded around provided Customer and Order models; I get that you aren't trying to be fully general, but people are going to have more data on their customers than this, and business logic that cares about that data.
The CLI doesn't seem production-ready either. "3.2" is a strange default for policy version (presumably chosen to make the test pass), and if you have multiple required arguments on the command line it isn't usual to make them all keyworded.
Oh, and to apply the MIT license properly you should have such a file in the repository and appropriate metadata in pyproject.toml.
You might also consider:
* Publishing an installable wheel, so that people don't have to do a "development"-type installation. Tools like uv and pipx can even set up a new environment from scratch for such a wheel; you already include the same abstract requirements in pyproject.toml after all. BTW, pip can now install from PEP 735 "requirement groups" described in pyproject.toml, and is soon expected to install from PEP 751 lockfiles. Regarding the licensing, you should also definitely check out PEP 639 https://peps.python.org/pep-0639/ .
* Accepting TOML as a third input format (it natively supports dates; support is built in since 3.11, and the original library they incorporated is available for earlier Python versions and is a small amount of native Python code, unlike pyyaml which may bring in a couple megabytes of compiled C).
* Allowing for mixing and matching of input formats (they're all fairly interchangeable anwyay).