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.
Files changed (75) hide show
  1. {constraintloop-0.1.0 → constraintloop-0.3.0}/.gitignore +2 -0
  2. constraintloop-0.3.0/CHANGELOG.md +59 -0
  3. {constraintloop-0.1.0 → constraintloop-0.3.0}/PKG-INFO +51 -7
  4. {constraintloop-0.1.0 → constraintloop-0.3.0}/README.md +49 -5
  5. constraintloop-0.3.0/docs/configuration.md +136 -0
  6. {constraintloop-0.1.0 → constraintloop-0.3.0}/docs/faq.md +5 -3
  7. {constraintloop-0.1.0 → constraintloop-0.3.0}/docs/release-readiness.md +6 -6
  8. {constraintloop-0.1.0 → constraintloop-0.3.0}/pyproject.toml +2 -1
  9. constraintloop-0.3.0/schema/constraintloop.schema.json +1072 -0
  10. constraintloop-0.3.0/scripts/generate_schema.py +31 -0
  11. {constraintloop-0.1.0 → constraintloop-0.3.0}/src/constraintloop/__init__.py +2 -2
  12. {constraintloop-0.1.0 → constraintloop-0.3.0}/src/constraintloop/cli.py +219 -6
  13. constraintloop-0.3.0/src/constraintloop/config.py +142 -0
  14. constraintloop-0.3.0/src/constraintloop/diagnostics.py +198 -0
  15. {constraintloop-0.1.0 → constraintloop-0.3.0}/src/constraintloop/digest.py +8 -1
  16. {constraintloop-0.1.0 → constraintloop-0.3.0}/src/constraintloop/engine.py +129 -25
  17. constraintloop-0.3.0/src/constraintloop/hygiene.py +67 -0
  18. {constraintloop-0.1.0 → constraintloop-0.3.0}/src/constraintloop/models.py +112 -1
  19. constraintloop-0.3.0/src/constraintloop/runners.py +532 -0
  20. {constraintloop-0.1.0 → constraintloop-0.3.0}/src/constraintloop/setup_hooks.py +32 -4
  21. {constraintloop-0.1.0 → constraintloop-0.3.0}/src/constraintloop/state.py +64 -0
  22. constraintloop-0.3.0/tests/test_cli.py +202 -0
  23. constraintloop-0.3.0/tests/test_cli_commands.py +529 -0
  24. constraintloop-0.3.0/tests/test_diagnostics.py +185 -0
  25. {constraintloop-0.1.0 → constraintloop-0.3.0}/tests/test_engine.py +46 -1
  26. {constraintloop-0.1.0 → constraintloop-0.3.0}/tests/test_hooks.py +36 -0
  27. {constraintloop-0.1.0 → constraintloop-0.3.0}/tests/test_models.py +119 -0
  28. {constraintloop-0.1.0 → constraintloop-0.3.0}/tests/test_release_metadata.py +15 -0
  29. constraintloop-0.3.0/tests/test_runners.py +327 -0
  30. constraintloop-0.3.0/tests/test_state.py +26 -0
  31. constraintloop-0.1.0/CHANGELOG.md +0 -29
  32. constraintloop-0.1.0/docs/configuration.md +0 -55
  33. constraintloop-0.1.0/src/constraintloop/config.py +0 -53
  34. constraintloop-0.1.0/src/constraintloop/runners.py +0 -290
  35. constraintloop-0.1.0/tests/test_cli.py +0 -65
  36. constraintloop-0.1.0/tests/test_cli_commands.py +0 -262
  37. constraintloop-0.1.0/tests/test_runners.py +0 -128
  38. {constraintloop-0.1.0 → constraintloop-0.3.0}/CONTRIBUTING.md +0 -0
  39. {constraintloop-0.1.0 → constraintloop-0.3.0}/GOVERNANCE.md +0 -0
  40. {constraintloop-0.1.0 → constraintloop-0.3.0}/LICENSE +0 -0
  41. {constraintloop-0.1.0 → constraintloop-0.3.0}/RELEASE.md +0 -0
  42. {constraintloop-0.1.0 → constraintloop-0.3.0}/SECURITY.md +0 -0
  43. {constraintloop-0.1.0 → constraintloop-0.3.0}/SUPPORT.md +0 -0
  44. {constraintloop-0.1.0 → constraintloop-0.3.0}/docs/convergence-loops.md +0 -0
  45. {constraintloop-0.1.0 → constraintloop-0.3.0}/docs/native-cli-evaluators.md +0 -0
  46. {constraintloop-0.1.0 → constraintloop-0.3.0}/docs/openai-evaluation.md +0 -0
  47. {constraintloop-0.1.0 → constraintloop-0.3.0}/docs/provider-privacy.md +0 -0
  48. {constraintloop-0.1.0 → constraintloop-0.3.0}/docs/recipes.md +0 -0
  49. {constraintloop-0.1.0 → constraintloop-0.3.0}/docs/threat-model.md +0 -0
  50. {constraintloop-0.1.0 → constraintloop-0.3.0}/scripts/check_anthropic_sdk.py +0 -0
  51. {constraintloop-0.1.0 → constraintloop-0.3.0}/scripts/check_coverage.py +0 -0
  52. {constraintloop-0.1.0 → constraintloop-0.3.0}/scripts/check_openai_sdk.py +0 -0
  53. {constraintloop-0.1.0 → constraintloop-0.3.0}/scripts/check_sdist_contents.py +0 -0
  54. {constraintloop-0.1.0 → constraintloop-0.3.0}/scripts/openai_eval_canary.py +0 -0
  55. {constraintloop-0.1.0 → constraintloop-0.3.0}/scripts/wheel_failure_smoke.py +0 -0
  56. {constraintloop-0.1.0 → constraintloop-0.3.0}/src/constraintloop/__main__.py +0 -0
  57. {constraintloop-0.1.0 → constraintloop-0.3.0}/src/constraintloop/environment.py +0 -0
  58. {constraintloop-0.1.0 → constraintloop-0.3.0}/src/constraintloop/eval_corpus.py +0 -0
  59. {constraintloop-0.1.0 → constraintloop-0.3.0}/src/constraintloop/evaluators.py +0 -0
  60. {constraintloop-0.1.0 → constraintloop-0.3.0}/src/constraintloop/hooks.py +0 -0
  61. {constraintloop-0.1.0 → constraintloop-0.3.0}/src/constraintloop/loops.py +0 -0
  62. {constraintloop-0.1.0 → constraintloop-0.3.0}/src/constraintloop/native_cli_evaluator.py +0 -0
  63. {constraintloop-0.1.0 → constraintloop-0.3.0}/src/constraintloop/py.typed +0 -0
  64. {constraintloop-0.1.0 → constraintloop-0.3.0}/src/constraintloop/scaffold.py +0 -0
  65. {constraintloop-0.1.0 → constraintloop-0.3.0}/tests/__init__.py +0 -0
  66. {constraintloop-0.1.0 → constraintloop-0.3.0}/tests/failure_lab.py +0 -0
  67. {constraintloop-0.1.0 → constraintloop-0.3.0}/tests/fixtures/openai_eval_corpus_v1.yml +0 -0
  68. {constraintloop-0.1.0 → constraintloop-0.3.0}/tests/test_digest.py +0 -0
  69. {constraintloop-0.1.0 → constraintloop-0.3.0}/tests/test_environment.py +0 -0
  70. {constraintloop-0.1.0 → constraintloop-0.3.0}/tests/test_eval_corpus.py +0 -0
  71. {constraintloop-0.1.0 → constraintloop-0.3.0}/tests/test_evaluators.py +0 -0
  72. {constraintloop-0.1.0 → constraintloop-0.3.0}/tests/test_failure_lab.py +0 -0
  73. {constraintloop-0.1.0 → constraintloop-0.3.0}/tests/test_loops.py +0 -0
  74. {constraintloop-0.1.0 → constraintloop-0.3.0}/tests/test_native_cli_evaluator.py +0 -0
  75. {constraintloop-0.1.0 → constraintloop-0.3.0}/tests/test_security.py +0 -0
@@ -14,3 +14,5 @@ build/
14
14
  dist/
15
15
  *.egg-info/
16
16
  .constraintloop/
17
+ constraintloop.local.yml
18
+ constraintloop.local.yaml
@@ -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.4
1
+ Metadata-Version: 2.5
2
2
  Name: constraintloop
3
- Version: 0.1.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
  [![CI](https://github.com/mauhpr/constraintloop/actions/workflows/ci.yml/badge.svg)](https://github.com/mauhpr/constraintloop/actions/workflows/ci.yml)
47
47
  [![codecov](https://codecov.io/gh/mauhpr/constraintloop/branch/main/graph/badge.svg)](https://codecov.io/gh/mauhpr/constraintloop)
48
+ [![PyPI](https://img.shields.io/pypi/v/constraintloop)](https://pypi.org/project/constraintloop/)
49
+ [![Python](https://img.shields.io/pypi/pyversions/constraintloop)](https://pypi.org/project/constraintloop/)
48
50
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](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
- python -m venv .venv
120
- . .venv/bin/activate
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.1 surfaces are the CLI and exit codes, configuration schema,
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
  [![CI](https://github.com/mauhpr/constraintloop/actions/workflows/ci.yml/badge.svg)](https://github.com/mauhpr/constraintloop/actions/workflows/ci.yml)
4
4
  [![codecov](https://codecov.io/gh/mauhpr/constraintloop/branch/main/graph/badge.svg)](https://codecov.io/gh/mauhpr/constraintloop)
5
+ [![PyPI](https://img.shields.io/pypi/v/constraintloop)](https://pypi.org/project/constraintloop/)
6
+ [![Python](https://img.shields.io/pypi/pyversions/constraintloop)](https://pypi.org/project/constraintloop/)
5
7
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](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
- python -m venv .venv
77
- . .venv/bin/activate
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.1 surfaces are the CLI and exit codes, configuration schema,
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. `constraintloop uninstall` removes only owned entries. Review
136
- and trust newly installed Codex project hooks through `/hooks`.
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.1?
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 pending Trusted
27
- Publisher are configured. The first production publication and external
28
- installation verification remain.
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 PyPI JSON endpoint for `constraintloop` returned 404 during this assessment,
31
- so the name appeared unoccupied. A name is not reserved until the project is
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.1.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",