evalgate-ai 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (52) hide show
  1. evalgate_ai-0.1.0/.gitattributes +1 -0
  2. evalgate_ai-0.1.0/.githooks/pre-push +12 -0
  3. evalgate_ai-0.1.0/.gitignore +14 -0
  4. evalgate_ai-0.1.0/CONTRIBUTING.md +50 -0
  5. evalgate_ai-0.1.0/LICENSE +21 -0
  6. evalgate_ai-0.1.0/PKG-INFO +194 -0
  7. evalgate_ai-0.1.0/README.md +165 -0
  8. evalgate_ai-0.1.0/docs/SPEC.md +1013 -0
  9. evalgate_ai-0.1.0/docs/ci.md +55 -0
  10. evalgate_ai-0.1.0/docs/report-format.md +64 -0
  11. evalgate_ai-0.1.0/examples/README.md +16 -0
  12. evalgate_ai-0.1.0/examples/cost-latency/baseline/cases.jsonl +6 -0
  13. evalgate_ai-0.1.0/examples/cost-latency/baseline/run.json +10 -0
  14. evalgate_ai-0.1.0/examples/cost-latency/candidate/cases.jsonl +6 -0
  15. evalgate_ai-0.1.0/examples/cost-latency/candidate/run.json +10 -0
  16. evalgate_ai-0.1.0/examples/cost-latency/evalgate.yaml +21 -0
  17. evalgate_ai-0.1.0/examples/quickstart/baseline/cases.jsonl +4 -0
  18. evalgate_ai-0.1.0/examples/quickstart/baseline/run.json +9 -0
  19. evalgate_ai-0.1.0/examples/quickstart/candidate/cases.jsonl +4 -0
  20. evalgate_ai-0.1.0/examples/quickstart/candidate/run.json +9 -0
  21. evalgate_ai-0.1.0/examples/quickstart/evalgate.yaml +31 -0
  22. evalgate_ai-0.1.0/examples/sdk_quickstart.py +52 -0
  23. evalgate_ai-0.1.0/examples/sdk_quickstart.yaml +14 -0
  24. evalgate_ai-0.1.0/pyproject.toml +68 -0
  25. evalgate_ai-0.1.0/src/evalgate/__init__.py +8 -0
  26. evalgate_ai-0.1.0/src/evalgate/_version.py +2 -0
  27. evalgate_ai-0.1.0/src/evalgate/api.py +31 -0
  28. evalgate_ai-0.1.0/src/evalgate/cli.py +116 -0
  29. evalgate_ai-0.1.0/src/evalgate/comparison/__init__.py +5 -0
  30. evalgate_ai-0.1.0/src/evalgate/comparison/engine.py +108 -0
  31. evalgate_ai-0.1.0/src/evalgate/engine.py +67 -0
  32. evalgate_ai-0.1.0/src/evalgate/io/__init__.py +19 -0
  33. evalgate_ai-0.1.0/src/evalgate/io/reader.py +110 -0
  34. evalgate_ai-0.1.0/src/evalgate/io/writer.py +139 -0
  35. evalgate_ai-0.1.0/src/evalgate/models/__init__.py +35 -0
  36. evalgate_ai-0.1.0/src/evalgate/models/policy.py +100 -0
  37. evalgate_ai-0.1.0/src/evalgate/models/report.py +113 -0
  38. evalgate_ai-0.1.0/src/evalgate/models/run.py +61 -0
  39. evalgate_ai-0.1.0/src/evalgate/policies/__init__.py +5 -0
  40. evalgate_ai-0.1.0/src/evalgate/policies/engine.py +93 -0
  41. evalgate_ai-0.1.0/src/evalgate/reporting/__init__.py +1 -0
  42. evalgate_ai-0.1.0/src/evalgate/reporting/html.py +234 -0
  43. evalgate_ai-0.1.0/src/evalgate/reporting/terminal.py +68 -0
  44. evalgate_ai-0.1.0/src/evalgate/validation.py +118 -0
  45. evalgate_ai-0.1.0/tests/conftest.py +55 -0
  46. evalgate_ai-0.1.0/tests/test_cli.py +96 -0
  47. evalgate_ai-0.1.0/tests/test_engine.py +183 -0
  48. evalgate_ai-0.1.0/tests/test_examples.py +35 -0
  49. evalgate_ai-0.1.0/tests/test_html_init.py +61 -0
  50. evalgate_ai-0.1.0/tests/test_io.py +87 -0
  51. evalgate_ai-0.1.0/tests/test_review_fixes.py +144 -0
  52. evalgate_ai-0.1.0/tests/test_sdk.py +112 -0
@@ -0,0 +1 @@
1
+ .githooks/* text eol=lf
@@ -0,0 +1,12 @@
1
+ #!/bin/sh
2
+ # Local replacement for CI: lint, format, types and tests must pass before pushing.
3
+ # Enable once per clone: git config core.hooksPath .githooks
4
+ set -e
5
+ cd "$(git rev-parse --show-toplevel)"
6
+ # Use the project venv (created by `uv sync`); Scripts/ on Windows, bin/ elsewhere.
7
+ PATH="$PWD/.venv/Scripts:$PWD/.venv/bin:$PATH"
8
+
9
+ echo "pre-push: ruff check" && ruff check .
10
+ echo "pre-push: ruff format --check" && ruff format --check .
11
+ echo "pre-push: mypy" && mypy src
12
+ echo "pre-push: pytest" && pytest -q
@@ -0,0 +1,14 @@
1
+ __pycache__/
2
+ *.py[cod]
3
+ .venv/
4
+ dist/
5
+ build/
6
+ *.egg-info/
7
+ .pytest_cache/
8
+ .ruff_cache/
9
+ .mypy_cache/
10
+ graphify-out
11
+ .claude
12
+ CLAUDE.md
13
+
14
+ evals/
@@ -0,0 +1,50 @@
1
+ # Contributing
2
+
3
+ Thanks for helping. EvalGate aims to be a small, correct tool, and that shapes what gets merged.
4
+
5
+ ## Setup
6
+
7
+ ```bash
8
+ uv sync
9
+ git config core.hooksPath .githooks # enables the pre-push checks
10
+ ```
11
+
12
+ There is no hosted CI. The `pre-push` hook runs the same checks a CI job would, and blocks the push if any fail:
13
+
14
+ ```bash
15
+ uv run ruff check .
16
+ uv run ruff format --check .
17
+ uv run mypy src
18
+ uv run pytest
19
+ ```
20
+
21
+ ## Ground rules
22
+
23
+ - **Fail closed.** Missing, malformed or incomparable input must give INVALID (exit 2), never PASS. Any change that touches validation or policy needs a test proving that bad input can't pass.
24
+ - **Explicit semantics.** Metrics declare a direction. Never divide by a zero baseline. No weighted overall scores.
25
+ - **Deterministic.** The same inputs, policy and version must produce byte-identical reports. Sort every list by stable keys, and keep timestamps out of results.
26
+ - **Offline core.** No network calls, LLM APIs or databases in the core.
27
+ - **Layering.** `comparison/` and `policies/` are pure functions over models. File I/O lives in `io/`. The CLI and SDK both go through `evalgate.api.compare`, so there is never a second code path.
28
+ - **Small.** Add a module or option only when real code needs it. New dependencies need a strong reason.
29
+
30
+ ## Where things live
31
+
32
+ ```text
33
+ src/evalgate/
34
+ models/ Pydantic models: run, case, policy, report
35
+ io/ read run dirs and policies; write reports; EvalRun recorder
36
+ validation.py comparability checks -> diagnostics
37
+ comparison/ matching and metric deltas (pure)
38
+ policies/ rule evaluation (pure)
39
+ engine.py validate -> compare -> decide
40
+ api.py path-based entry point shared by CLI and SDK
41
+ reporting/ terminal and HTML renderers
42
+ ```
43
+
44
+ The product spec is [docs/SPEC.md](docs/SPEC.md), and the JSON report contract is [docs/report-format.md](docs/report-format.md). A change to the report shape must update that doc, and bump `report_version` if it breaks existing fields.
45
+
46
+ ## Pull requests
47
+
48
+ - One topic per PR, with tests. A bug fix starts with a test that fails without the fix.
49
+ - Explain *why* in the description, especially any change to decision semantics.
50
+ - To release, bump `src/evalgate/_version.py`. It is the only place the version lives.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Josep Audenis
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,194 @@
1
+ Metadata-Version: 2.5
2
+ Name: evalgate-ai
3
+ Version: 0.1.0
4
+ Summary: Local-first AI regression testing and release decision engine.
5
+ Project-URL: Homepage, https://github.com/josep-audenis/evalgate
6
+ Project-URL: Repository, https://github.com/josep-audenis/evalgate
7
+ Project-URL: Issues, https://github.com/josep-audenis/evalgate/issues
8
+ Author: Josep Audenis
9
+ License-Expression: MIT
10
+ License-File: LICENSE
11
+ Keywords: ci,evaluation,llm,regression-testing,release-gate
12
+ Classifier: Development Status :: 3 - Alpha
13
+ Classifier: Environment :: Console
14
+ Classifier: Intended Audience :: Developers
15
+ Classifier: Operating System :: OS Independent
16
+ Classifier: Programming Language :: Python :: 3
17
+ Classifier: Programming Language :: Python :: 3.11
18
+ Classifier: Programming Language :: Python :: 3.12
19
+ Classifier: Programming Language :: Python :: 3.13
20
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
21
+ Classifier: Topic :: Software Development :: Quality Assurance
22
+ Classifier: Typing :: Typed
23
+ Requires-Python: >=3.11
24
+ Requires-Dist: pydantic>=2.6
25
+ Requires-Dist: pyyaml>=6
26
+ Requires-Dist: rich>=13
27
+ Requires-Dist: typer>=0.12
28
+ Description-Content-Type: text/markdown
29
+
30
+ # EvalGate
31
+
32
+ **Local-first regression testing and release decisions for AI applications.**
33
+
34
+ You changed a prompt, model, tool or retrieval step. Your eval pipeline produced scores for the old version and the new one. EvalGate answers three questions:
35
+
36
+ 1. **What changed?**
37
+ 2. **What got worse?**
38
+ 3. **Is this version acceptable to release?**
39
+
40
+ It compares a *baseline* run against a *candidate* run case by case and applies your release policy. It returns an explainable **PASS / FAIL / INVALID**, with exit codes `0 / 1 / 2` for CI. It runs fully offline, with no LLM API key, account or database.
41
+
42
+ ```text
43
+ $ evalgate compare evals/baseline evals/candidate --policy evalgate.yaml
44
+ baseline-v1 -> candidate-v2 dataset regression-suite@v3 evaluator rubric-v2
45
+ cases: 4 matched, 4 compared, 0 baseline errors, 0 candidate errors
46
+ metric direction baseline candidate delta delta %
47
+ quality maximize 0.8 0.865 +0.065 +8.12%
48
+ ...
49
+ FAIL checks.required.safety_valid: required check 'safety_valid' failed in 1 case(s): abuse-001/safety_valid
50
+ decision: FAIL
51
+ ```
52
+
53
+ Average quality went up, but one case started failing a safety check, so the candidate does not ship.
54
+
55
+ ## Install
56
+
57
+ ```bash
58
+ pip install evalgate-ai
59
+ ```
60
+
61
+ The package is published as `evalgate-ai`. It imports as `evalgate`, and the command is `evalgate`. Requires Python 3.11 or newer.
62
+
63
+ ## Quickstart
64
+
65
+ **1. Write each run as a directory.** Use `run.json` for identity and `cases.jsonl` with one JSON object per test case:
66
+
67
+ ```json
68
+ {"schema_version": "1.0", "run_id": "candidate-v2", "dataset_id": "regression-suite",
69
+ "dataset_version": "v3", "evaluator_version": "rubric-v2"}
70
+ ```
71
+
72
+ ```json
73
+ {"case_id": "refund-001", "status": "ok", "scores": {"quality": 0.91},
74
+ "checks": {"safety_valid": true}, "metrics": {"latency_ms": 3000, "cost_usd": 0.012},
75
+ "metadata": {"category": "billing"}}
76
+ ```
77
+
78
+ If the pipeline failed on a case, record `"status": "error"` instead of inventing scores. Or let the Python SDK below write these files for you.
79
+
80
+ **2. Create a policy:**
81
+
82
+ ```bash
83
+ evalgate init # writes a commented evalgate.yaml
84
+ ```
85
+
86
+ ```yaml
87
+ version: 1
88
+ metrics:
89
+ quality:
90
+ path: scores.quality
91
+ direction: maximize # explicit: EvalGate never assumes higher is better
92
+ max_mean_regression_abs: 0.02
93
+ latency:
94
+ path: metrics.latency_ms
95
+ direction: minimize
96
+ max_mean_regression_pct: 10
97
+ checks:
98
+ required: [safety_valid] # must pass in every candidate case
99
+ max_new_failures: 0 # nothing that passed before may fail now
100
+ ```
101
+
102
+ **3. Compare:**
103
+
104
+ ```bash
105
+ evalgate validate evals/candidate
106
+ evalgate compare evals/baseline evals/candidate --policy evalgate.yaml \
107
+ --json report.json --report report.html
108
+ ```
109
+
110
+ - `--report` writes one standalone HTML file: no scripts and no external assets.
111
+ - `--json` writes a stable, documented report: see [report format](https://github.com/josep-audenis/evalgate/blob/main/docs/report-format.md).
112
+ - Neither report contains raw prompts or outputs.
113
+
114
+ ## Python SDK
115
+
116
+ ```python
117
+ from evalgate import EvalRun, compare
118
+
119
+ with EvalRun(
120
+ "candidate", dataset="support-suite", dataset_version="v3", evaluator_version="rubric-v2"
121
+ ) as run: # writes evals/candidate/
122
+ for case in dataset:
123
+ try:
124
+ output = execute_agent(case)
125
+ except Exception as exc:
126
+ run.record_error(case["id"], repr(exc)) # never invent scores
127
+ continue
128
+ run.record(
129
+ case["id"],
130
+ scores={"quality": judge(output)},
131
+ checks={"safety_valid": is_safe(output)},
132
+ metrics={"latency_ms": 1234},
133
+ )
134
+
135
+ report = compare("evals/baseline", "evals/candidate", policy="evalgate.yaml")
136
+ print(report.summary())
137
+ report.to_json("report.json")
138
+ report.to_html("report.html")
139
+ ```
140
+
141
+ - **Validation:** values are checked as you record them. Duplicate `case_id`s raise an error.
142
+ - **Crash safety:** `run.json` is written only when the `with` block exits cleanly, so an interrupted run never loads as complete.
143
+ - **Overwrites:** `EvalRun` won't replace an existing run unless you pass `overwrite=True`. Even then, the old run is replaced only when the new one finishes cleanly.
144
+ - **Same results as the CLI:** the SDK's `compare` is the same code path as `evalgate compare`, and the reports are identical.
145
+
146
+ ## How decisions are made
147
+
148
+ - **INVALID (exit 2):** a trustworthy decision is impossible. Causes:
149
+ - missing or duplicate cases
150
+ - a dataset or evaluator version mismatch
151
+ - missing metrics or checks
152
+ - malformed files
153
+ - a percent threshold on a metric whose baseline mean is 0
154
+
155
+ Invalid input never produces a PASS.
156
+ - **FAIL (exit 1):** the comparison is valid, but at least one policy rule is violated.
157
+ - **PASS (exit 0):** the comparison is valid and every rule holds.
158
+
159
+ Further rules:
160
+ - Means are computed over cases that ran successfully in both runs.
161
+ - Cases with `status: "error"` count against `max_execution_errors` (default 0) and never count as successes.
162
+ - Every metric declares its direction and at least one threshold.
163
+ - The policy is strict. Unknown or duplicate keys, `true` where a number is expected, and a policy with no rules are all rejected.
164
+ - There is no weighted overall score. Each rule passes or fails on its own, so one regression can't hide behind an improvement elsewhere.
165
+
166
+ ## Use in CI
167
+
168
+ Exit codes make EvalGate a drop-in CI step. See [CI integration](https://github.com/josep-audenis/evalgate/blob/main/docs/ci.md) for a GitHub Actions example.
169
+
170
+ ## Examples
171
+
172
+ [examples/](https://github.com/josep-audenis/evalgate/tree/main/examples) has runnable scenarios:
173
+ - a safety regression hidden by better averages
174
+ - a quality gain that blows the cost and latency budget
175
+ - an SDK eval loop with a timed-out case
176
+
177
+ ## Status and scope
178
+
179
+ Version 0.1.0 (alpha). EvalGate compares results your pipeline already produced. It does **not** run your application, call LLM judges, or host datasets.
180
+
181
+ Not yet included:
182
+ - statistical uncertainty (confidence intervals)
183
+ - repeated-run comparison
184
+ - adapters for other eval frameworks
185
+
186
+ Planned work is in the [spec](https://github.com/josep-audenis/evalgate/blob/main/docs/SPEC.md).
187
+
188
+ ## Contributing
189
+
190
+ See [CONTRIBUTING.md](https://github.com/josep-audenis/evalgate/blob/main/CONTRIBUTING.md).
191
+
192
+ ## License
193
+
194
+ MIT
@@ -0,0 +1,165 @@
1
+ # EvalGate
2
+
3
+ **Local-first regression testing and release decisions for AI applications.**
4
+
5
+ You changed a prompt, model, tool or retrieval step. Your eval pipeline produced scores for the old version and the new one. EvalGate answers three questions:
6
+
7
+ 1. **What changed?**
8
+ 2. **What got worse?**
9
+ 3. **Is this version acceptable to release?**
10
+
11
+ It compares a *baseline* run against a *candidate* run case by case and applies your release policy. It returns an explainable **PASS / FAIL / INVALID**, with exit codes `0 / 1 / 2` for CI. It runs fully offline, with no LLM API key, account or database.
12
+
13
+ ```text
14
+ $ evalgate compare evals/baseline evals/candidate --policy evalgate.yaml
15
+ baseline-v1 -> candidate-v2 dataset regression-suite@v3 evaluator rubric-v2
16
+ cases: 4 matched, 4 compared, 0 baseline errors, 0 candidate errors
17
+ metric direction baseline candidate delta delta %
18
+ quality maximize 0.8 0.865 +0.065 +8.12%
19
+ ...
20
+ FAIL checks.required.safety_valid: required check 'safety_valid' failed in 1 case(s): abuse-001/safety_valid
21
+ decision: FAIL
22
+ ```
23
+
24
+ Average quality went up, but one case started failing a safety check, so the candidate does not ship.
25
+
26
+ ## Install
27
+
28
+ ```bash
29
+ pip install evalgate-ai
30
+ ```
31
+
32
+ The package is published as `evalgate-ai`. It imports as `evalgate`, and the command is `evalgate`. Requires Python 3.11 or newer.
33
+
34
+ ## Quickstart
35
+
36
+ **1. Write each run as a directory.** Use `run.json` for identity and `cases.jsonl` with one JSON object per test case:
37
+
38
+ ```json
39
+ {"schema_version": "1.0", "run_id": "candidate-v2", "dataset_id": "regression-suite",
40
+ "dataset_version": "v3", "evaluator_version": "rubric-v2"}
41
+ ```
42
+
43
+ ```json
44
+ {"case_id": "refund-001", "status": "ok", "scores": {"quality": 0.91},
45
+ "checks": {"safety_valid": true}, "metrics": {"latency_ms": 3000, "cost_usd": 0.012},
46
+ "metadata": {"category": "billing"}}
47
+ ```
48
+
49
+ If the pipeline failed on a case, record `"status": "error"` instead of inventing scores. Or let the Python SDK below write these files for you.
50
+
51
+ **2. Create a policy:**
52
+
53
+ ```bash
54
+ evalgate init # writes a commented evalgate.yaml
55
+ ```
56
+
57
+ ```yaml
58
+ version: 1
59
+ metrics:
60
+ quality:
61
+ path: scores.quality
62
+ direction: maximize # explicit: EvalGate never assumes higher is better
63
+ max_mean_regression_abs: 0.02
64
+ latency:
65
+ path: metrics.latency_ms
66
+ direction: minimize
67
+ max_mean_regression_pct: 10
68
+ checks:
69
+ required: [safety_valid] # must pass in every candidate case
70
+ max_new_failures: 0 # nothing that passed before may fail now
71
+ ```
72
+
73
+ **3. Compare:**
74
+
75
+ ```bash
76
+ evalgate validate evals/candidate
77
+ evalgate compare evals/baseline evals/candidate --policy evalgate.yaml \
78
+ --json report.json --report report.html
79
+ ```
80
+
81
+ - `--report` writes one standalone HTML file: no scripts and no external assets.
82
+ - `--json` writes a stable, documented report: see [report format](https://github.com/josep-audenis/evalgate/blob/main/docs/report-format.md).
83
+ - Neither report contains raw prompts or outputs.
84
+
85
+ ## Python SDK
86
+
87
+ ```python
88
+ from evalgate import EvalRun, compare
89
+
90
+ with EvalRun(
91
+ "candidate", dataset="support-suite", dataset_version="v3", evaluator_version="rubric-v2"
92
+ ) as run: # writes evals/candidate/
93
+ for case in dataset:
94
+ try:
95
+ output = execute_agent(case)
96
+ except Exception as exc:
97
+ run.record_error(case["id"], repr(exc)) # never invent scores
98
+ continue
99
+ run.record(
100
+ case["id"],
101
+ scores={"quality": judge(output)},
102
+ checks={"safety_valid": is_safe(output)},
103
+ metrics={"latency_ms": 1234},
104
+ )
105
+
106
+ report = compare("evals/baseline", "evals/candidate", policy="evalgate.yaml")
107
+ print(report.summary())
108
+ report.to_json("report.json")
109
+ report.to_html("report.html")
110
+ ```
111
+
112
+ - **Validation:** values are checked as you record them. Duplicate `case_id`s raise an error.
113
+ - **Crash safety:** `run.json` is written only when the `with` block exits cleanly, so an interrupted run never loads as complete.
114
+ - **Overwrites:** `EvalRun` won't replace an existing run unless you pass `overwrite=True`. Even then, the old run is replaced only when the new one finishes cleanly.
115
+ - **Same results as the CLI:** the SDK's `compare` is the same code path as `evalgate compare`, and the reports are identical.
116
+
117
+ ## How decisions are made
118
+
119
+ - **INVALID (exit 2):** a trustworthy decision is impossible. Causes:
120
+ - missing or duplicate cases
121
+ - a dataset or evaluator version mismatch
122
+ - missing metrics or checks
123
+ - malformed files
124
+ - a percent threshold on a metric whose baseline mean is 0
125
+
126
+ Invalid input never produces a PASS.
127
+ - **FAIL (exit 1):** the comparison is valid, but at least one policy rule is violated.
128
+ - **PASS (exit 0):** the comparison is valid and every rule holds.
129
+
130
+ Further rules:
131
+ - Means are computed over cases that ran successfully in both runs.
132
+ - Cases with `status: "error"` count against `max_execution_errors` (default 0) and never count as successes.
133
+ - Every metric declares its direction and at least one threshold.
134
+ - The policy is strict. Unknown or duplicate keys, `true` where a number is expected, and a policy with no rules are all rejected.
135
+ - There is no weighted overall score. Each rule passes or fails on its own, so one regression can't hide behind an improvement elsewhere.
136
+
137
+ ## Use in CI
138
+
139
+ Exit codes make EvalGate a drop-in CI step. See [CI integration](https://github.com/josep-audenis/evalgate/blob/main/docs/ci.md) for a GitHub Actions example.
140
+
141
+ ## Examples
142
+
143
+ [examples/](https://github.com/josep-audenis/evalgate/tree/main/examples) has runnable scenarios:
144
+ - a safety regression hidden by better averages
145
+ - a quality gain that blows the cost and latency budget
146
+ - an SDK eval loop with a timed-out case
147
+
148
+ ## Status and scope
149
+
150
+ Version 0.1.0 (alpha). EvalGate compares results your pipeline already produced. It does **not** run your application, call LLM judges, or host datasets.
151
+
152
+ Not yet included:
153
+ - statistical uncertainty (confidence intervals)
154
+ - repeated-run comparison
155
+ - adapters for other eval frameworks
156
+
157
+ Planned work is in the [spec](https://github.com/josep-audenis/evalgate/blob/main/docs/SPEC.md).
158
+
159
+ ## Contributing
160
+
161
+ See [CONTRIBUTING.md](https://github.com/josep-audenis/evalgate/blob/main/CONTRIBUTING.md).
162
+
163
+ ## License
164
+
165
+ MIT