Merit
Merit is a Python testing framework for AI projects. It follows pytest syntax and culture while introducing components essential for testing AI software: metrics, typed datasets, semantic predicates (LLM-as-a-Judge), and OTEL traces.
Installation
uv add appmerit
Merit 101
Follow pytest habits...
- Create 'merit_*.py' files
- Write 'def merit_*' functions
- Use 'merit.resource' instead of 'pytest.fixture'
- Add 'assert' expressions within the functions
- Run 'uv run merit test'
...while leveraging Merit APIs.
- Use 'with metrics()' context to turn failed assertions into quality metrics
- Use 'has_facts()' and other semantic predicates for asserting natural language
- Access OTEL span data and assert it with 'follows_policy()' predicate
- Parse datasets into clearly typed and validated data objects
Example
import merit
from merit import Case, Metric, metrics
from merit.predicates import has_unsupported_facts, follows_policy
from pydantic import BaseModel
@merit.sut
def store_chatbot(prompt: str) -> str:
return call_llm(prompt)
@merit.metric
def accuracy():
metric = Metric()
yield metric
assert metric.mean > 0.8
yield metric.mean
class Refs(BaseModel):
kb: str
expected_tool: str | None = None
cases = [
Case(sut_input_values={"prompt": "When are you open?"}, references=Refs(kb="Store hours: 9 AM - 6 PM, Monday-Saturday. Closed Sundays.")),
Case(sut_input_values={"prompt": "Return policy?"}, references=Refs(kb="30-day returns with receipt.")),
Case(sut_input_values={"prompt": "How much for the Nike Air Max?"}, references=Refs(kb="Nike Air Max: $129.99", expected_tool="offer_product")),
]
@merit.iter_cases(cases)
@merit.repeat(3)
async def merit_chatbot_no_hallucinations(
case: Case[Refs],
store_chatbot,
accuracy: Metric,
trace_context):
"""AI agent relies on knowledge base and tool calls for transactional questions"""
response = store_chatbot(**case.sut_input_values)
# Verify the answer don't have any unsupported facts
with metrics(accuracy):
assert not await has_unsupported_facts(response, case.references.kb)
# Verify tool was called when expected
if expected_tool := case.references.expected_tool:
sut_spans = trace_context.get_sut_spans(name="store_chatbot")
tool_names = [
s.attributes.get("llm.request.functions.0.name")
for s in trace_context.get_llm_calls()
if s.attributes
]
assert expected_tool in tool_names
Run it:
merit test --trace
Use a custom run UUID when you need stable correlation IDs:
merit test --trace --run-id 3f5f5e9a-1c2d-4b5f-9c2b-7f6d8a9b0c1d
Output:
Merit Test Runner
=================
Collected 1 test
test_example.py::merit_chatbot_responds ✓
==================== 1 passed in 0.08s ====================
Documentation
Full documentation: docs.appmerit.com
Getting Started:
- Quick Start - Get up and running in 5 minutes
Usage:
- Writing Merits - How to define a proper merit suite
- Running Merits - How to execute suits and merits
Concepts:
- Merit - Like test but better
- Resource - Like fixtures but better
- Case - Container for parsed dataset entities
- Metric - Aggregating assertions
- Semantic Predicates - Asserting language and logs
- SUT (System Under Test) - Collecting and accesing traces
API Reference:
- Merit Definitions APIs - Tune discovery and execution
- Merit Predicates APIs - Build your own semantic predicates
- Merit Metric APIs - Build complex metric systems
- Merit Tracing APIs - OpenTelemetry integration
Contributing
We welcome contributions! To get started:
- Fork the repository
- Clone your fork:
git clone https://github.com/YOUR_USERNAME/merit.git - Create a branch:
git checkout -b your-feature-name - Install dependencies:
uv sync - Make your changes
- Run tests:
uv run merit test - Run lints:
uv run ruff check . - Submit a pull request
For more details, see CONTRIBUTING.md.
Development Setup:
# Clone the repository
git clone https://github.com/appMerit/merit.git
cd merit
# Install dependencies
uv sync
# Run tests
uv run merit test
# Run lints
uv run ruff check .
uv run mypy .
License
This project is licensed under the MIT License - see the LICENSE file for details.
Support
- Documentation: docs.appmerit.com
- GitHub Issues: github.com/appMerit/merit/issues
- Email: support@appmerit.com
Metadata
Release files for appmerit 0.1.4
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| appmerit-0.1.4.tar.gz | 602.4 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| appmerit-0.1.4-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 699.9 kB
Release files / appmerit-0.1.4.tar.gz
| Download URL | appmerit-0.1.4.tar.gz |
|---|---|
| Size | 602.4 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
f32e4776088f924db933c9ecbececb6107c978ddcd15040bc0fe0bc1851af296
|
|
BLAKE2b-256 checksum How to use checksums |
6d491fb54c80be3b85e19d674d8969db8ec0b2e9d3ad01a8245d5187ab062797
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.7
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Feb 19, 2026.
Transparency logRelease files / appmerit-0.1.4-py3-none-any.whl
| Download URL | appmerit-0.1.4-py3-none-any.whl |
|---|---|
| Size | 97.5 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
4ad58507aef2d12f454e0dc74e952ed17b00f0d6c087f80e2c6f85c76584f4b1
|
|
BLAKE2b-256 checksum How to use checksums |
edbe68e6ca06417172619359e5ada56d35a9d81e76855b28267a30cf0572dea5
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.7
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Feb 19, 2026.
Transparency log