constraintloop 0.1.0__tar.gz → 0.3.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.
- {constraintloop-0.1.0 → constraintloop-0.3.0}/.gitignore +2 -0
- constraintloop-0.3.0/CHANGELOG.md +59 -0
- {constraintloop-0.1.0 → constraintloop-0.3.0}/PKG-INFO +51 -7
- {constraintloop-0.1.0 → constraintloop-0.3.0}/README.md +49 -5
- constraintloop-0.3.0/docs/configuration.md +136 -0
- {constraintloop-0.1.0 → constraintloop-0.3.0}/docs/faq.md +5 -3
- {constraintloop-0.1.0 → constraintloop-0.3.0}/docs/release-readiness.md +6 -6
- {constraintloop-0.1.0 → constraintloop-0.3.0}/pyproject.toml +2 -1
- constraintloop-0.3.0/schema/constraintloop.schema.json +1072 -0
- constraintloop-0.3.0/scripts/generate_schema.py +31 -0
- {constraintloop-0.1.0 → constraintloop-0.3.0}/src/constraintloop/__init__.py +2 -2
- {constraintloop-0.1.0 → constraintloop-0.3.0}/src/constraintloop/cli.py +219 -6
- constraintloop-0.3.0/src/constraintloop/config.py +142 -0
- constraintloop-0.3.0/src/constraintloop/diagnostics.py +198 -0
- {constraintloop-0.1.0 → constraintloop-0.3.0}/src/constraintloop/digest.py +8 -1
- {constraintloop-0.1.0 → constraintloop-0.3.0}/src/constraintloop/engine.py +129 -25
- constraintloop-0.3.0/src/constraintloop/hygiene.py +67 -0
- {constraintloop-0.1.0 → constraintloop-0.3.0}/src/constraintloop/models.py +112 -1
- constraintloop-0.3.0/src/constraintloop/runners.py +532 -0
- {constraintloop-0.1.0 → constraintloop-0.3.0}/src/constraintloop/setup_hooks.py +32 -4
- {constraintloop-0.1.0 → constraintloop-0.3.0}/src/constraintloop/state.py +64 -0
- constraintloop-0.3.0/tests/test_cli.py +202 -0
- constraintloop-0.3.0/tests/test_cli_commands.py +529 -0
- constraintloop-0.3.0/tests/test_diagnostics.py +185 -0
- {constraintloop-0.1.0 → constraintloop-0.3.0}/tests/test_engine.py +46 -1
- {constraintloop-0.1.0 → constraintloop-0.3.0}/tests/test_hooks.py +36 -0
- {constraintloop-0.1.0 → constraintloop-0.3.0}/tests/test_models.py +119 -0
- {constraintloop-0.1.0 → constraintloop-0.3.0}/tests/test_release_metadata.py +15 -0
- constraintloop-0.3.0/tests/test_runners.py +327 -0
- constraintloop-0.3.0/tests/test_state.py +26 -0
- constraintloop-0.1.0/CHANGELOG.md +0 -29
- constraintloop-0.1.0/docs/configuration.md +0 -55
- constraintloop-0.1.0/src/constraintloop/config.py +0 -53
- constraintloop-0.1.0/src/constraintloop/runners.py +0 -290
- constraintloop-0.1.0/tests/test_cli.py +0 -65
- constraintloop-0.1.0/tests/test_cli_commands.py +0 -262
- constraintloop-0.1.0/tests/test_runners.py +0 -128
- {constraintloop-0.1.0 → constraintloop-0.3.0}/CONTRIBUTING.md +0 -0
- {constraintloop-0.1.0 → constraintloop-0.3.0}/GOVERNANCE.md +0 -0
- {constraintloop-0.1.0 → constraintloop-0.3.0}/LICENSE +0 -0
- {constraintloop-0.1.0 → constraintloop-0.3.0}/RELEASE.md +0 -0
- {constraintloop-0.1.0 → constraintloop-0.3.0}/SECURITY.md +0 -0
- {constraintloop-0.1.0 → constraintloop-0.3.0}/SUPPORT.md +0 -0
- {constraintloop-0.1.0 → constraintloop-0.3.0}/docs/convergence-loops.md +0 -0
- {constraintloop-0.1.0 → constraintloop-0.3.0}/docs/native-cli-evaluators.md +0 -0
- {constraintloop-0.1.0 → constraintloop-0.3.0}/docs/openai-evaluation.md +0 -0
- {constraintloop-0.1.0 → constraintloop-0.3.0}/docs/provider-privacy.md +0 -0
- {constraintloop-0.1.0 → constraintloop-0.3.0}/docs/recipes.md +0 -0
- {constraintloop-0.1.0 → constraintloop-0.3.0}/docs/threat-model.md +0 -0
- {constraintloop-0.1.0 → constraintloop-0.3.0}/scripts/check_anthropic_sdk.py +0 -0
- {constraintloop-0.1.0 → constraintloop-0.3.0}/scripts/check_coverage.py +0 -0
- {constraintloop-0.1.0 → constraintloop-0.3.0}/scripts/check_openai_sdk.py +0 -0
- {constraintloop-0.1.0 → constraintloop-0.3.0}/scripts/check_sdist_contents.py +0 -0
- {constraintloop-0.1.0 → constraintloop-0.3.0}/scripts/openai_eval_canary.py +0 -0
- {constraintloop-0.1.0 → constraintloop-0.3.0}/scripts/wheel_failure_smoke.py +0 -0
- {constraintloop-0.1.0 → constraintloop-0.3.0}/src/constraintloop/__main__.py +0 -0
- {constraintloop-0.1.0 → constraintloop-0.3.0}/src/constraintloop/environment.py +0 -0
- {constraintloop-0.1.0 → constraintloop-0.3.0}/src/constraintloop/eval_corpus.py +0 -0
- {constraintloop-0.1.0 → constraintloop-0.3.0}/src/constraintloop/evaluators.py +0 -0
- {constraintloop-0.1.0 → constraintloop-0.3.0}/src/constraintloop/hooks.py +0 -0
- {constraintloop-0.1.0 → constraintloop-0.3.0}/src/constraintloop/loops.py +0 -0
- {constraintloop-0.1.0 → constraintloop-0.3.0}/src/constraintloop/native_cli_evaluator.py +0 -0
- {constraintloop-0.1.0 → constraintloop-0.3.0}/src/constraintloop/py.typed +0 -0
- {constraintloop-0.1.0 → constraintloop-0.3.0}/src/constraintloop/scaffold.py +0 -0
- {constraintloop-0.1.0 → constraintloop-0.3.0}/tests/__init__.py +0 -0
- {constraintloop-0.1.0 → constraintloop-0.3.0}/tests/failure_lab.py +0 -0
- {constraintloop-0.1.0 → constraintloop-0.3.0}/tests/fixtures/openai_eval_corpus_v1.yml +0 -0
- {constraintloop-0.1.0 → constraintloop-0.3.0}/tests/test_digest.py +0 -0
- {constraintloop-0.1.0 → constraintloop-0.3.0}/tests/test_environment.py +0 -0
- {constraintloop-0.1.0 → constraintloop-0.3.0}/tests/test_eval_corpus.py +0 -0
- {constraintloop-0.1.0 → constraintloop-0.3.0}/tests/test_evaluators.py +0 -0
- {constraintloop-0.1.0 → constraintloop-0.3.0}/tests/test_failure_lab.py +0 -0
- {constraintloop-0.1.0 → constraintloop-0.3.0}/tests/test_loops.py +0 -0
- {constraintloop-0.1.0 → constraintloop-0.3.0}/tests/test_native_cli_evaluator.py +0 -0
- {constraintloop-0.1.0 → constraintloop-0.3.0}/tests/test_security.py +0 -0
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes are documented here. The project follows Semantic
|
|
4
|
+
Versioning, with the usual initial-development flexibility for `0.y.z`.
|
|
5
|
+
|
|
6
|
+
## [Unreleased]
|
|
7
|
+
|
|
8
|
+
## [0.3.0] - 2026-08-18
|
|
9
|
+
|
|
10
|
+
- Add native monotonic ratchet constraints with committed JSON baselines,
|
|
11
|
+
strengthening-only baseline updates by default, and explicit intentional
|
|
12
|
+
regression overrides.
|
|
13
|
+
- Preserve selected fields from JSON report artifacts as structured evidence
|
|
14
|
+
and show metric values, baselines, and changes in run and status output.
|
|
15
|
+
- Add `constraintloop explain` for phase eligibility, matched and changed watch
|
|
16
|
+
paths, cache state, and complete dependency chains.
|
|
17
|
+
- Diagnose missing worktree environment files, virtual environments, container
|
|
18
|
+
runtimes, Docker daemons, and ratchet baselines in `doctor --deep`.
|
|
19
|
+
- Publish a generated JSON Schema for YAML editor validation and autocomplete.
|
|
20
|
+
- Classify genuine constraint failures separately from environmental and
|
|
21
|
+
startup failures in human-readable summaries and JSON evidence.
|
|
22
|
+
|
|
23
|
+
## [0.2.0] - 2026-08-07
|
|
24
|
+
|
|
25
|
+
- Preserve selected monorepo project paths in generated hooks, support explicit
|
|
26
|
+
persistent hook executables, and pin ephemeral `uvx` hook invocations.
|
|
27
|
+
- Add gitignored, strengthening-only local contract overlays while keeping CI
|
|
28
|
+
authoritative, and automatically protect local state from Git tracking.
|
|
29
|
+
- Stream constraint start, heartbeat, retry, cache reuse, and completion status
|
|
30
|
+
during long human-readable runs.
|
|
31
|
+
- Add bounded per-command transient retry policies for exit codes, startup
|
|
32
|
+
failures, and timeouts with explicit total budgets.
|
|
33
|
+
- Add read-only `doctor --deep` diagnostics for executables, Python invocation,
|
|
34
|
+
environment variables/files, empty watch globs, and state hygiene.
|
|
35
|
+
- Recommend isolated `uv tool` or `pipx` installation to avoid project dependency
|
|
36
|
+
conflicts.
|
|
37
|
+
|
|
38
|
+
## [0.1.0] - 2026-07-29
|
|
39
|
+
|
|
40
|
+
- Added the initial evidence engine, strict contract schema, provider adapters,
|
|
41
|
+
native agent hooks, contributor quality configuration, and CI baseline.
|
|
42
|
+
- Added deterministic OpenAI request-contract tests, refusal and incomplete
|
|
43
|
+
response handling, safe call metadata, SDK compatibility checks, and a
|
|
44
|
+
versioned opt-in semantic evaluation corpus.
|
|
45
|
+
- Added isolated native Codex and Claude Code command evaluators with
|
|
46
|
+
hook-aware same-agent preference and strict structured output.
|
|
47
|
+
- Added bounded convergence loops with pending evidence, strict budgets, atomic
|
|
48
|
+
journals, recoverable supervisor leases, stable cycle exit codes, native
|
|
49
|
+
prompts, and shared Stop-hook attempt accounting.
|
|
50
|
+
- Declared the v0.1 compatibility boundary around CLI and versioned protocols;
|
|
51
|
+
Python submodules remain internal during initial development.
|
|
52
|
+
- Added snapshot-bound advisory acknowledgments so Stop feedback must be
|
|
53
|
+
addressed or explicitly explained before completion can continue.
|
|
54
|
+
- Added canonical package metadata, a build-once PyPI Trusted Publishing
|
|
55
|
+
workflow, release invariants, CODEOWNERS, and dependency automation.
|
|
56
|
+
- Hardened project-bound and reversible hook setup, malformed hook/settings
|
|
57
|
+
handling, exact-result deterministic waivers, complete-bundle rubric caching,
|
|
58
|
+
rename disclosure, and evaluator-scoped secret loading and redaction.
|
|
59
|
+
- Added Contributor Covenant 2.1 with private conduct reporting instructions.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
2
|
Name: constraintloop
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.3.0
|
|
4
4
|
Summary: Evidence-based completion gates for AI coding agents
|
|
5
5
|
Project-URL: Homepage, https://github.com/mauhpr/constraintloop
|
|
6
6
|
Project-URL: Documentation, https://github.com/mauhpr/constraintloop/tree/main/docs
|
|
@@ -45,6 +45,8 @@ Description-Content-Type: text/markdown
|
|
|
45
45
|
|
|
46
46
|
[](https://github.com/mauhpr/constraintloop/actions/workflows/ci.yml)
|
|
47
47
|
[](https://codecov.io/gh/mauhpr/constraintloop)
|
|
48
|
+
[](https://pypi.org/project/constraintloop/)
|
|
49
|
+
[](https://pypi.org/project/constraintloop/)
|
|
48
50
|
[](https://opensource.org/licenses/MIT)
|
|
49
51
|
|
|
50
52
|
ConstraintLoop is an evidence-based completion gate for AI coding agents. Instead
|
|
@@ -116,9 +118,8 @@ flowchart LR
|
|
|
116
118
|
## Quick start
|
|
117
119
|
|
|
118
120
|
```bash
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
pip install constraintloop
|
|
121
|
+
uv tool install constraintloop
|
|
122
|
+
# Or: pipx install constraintloop
|
|
122
123
|
|
|
123
124
|
constraintloop init
|
|
124
125
|
constraintloop setup --adapter all
|
|
@@ -130,6 +131,12 @@ constraintloop ci
|
|
|
130
131
|
plain `constraintloop.yml`. It does not install tools or silently invent gates.
|
|
131
132
|
Review and commit the contract.
|
|
132
133
|
|
|
134
|
+
Install ConstraintLoop as an isolated tool instead of adding it to the target
|
|
135
|
+
project's environment. This avoids dependency conflicts with the application.
|
|
136
|
+
If you intentionally run setup through `uvx`, generated hooks pin the current
|
|
137
|
+
ConstraintLoop version. You can choose another persistent invocation with, for
|
|
138
|
+
example, `constraintloop setup --hook-executable "pipx run constraintloop"`.
|
|
139
|
+
|
|
133
140
|
The five commands above establish this flow:
|
|
134
141
|
|
|
135
142
|
```mermaid
|
|
@@ -160,6 +167,10 @@ constraints:
|
|
|
160
167
|
command: [python, -m, pytest, -q]
|
|
161
168
|
phases: [stop, ci]
|
|
162
169
|
watch: ["src/**/*.py", "tests/**/*.py", pyproject.toml]
|
|
170
|
+
retry:
|
|
171
|
+
max_attempts: 3
|
|
172
|
+
exit_codes: [1]
|
|
173
|
+
delay_seconds: 2
|
|
163
174
|
|
|
164
175
|
coverage:
|
|
165
176
|
kind: metric
|
|
@@ -173,6 +184,14 @@ constraints:
|
|
|
173
184
|
needs: [tests]
|
|
174
185
|
phases: [stop, ci]
|
|
175
186
|
|
|
187
|
+
database_consumers:
|
|
188
|
+
kind: ratchet
|
|
189
|
+
description: Do not add legacy database consumers during migration
|
|
190
|
+
command: [python, scripts/inventory_consumers.py, --json]
|
|
191
|
+
parser: {type: json, path: counts.database_consumers}
|
|
192
|
+
mode: must_not_increase
|
|
193
|
+
phases: [stop, ci]
|
|
194
|
+
|
|
176
195
|
design_review:
|
|
177
196
|
kind: rubric
|
|
178
197
|
enforcement: advisory
|
|
@@ -193,6 +212,15 @@ evaluators:
|
|
|
193
212
|
See [examples/constraintloop.full.yml](examples/constraintloop.full.yml) for all
|
|
194
213
|
constraint types.
|
|
195
214
|
|
|
215
|
+
Ratchets store their numeric baseline and evidence SHA-256 in the committed
|
|
216
|
+
`constraintloop-baselines.json`; baseline changes are therefore explicit code
|
|
217
|
+
review events. JSON artifact constraints can map selected dotted paths through
|
|
218
|
+
`evidence` so human-readable runs and `constraintloop status` report useful
|
|
219
|
+
counts and changes while the complete machine-readable run remains available
|
|
220
|
+
through `--json`. The published
|
|
221
|
+
[JSON Schema](schema/constraintloop.schema.json) provides editor validation and
|
|
222
|
+
autocomplete for every contract field.
|
|
223
|
+
|
|
196
224
|
The pre-release engineering and open-source checklist is tracked in
|
|
197
225
|
[docs/release-readiness.md](docs/release-readiness.md).
|
|
198
226
|
Participation is governed by the [Code of Conduct](CODE_OF_CONDUCT.md).
|
|
@@ -263,6 +291,13 @@ stale without a mutable invalidation list. Local state lives under the
|
|
|
263
291
|
gitignored `.constraintloop/state` directory; set `CONSTRAINTLOOP_CACHE_DIR` to
|
|
264
292
|
override it.
|
|
265
293
|
|
|
294
|
+
For stronger machine-local gates, create a gitignored
|
|
295
|
+
`constraintloop.local.yml`. ConstraintLoop recursively merges mappings over the
|
|
296
|
+
repository contract and rejects changes that could weaken committed gates.
|
|
297
|
+
The authoritative `constraintloop ci` command ignores this overlay.
|
|
298
|
+
`init` and `setup` add the overlay names and `.constraintloop/state/` to the
|
|
299
|
+
selected project's `.gitignore`, and warn if state is already tracked.
|
|
300
|
+
|
|
266
301
|
### Verdicts and what they mean
|
|
267
302
|
|
|
268
303
|
| Verdict | Meaning | Can complete? |
|
|
@@ -290,12 +325,21 @@ override it.
|
|
|
290
325
|
- `constraintloop loop-prompt NAME --adapter claude|codex` — print the bounded
|
|
291
326
|
native-agent repair protocol without launching an agent.
|
|
292
327
|
- `constraintloop status` — inspect evidence without executing commands.
|
|
328
|
+
- `constraintloop explain --phase change|stop|ci` — show why each constraint
|
|
329
|
+
runs or is skipped, including matched and changed watch paths, cache state,
|
|
330
|
+
and dependency chains.
|
|
331
|
+
- `constraintloop baseline update ID|--all` — initialize or strengthen native
|
|
332
|
+
ratchet baselines; weakening requires the explicit `--allow-regression` flag.
|
|
293
333
|
- `constraintloop debug ID` — explain evidence freshness, evaluator
|
|
294
334
|
configuration, executable resolution, and native CLI availability without
|
|
295
335
|
running an evaluator or consuming model quota.
|
|
296
336
|
- `constraintloop acknowledge ID --reason "..."` — record an explicit
|
|
297
337
|
snapshot-bound advisory disposition without changing its verdict.
|
|
298
|
-
- `constraintloop doctor` — validate and fingerprint the contract
|
|
338
|
+
- `constraintloop doctor` — validate and fingerprint the contract;
|
|
339
|
+
`--deep` also checks executables, Python invocations, referenced environment
|
|
340
|
+
files and variables, worktree environment templates, virtual environments,
|
|
341
|
+
container runtimes and daemons, ratchet baselines, empty watch globs, and
|
|
342
|
+
local-state hygiene.
|
|
299
343
|
- `constraintloop waive ID --reason "..."` — human-local, snapshot-bound waiver
|
|
300
344
|
for fresh non-passing deterministic evidence. Rubrics cannot be waived.
|
|
301
345
|
- `constraintloop enhance` — write a review-only proposal for stronger tooling.
|
|
@@ -337,7 +381,7 @@ responses become `uncertain`; a required rubric therefore fails closed.
|
|
|
337
381
|
|
|
338
382
|
## Compatibility boundary
|
|
339
383
|
|
|
340
|
-
The supported v0.
|
|
384
|
+
The supported v0.3 surfaces are the CLI and exit codes, configuration schema,
|
|
341
385
|
evaluator command protocol, native hook responses, and schema-versioned
|
|
342
386
|
evidence and cycle JSON. Python submodules are internal during initial
|
|
343
387
|
development and are not covered by semantic-versioning compatibility promises.
|
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
[](https://github.com/mauhpr/constraintloop/actions/workflows/ci.yml)
|
|
4
4
|
[](https://codecov.io/gh/mauhpr/constraintloop)
|
|
5
|
+
[](https://pypi.org/project/constraintloop/)
|
|
6
|
+
[](https://pypi.org/project/constraintloop/)
|
|
5
7
|
[](https://opensource.org/licenses/MIT)
|
|
6
8
|
|
|
7
9
|
ConstraintLoop is an evidence-based completion gate for AI coding agents. Instead
|
|
@@ -73,9 +75,8 @@ flowchart LR
|
|
|
73
75
|
## Quick start
|
|
74
76
|
|
|
75
77
|
```bash
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
pip install constraintloop
|
|
78
|
+
uv tool install constraintloop
|
|
79
|
+
# Or: pipx install constraintloop
|
|
79
80
|
|
|
80
81
|
constraintloop init
|
|
81
82
|
constraintloop setup --adapter all
|
|
@@ -87,6 +88,12 @@ constraintloop ci
|
|
|
87
88
|
plain `constraintloop.yml`. It does not install tools or silently invent gates.
|
|
88
89
|
Review and commit the contract.
|
|
89
90
|
|
|
91
|
+
Install ConstraintLoop as an isolated tool instead of adding it to the target
|
|
92
|
+
project's environment. This avoids dependency conflicts with the application.
|
|
93
|
+
If you intentionally run setup through `uvx`, generated hooks pin the current
|
|
94
|
+
ConstraintLoop version. You can choose another persistent invocation with, for
|
|
95
|
+
example, `constraintloop setup --hook-executable "pipx run constraintloop"`.
|
|
96
|
+
|
|
90
97
|
The five commands above establish this flow:
|
|
91
98
|
|
|
92
99
|
```mermaid
|
|
@@ -117,6 +124,10 @@ constraints:
|
|
|
117
124
|
command: [python, -m, pytest, -q]
|
|
118
125
|
phases: [stop, ci]
|
|
119
126
|
watch: ["src/**/*.py", "tests/**/*.py", pyproject.toml]
|
|
127
|
+
retry:
|
|
128
|
+
max_attempts: 3
|
|
129
|
+
exit_codes: [1]
|
|
130
|
+
delay_seconds: 2
|
|
120
131
|
|
|
121
132
|
coverage:
|
|
122
133
|
kind: metric
|
|
@@ -130,6 +141,14 @@ constraints:
|
|
|
130
141
|
needs: [tests]
|
|
131
142
|
phases: [stop, ci]
|
|
132
143
|
|
|
144
|
+
database_consumers:
|
|
145
|
+
kind: ratchet
|
|
146
|
+
description: Do not add legacy database consumers during migration
|
|
147
|
+
command: [python, scripts/inventory_consumers.py, --json]
|
|
148
|
+
parser: {type: json, path: counts.database_consumers}
|
|
149
|
+
mode: must_not_increase
|
|
150
|
+
phases: [stop, ci]
|
|
151
|
+
|
|
133
152
|
design_review:
|
|
134
153
|
kind: rubric
|
|
135
154
|
enforcement: advisory
|
|
@@ -150,6 +169,15 @@ evaluators:
|
|
|
150
169
|
See [examples/constraintloop.full.yml](examples/constraintloop.full.yml) for all
|
|
151
170
|
constraint types.
|
|
152
171
|
|
|
172
|
+
Ratchets store their numeric baseline and evidence SHA-256 in the committed
|
|
173
|
+
`constraintloop-baselines.json`; baseline changes are therefore explicit code
|
|
174
|
+
review events. JSON artifact constraints can map selected dotted paths through
|
|
175
|
+
`evidence` so human-readable runs and `constraintloop status` report useful
|
|
176
|
+
counts and changes while the complete machine-readable run remains available
|
|
177
|
+
through `--json`. The published
|
|
178
|
+
[JSON Schema](schema/constraintloop.schema.json) provides editor validation and
|
|
179
|
+
autocomplete for every contract field.
|
|
180
|
+
|
|
153
181
|
The pre-release engineering and open-source checklist is tracked in
|
|
154
182
|
[docs/release-readiness.md](docs/release-readiness.md).
|
|
155
183
|
Participation is governed by the [Code of Conduct](CODE_OF_CONDUCT.md).
|
|
@@ -220,6 +248,13 @@ stale without a mutable invalidation list. Local state lives under the
|
|
|
220
248
|
gitignored `.constraintloop/state` directory; set `CONSTRAINTLOOP_CACHE_DIR` to
|
|
221
249
|
override it.
|
|
222
250
|
|
|
251
|
+
For stronger machine-local gates, create a gitignored
|
|
252
|
+
`constraintloop.local.yml`. ConstraintLoop recursively merges mappings over the
|
|
253
|
+
repository contract and rejects changes that could weaken committed gates.
|
|
254
|
+
The authoritative `constraintloop ci` command ignores this overlay.
|
|
255
|
+
`init` and `setup` add the overlay names and `.constraintloop/state/` to the
|
|
256
|
+
selected project's `.gitignore`, and warn if state is already tracked.
|
|
257
|
+
|
|
223
258
|
### Verdicts and what they mean
|
|
224
259
|
|
|
225
260
|
| Verdict | Meaning | Can complete? |
|
|
@@ -247,12 +282,21 @@ override it.
|
|
|
247
282
|
- `constraintloop loop-prompt NAME --adapter claude|codex` — print the bounded
|
|
248
283
|
native-agent repair protocol without launching an agent.
|
|
249
284
|
- `constraintloop status` — inspect evidence without executing commands.
|
|
285
|
+
- `constraintloop explain --phase change|stop|ci` — show why each constraint
|
|
286
|
+
runs or is skipped, including matched and changed watch paths, cache state,
|
|
287
|
+
and dependency chains.
|
|
288
|
+
- `constraintloop baseline update ID|--all` — initialize or strengthen native
|
|
289
|
+
ratchet baselines; weakening requires the explicit `--allow-regression` flag.
|
|
250
290
|
- `constraintloop debug ID` — explain evidence freshness, evaluator
|
|
251
291
|
configuration, executable resolution, and native CLI availability without
|
|
252
292
|
running an evaluator or consuming model quota.
|
|
253
293
|
- `constraintloop acknowledge ID --reason "..."` — record an explicit
|
|
254
294
|
snapshot-bound advisory disposition without changing its verdict.
|
|
255
|
-
- `constraintloop doctor` — validate and fingerprint the contract
|
|
295
|
+
- `constraintloop doctor` — validate and fingerprint the contract;
|
|
296
|
+
`--deep` also checks executables, Python invocations, referenced environment
|
|
297
|
+
files and variables, worktree environment templates, virtual environments,
|
|
298
|
+
container runtimes and daemons, ratchet baselines, empty watch globs, and
|
|
299
|
+
local-state hygiene.
|
|
256
300
|
- `constraintloop waive ID --reason "..."` — human-local, snapshot-bound waiver
|
|
257
301
|
for fresh non-passing deterministic evidence. Rubrics cannot be waived.
|
|
258
302
|
- `constraintloop enhance` — write a review-only proposal for stronger tooling.
|
|
@@ -294,7 +338,7 @@ responses become `uncertain`; a required rubric therefore fails closed.
|
|
|
294
338
|
|
|
295
339
|
## Compatibility boundary
|
|
296
340
|
|
|
297
|
-
The supported v0.
|
|
341
|
+
The supported v0.3 surfaces are the CLI and exit codes, configuration schema,
|
|
298
342
|
evaluator command protocol, native hook responses, and schema-versioned
|
|
299
343
|
evidence and cycle JSON. Python submodules are internal during initial
|
|
300
344
|
development and are not covered by semantic-versioning compatibility promises.
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
# Configuration reference
|
|
2
|
+
|
|
3
|
+
ConstraintLoop reads the nearest supported YAML contract filename. The schema
|
|
4
|
+
is strict: unknown fields are errors.
|
|
5
|
+
|
|
6
|
+
The root fields are `version` (currently `1`), `settings`, `constraints`,
|
|
7
|
+
`evaluators`, and `loops`.
|
|
8
|
+
|
|
9
|
+
The generated JSON Schema is published at
|
|
10
|
+
[`schema/constraintloop.schema.json`](../schema/constraintloop.schema.json).
|
|
11
|
+
Editors that support YAML language-server directives can enable validation and
|
|
12
|
+
autocomplete with:
|
|
13
|
+
|
|
14
|
+
```yaml
|
|
15
|
+
# yaml-language-server: $schema=https://raw.githubusercontent.com/mauhpr/constraintloop/main/schema/constraintloop.schema.json
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
Settings default to:
|
|
19
|
+
|
|
20
|
+
| Field | Default | Allowed |
|
|
21
|
+
| --- | ---: | --- |
|
|
22
|
+
| `max_auto_retries` | 2 | 0–20 |
|
|
23
|
+
| `concurrency` | 4 | 1–32 |
|
|
24
|
+
| `evidence_output_limit` | 65536 | 1024–1048576 bytes |
|
|
25
|
+
| `evaluation_bundle_limit` | 102400 | 4096–2097152 bytes |
|
|
26
|
+
| `progress_interval_seconds` | 15 | 0.1–300 seconds |
|
|
27
|
+
|
|
28
|
+
If `constraintloop.local.yml` or `constraintloop.local.yaml` exists beside the
|
|
29
|
+
repository contract, it is loaded as a local overlay. Mapping values merge
|
|
30
|
+
recursively. Overlays may add constraints and tighten an existing constraint's
|
|
31
|
+
enforcement, phase set, dependency set, or timeout. They cannot disable or
|
|
32
|
+
replace committed gates, commands, evaluators, loops, watched inputs, or reduce
|
|
33
|
+
evidence limits. Only one overlay filename may exist. The merged contract is
|
|
34
|
+
validated normally and its digest invalidates evidence when local policy
|
|
35
|
+
changes. `init` and `setup` add both overlay names to `.gitignore`. The
|
|
36
|
+
authoritative `constraintloop ci` command ignores local overlays and always
|
|
37
|
+
evaluates the committed repository contract.
|
|
38
|
+
|
|
39
|
+
Every constraint supports `description`, `enforcement` (`required` or
|
|
40
|
+
`advisory`), `phases` (`change`, `stop`, `ci`), `watch` globs, dependency IDs
|
|
41
|
+
in `needs`, `timeout_seconds`, and `enabled`. Dependencies must exist and the
|
|
42
|
+
graph must be acyclic.
|
|
43
|
+
Identifiers may contain letters, numbers, dots, underscores, and hyphens.
|
|
44
|
+
`watch` and `include` values must be nonempty project-relative POSIX globs.
|
|
45
|
+
|
|
46
|
+
Command constraints use `kind: command`, `command`, `cwd`, `shell`,
|
|
47
|
+
`success_codes`, and `pending_codes` (default `[75]`). Prefer an argv list. A
|
|
48
|
+
string command is rejected unless `shell: true` explicitly accepts shell
|
|
49
|
+
parsing. Success and pending codes may not overlap.
|
|
50
|
+
|
|
51
|
+
Command, metric, and ratchet constraints may declare an optional transient
|
|
52
|
+
retry policy:
|
|
53
|
+
|
|
54
|
+
```yaml
|
|
55
|
+
retry:
|
|
56
|
+
max_attempts: 3
|
|
57
|
+
exit_codes: [1, 125]
|
|
58
|
+
retry_timeouts: false
|
|
59
|
+
retry_start_errors: true
|
|
60
|
+
delay_seconds: 2
|
|
61
|
+
total_timeout_seconds: 90
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
No retries occur when `retry` is absent. A configured policy retries only the
|
|
65
|
+
listed exit codes and, when enabled, timeouts or process startup failures.
|
|
66
|
+
Every attempt is capped by the constraint's normal timeout. Retry and periodic
|
|
67
|
+
running status lines are emitted during human-readable runs; `--json` remains a
|
|
68
|
+
single machine-readable document. `timeout_seconds` bounds each attempt and,
|
|
69
|
+
unless overridden, the complete retry sequence including delays. Timeout
|
|
70
|
+
retries require an explicit `total_timeout_seconds` greater than the per-attempt
|
|
71
|
+
timeout. This keeps the total bound visible while leaving enough budget for a
|
|
72
|
+
second attempt.
|
|
73
|
+
|
|
74
|
+
Metric constraints add `parser` and `threshold`. A parser has type `json` or
|
|
75
|
+
`regex`, reads `stdout`, `stderr`, or a project-contained `file`, and selects a
|
|
76
|
+
dotted JSON `path` or regex `pattern` and `group`. Threshold operators are
|
|
77
|
+
`gt`, `gte`, `lt`, `lte`, and `eq`.
|
|
78
|
+
|
|
79
|
+
Ratchet constraints use `kind: ratchet` with the same command and parser fields
|
|
80
|
+
as a metric. Their default `mode: must_not_increase` compares the current value
|
|
81
|
+
to the committed `constraintloop-baselines.json`; `must_not_decrease` supports
|
|
82
|
+
monotonic growth metrics. Initialize or strengthen baselines explicitly:
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
constraintloop baseline update database_consumers
|
|
86
|
+
constraintloop baseline update --all
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
Updates that would weaken an existing baseline are rejected. Use
|
|
90
|
+
`--allow-regression` only for a reviewed, intentional reset, then commit the
|
|
91
|
+
baseline artifact with the contract. `baseline_file` can select another
|
|
92
|
+
project-relative JSON file. Each baseline entry records both the numeric value
|
|
93
|
+
and the SHA-256 digest of the parsed evidence source, replacing the separate
|
|
94
|
+
count-and-hash bookkeeping commonly used for migration inventories.
|
|
95
|
+
|
|
96
|
+
Artifact constraints use `kind: artifact`, a project-contained `path`, format
|
|
97
|
+
`any`, `json`, or `junit`, and `non_empty`. JSON artifacts can expose selected
|
|
98
|
+
dotted paths as structured evidence so summaries and `status` show meaningful
|
|
99
|
+
counts instead of the entire report:
|
|
100
|
+
|
|
101
|
+
```yaml
|
|
102
|
+
report:
|
|
103
|
+
kind: artifact
|
|
104
|
+
path: reports/consumer-inventory.json
|
|
105
|
+
format: json
|
|
106
|
+
evidence:
|
|
107
|
+
consumers: counts.consumers
|
|
108
|
+
change: counts.change
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
Rubric constraints use `kind: rubric`, an evaluator ID, a written `rubric`,
|
|
112
|
+
`include` globs, `runs`, and `pass_quorum`. Required rubrics need at least two
|
|
113
|
+
runs and an explicit majority quorum.
|
|
114
|
+
|
|
115
|
+
Evaluators are:
|
|
116
|
+
|
|
117
|
+
- `command`: `command`, `shell`, and `timeout_seconds`;
|
|
118
|
+
- `openai`: `model`, `api_key_env`, `timeout_seconds`, `max_attempts`,
|
|
119
|
+
`max_output_tokens`, and `reasoning_effort`;
|
|
120
|
+
- `anthropic`: `model`, `api_key_env`, `timeout_seconds`, `max_attempts`, and
|
|
121
|
+
`max_output_tokens`.
|
|
122
|
+
|
|
123
|
+
See `examples/constraintloop.full.yml` for a parseable full example. CI ignores
|
|
124
|
+
local waivers. Each loop declares a phase, positive polling interval, repair and
|
|
125
|
+
unchanged-repair budgets, a duration budget, and fixed pass/failure/pending/
|
|
126
|
+
exhaustion actions. Unknown fields and zero or unbounded budgets are rejected.
|
|
127
|
+
At most one Stop-phase loop is allowed. Ready deterministic constraints execute
|
|
128
|
+
concurrently up to `settings.concurrency`; rubric evaluators remain serialized
|
|
129
|
+
and result ordering follows the contract.
|
|
130
|
+
`constraintloop explain --phase stop` reports why every constraint is eligible
|
|
131
|
+
or skipped, the files matched by its watch globs, changed watch paths, cache
|
|
132
|
+
state, and dependency chains without executing any gate. Human-readable final
|
|
133
|
+
summaries label concrete policy failures as `constraint` and startup,
|
|
134
|
+
prerequisite, or evaluation errors as `environment`; the same
|
|
135
|
+
`failure_category` is retained in JSON evidence.
|
|
136
|
+
See `docs/convergence-loops.md` for the cycle protocol and stable exit codes.
|
|
@@ -132,8 +132,10 @@ trusted completion boundary.
|
|
|
132
132
|
### Will setup overwrite existing hooks?
|
|
133
133
|
|
|
134
134
|
No. `constraintloop setup` merges owned hook entries and preserves unrelated
|
|
135
|
-
configuration.
|
|
136
|
-
|
|
135
|
+
configuration. In a monorepo, hooks retain the exact directory selected with
|
|
136
|
+
`--project` instead of falling back to the Git root. `constraintloop uninstall`
|
|
137
|
+
removes only owned entries. Review and trust newly installed Codex project hooks
|
|
138
|
+
through `/hooks`.
|
|
137
139
|
|
|
138
140
|
### Why does a hook say `Missing option --project`?
|
|
139
141
|
|
|
@@ -168,7 +170,7 @@ journal and releases the lease.
|
|
|
168
170
|
|
|
169
171
|
## Compatibility and release
|
|
170
172
|
|
|
171
|
-
### Which platforms are supported in v0.
|
|
173
|
+
### Which platforms are supported in v0.2?
|
|
172
174
|
|
|
173
175
|
Linux and macOS on Python 3.11 through 3.14. Windows is not supported until
|
|
174
176
|
hook commands, locking, process control, and installed-wheel behavior have
|
|
@@ -23,13 +23,13 @@ ConstraintLoop currently has:
|
|
|
23
23
|
- a self-contract that passes its deterministic gates.
|
|
24
24
|
|
|
25
25
|
The public GitHub repository, protected `main` branch, cross-platform CI,
|
|
26
|
-
community-health files, production `pypi` environment, and
|
|
27
|
-
|
|
28
|
-
|
|
26
|
+
community-health files, production `pypi` environment, and Trusted Publisher
|
|
27
|
+
are configured. Version 0.1.0 was published through that identity,
|
|
28
|
+
both distributions expose PyPI provenance, and a clean public-index install
|
|
29
|
+
passed the CLI initialization and contract-validation smoke test.
|
|
29
30
|
|
|
30
|
-
The
|
|
31
|
-
|
|
32
|
-
actually registered and published.
|
|
31
|
+
The canonical package page is
|
|
32
|
+
[pypi.org/project/constraintloop](https://pypi.org/project/constraintloop/).
|
|
33
33
|
|
|
34
34
|
## v0.1 release gates
|
|
35
35
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "constraintloop"
|
|
3
|
-
version = "0.
|
|
3
|
+
version = "0.3.0"
|
|
4
4
|
description = "Evidence-based completion gates for AI coding agents"
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
license = "MIT"
|
|
@@ -66,6 +66,7 @@ include = [
|
|
|
66
66
|
"/tests",
|
|
67
67
|
"/docs",
|
|
68
68
|
"/scripts",
|
|
69
|
+
"/schema",
|
|
69
70
|
"/pyproject.toml",
|
|
70
71
|
"/README.md",
|
|
71
72
|
"/LICENSE",
|