evident
A small, composable toolkit for building evidence-driven applications.
Observe
↓
Evaluate
↓
Diagnose
↓
Intervene
↓
Verify
↓
Keep or Reject
What problem does this solve?
Many applications need to:
- observe something real (a document, audio, config, log, sensor reading)
- measure how well an artifact agrees with that reality
- identify likely problems
- propose or perform a bounded improvement
- independently measure the result
- keep the improvement only if evidence shows it helped
- retain enough provenance to explain what happened
evident makes this pattern reusable across completely different domains,
without forcing you into a heavyweight framework.
Quick start
from evident import improve_and_verify, Evaluation
from evident.policies import strictly_better
# The evaluator captures its own evidence via closure.
# No evidence parameter needed in the framework API.
lyrics = load_lyrics("song.lrc")
audio = load_audio("song.mp3")
def evaluate(candidate):
return score_lyrics_against_audio(candidate, lyrics, audio)
def improve(artifact, diagnosis):
return fix_timing(artifact, diagnosis)
result, decision = improve_and_verify(
artifact=artifact,
evaluator=evaluate,
improver=improve,
policy=strictly_better,
)
For iterative improvement:
from evident import EvidenceLoop
loop = EvidenceLoop(
artifact=artifact,
evaluator=evaluate, # (artifact) -> Evaluation
improver=improve, # (artifact, diagnosis) -> candidate
policy=strictly_better,
)
result, history = loop.run()
Why isn't this just a test suite?
A test suite tells you pass or fail.
evident measures how well, tracks why something might be wrong,
attempts an improvement, and independently verifies whether the
improvement actually helped before accepting it.
Why isn't this just an optimization library?
Optimization libraries minimise a loss function; they don't care why the
loss improved or whether the improvement is trustworthy.
evident is about provenance and accountability: an improvement is only
accepted when an independent evaluator (not the improver) confirms it.
Where does Bayesian inference fit?
Bayesian belief updating, active learning, and Bayesian optimisation are
strategies – they can live in the evaluator, diagnoser, or improver
slots without changing the core loop.
The first version of evident does not include Bayesian inference.
The substrate is designed so that adding it later requires no changes
to the core.
Where does AI fit?
AI can be the improver (e.g. an LLM that edits a document) or the
evaluator (e.g. a classifier that scores an artifact).
The framework's only constraint: the improver and the evaluator must be independent. If the same AI both proposes and accepts an improvement, the framework provides no safety net.
What remains application-specific?
Everything domain-specific stays in your code:
| Slot | Your responsibility |
|---|---|
artifact |
the thing you want to improve |
evaluator |
(artifact) -> Evaluation – captures its own evidence via closure |
improver |
(artifact, diagnosis) -> candidate |
policy |
(before, after) -> Decision – what "better" means |
diagnoser |
optional (evaluation) -> Diagnosis |
The fundamental invariant
improver says "better"
≠
framework accepts "better"
Only independent evaluation causes acceptance:
candidate -> independent evaluator -> evaluation -> policy -> accept/reject
Multi-metric policies
A policy is a plain Python function. No DSL, no configuration, no framework-specific abstractions.
def require_both_improve(before: Evaluation, after: Evaluation) -> Decision:
"""Accept only when ALL metrics improve."""
both = all(
after.metrics.get(k, 0) > before.metrics.get(k, 0)
for k in before.metrics
)
reason = "all metrics improved" if both else "some metrics did not improve"
return Decision(accepted=both, reason=reason, before=before, after=after)
Provenance (opt-in)
By default improve_and_verify returns (artifact, decision).
Pass provenance=True to also get a structured record:
result, decision, prov = improve_and_verify(
artifact, evaluate, improve, policy, provenance=True
)
print(prov.to_dict())
# {
# "artifact_id": "...",
# "evaluator_id": "...",
# "before": {"overall": 0.5, ...},
# "after": {"overall": 0.8, ...},
# "decision": {"accepted": true, "improvement": 0.3}
# }
Installation
pip install evidentkit
Bootstrap a new project
evidence init my-project
cd my-project
pip install -e ".[dev]"
pytest
This creates:
my-project/
pyproject.toml
README.md
src/my_project/
artifact.py <- define your artifact
evidence.py <- define your evidence type
evaluate.py <- make_evaluator(evidence) -> (artifact) -> Evaluation
improve.py <- proposes a candidate
policy.py <- accepts or rejects
tests/
test_my_project.py
Examples
| Example | Domain | What it shows |
|---|---|---|
examples/document_extraction/ |
Text | Word-overlap scoring with closure-based evidence |
examples/config_validation/ |
Config | Pass/fail assertion, missing-key repair |
python examples/document_extraction/run.py
python examples/config_validation/run.py
API reference
improve_and_verify
result, decision = improve_and_verify(
artifact,
evaluator, # (artifact) -> Evaluation
improver, # (artifact, diagnosis) -> candidate
policy, # (before, after) -> Decision
)
EvidenceLoop
loop = EvidenceLoop(
artifact=...,
evaluator=evaluate,
improver=improve,
policy=policy,
diagnoser=None, # optional: (evaluation) -> Diagnosis
max_iterations=10,
)
result, history = loop.run()
compare
decision = compare(before, after, policy)
Bundled policies (evident.policies)
| Policy | Accepts when |
|---|---|
strictly_better |
after.overall > before.overall |
must_pass |
after.passed is True |
threshold(min) |
after.overall >= min |
Development
pip install -e ".[dev]"
pytest
ruff check src tests
Architecture
evident/
models.py - immutable dataclasses (Evaluation, Decision, Provenance, ...)
core.py - plain functions: compare(), improve_and_verify()
loop.py - EvidenceLoop convenience wrapper
policies.py - bundled acceptance policies
cli.py - `evidence init` command
No databases, no service infrastructure, no plugin registries. Read the source in one sitting.
License
MIT
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 evidentkit-1.0.0.tar.gz.
File metadata
- Download URL: evidentkit-1.0.0.tar.gz
- Upload date:
- Size: 18.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
8494f2a1e58225dfeb3c697c78c56fe0a649a05b318f5fb270955e3f2f00c245
|
|
| MD5 |
c5b56a3bcc258fb4f145df5d856f4d1a
|
|
| BLAKE2b-256 |
fc6d222303cec8a7226e8ca2d7687d88e8513d43e8bfa5ab843e5dda2ace61fa
|
Provenance
The following attestation bundles were made for evidentkit-1.0.0.tar.gz:
Publisher:
publish.yml on wilsonify/evident
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
evidentkit-1.0.0.tar.gz -
Subject digest:
8494f2a1e58225dfeb3c697c78c56fe0a649a05b318f5fb270955e3f2f00c245 - Sigstore transparency entry: 2830471245
- Sigstore integration time:
-
Permalink:
wilsonify/evident@4a16fe3a189952cb77bf0a1c495110893a782c3f -
Branch / Tag:
refs/tags/v1.0.0 - Owner: https://github.com/wilsonify
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@4a16fe3a189952cb77bf0a1c495110893a782c3f -
Trigger Event:
push
-
Statement type:
File details
Details for the file evidentkit-1.0.0-py3-none-any.whl.
File metadata
- Download URL: evidentkit-1.0.0-py3-none-any.whl
- Upload date:
- Size: 12.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f8cd7a1d6c3b0f8fa9c3b5c69535cbf93bb36760ea034aed6c65987263ea1f3b
|
|
| MD5 |
9156acd500d3e8195408da5c2d5be9ce
|
|
| BLAKE2b-256 |
1a8dbb12c7ae088676a66f7b67862ebc6a6d764c07adc14806fcbd704c72372b
|
Provenance
The following attestation bundles were made for evidentkit-1.0.0-py3-none-any.whl:
Publisher:
publish.yml on wilsonify/evident
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
evidentkit-1.0.0-py3-none-any.whl -
Subject digest:
f8cd7a1d6c3b0f8fa9c3b5c69535cbf93bb36760ea034aed6c65987263ea1f3b - Sigstore transparency entry: 2830471311
- Sigstore integration time:
-
Permalink:
wilsonify/evident@4a16fe3a189952cb77bf0a1c495110893a782c3f -
Branch / Tag:
refs/tags/v1.0.0 - Owner: https://github.com/wilsonify
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@4a16fe3a189952cb77bf0a1c495110893a782c3f -
Trigger Event:
push
-
Statement type: