helix-grounding 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 (65) hide show
  1. helix_grounding-0.1.0/.gitignore +34 -0
  2. helix_grounding-0.1.0/LICENSE +21 -0
  3. helix_grounding-0.1.0/PKG-INFO +225 -0
  4. helix_grounding-0.1.0/README.md +193 -0
  5. helix_grounding-0.1.0/docs/ARCHITECTURE.md +229 -0
  6. helix_grounding-0.1.0/docs/BUSINESS_MODEL.md +136 -0
  7. helix_grounding-0.1.0/docs/CASE_STUDY.html +265 -0
  8. helix_grounding-0.1.0/docs/DECISION_LOG.md +1455 -0
  9. helix_grounding-0.1.0/docs/FIRST_USERS.md +214 -0
  10. helix_grounding-0.1.0/docs/MARKET_RESEARCH.html +537 -0
  11. helix_grounding-0.1.0/docs/OLLAMA_SETUP.md +123 -0
  12. helix_grounding-0.1.0/docs/PUBLISHING.md +201 -0
  13. helix_grounding-0.1.0/docs/ROADMAP.md +108 -0
  14. helix_grounding-0.1.0/pyproject.toml +77 -0
  15. helix_grounding-0.1.0/scripts/diagnose_env.py +48 -0
  16. helix_grounding-0.1.0/scripts/export_diagrams.py +61 -0
  17. helix_grounding-0.1.0/scripts/reproduce_d036.py +110 -0
  18. helix_grounding-0.1.0/scripts/set_repo_url.py +56 -0
  19. helix_grounding-0.1.0/src/helix_api/__init__.py +1 -0
  20. helix_grounding-0.1.0/src/helix_api/app.py +172 -0
  21. helix_grounding-0.1.0/src/helix_api/audit.py +73 -0
  22. helix_grounding-0.1.0/src/helix_api/auth.py +121 -0
  23. helix_grounding-0.1.0/src/helix_bom/__init__.py +1 -0
  24. helix_grounding-0.1.0/src/helix_bom/agent.py +618 -0
  25. helix_grounding-0.1.0/src/helix_bom/cli.py +238 -0
  26. helix_grounding-0.1.0/src/helix_bom/components.py +66 -0
  27. helix_grounding-0.1.0/src/helix_bom/diagrams.py +226 -0
  28. helix_grounding-0.1.0/src/helix_bom/examples/sample_bom.csv +12 -0
  29. helix_grounding-0.1.0/src/helix_bom/ingest.py +355 -0
  30. helix_grounding-0.1.0/src/helix_grounding/__init__.py +74 -0
  31. helix_grounding-0.1.0/src/helix_grounding/claims.py +136 -0
  32. helix_grounding-0.1.0/src/helix_grounding/domains/__init__.py +12 -0
  33. helix_grounding-0.1.0/src/helix_grounding/domains/bom.py +169 -0
  34. helix_grounding-0.1.0/src/helix_grounding/domains/invoice.py +151 -0
  35. helix_grounding-0.1.0/src/helix_grounding/extractors.py +397 -0
  36. helix_grounding-0.1.0/src/helix_grounding/truth.py +179 -0
  37. helix_grounding-0.1.0/src/helix_grounding/verifier.py +152 -0
  38. helix_grounding-0.1.0/src/helix_llm/__init__.py +1 -0
  39. helix_grounding-0.1.0/src/helix_llm/client.py +124 -0
  40. helix_grounding-0.1.0/tests/fixtures/altium_with_pricing.csv +7 -0
  41. helix_grounding-0.1.0/tests/fixtures/kicad_grouped.csv +11 -0
  42. helix_grounding-0.1.0/tests/fixtures/spreadsheet_european.csv +4 -0
  43. helix_grounding-0.1.0/tests/sandbox/test_bom_review_clean_case_sandbox.py +63 -0
  44. helix_grounding-0.1.0/tests/sandbox/test_bom_review_realistic_scale_sandbox.py +132 -0
  45. helix_grounding-0.1.0/tests/sandbox/test_bom_review_sandbox.py +66 -0
  46. helix_grounding-0.1.0/tests/sandbox/test_component_lookup_sandbox.py +30 -0
  47. helix_grounding-0.1.0/tests/sandbox/test_grounding_safety_net_sandbox.py +149 -0
  48. helix_grounding-0.1.0/tests/sandbox/test_interconnect_diagram_sandbox.py +36 -0
  49. helix_grounding-0.1.0/tests/sandbox/test_llm_client_sandbox.py +49 -0
  50. helix_grounding-0.1.0/tests/sandbox/test_orchestrator_realistic_scale_sandbox.py +90 -0
  51. helix_grounding-0.1.0/tests/sandbox/test_orchestrator_sandbox.py +86 -0
  52. helix_grounding-0.1.0/tests/sandbox/test_tier_gating_sandbox.py +75 -0
  53. helix_grounding-0.1.0/tests/sandbox/test_variated_1_over_budget_only_sandbox.py +48 -0
  54. helix_grounding-0.1.0/tests/sandbox/test_variated_2_multi_lead_time_sandbox.py +67 -0
  55. helix_grounding-0.1.0/tests/sandbox/test_variated_3_physical_fit_only_sandbox.py +47 -0
  56. helix_grounding-0.1.0/tests/sandbox/test_visual_diagrams_sandbox.py +71 -0
  57. helix_grounding-0.1.0/tests/test_api_auth.py +203 -0
  58. helix_grounding-0.1.0/tests/test_bom_cli.py +214 -0
  59. helix_grounding-0.1.0/tests/test_bom_ingest.py +306 -0
  60. helix_grounding-0.1.0/tests/test_case_study.py +23 -0
  61. helix_grounding-0.1.0/tests/test_diagram_fixes.py +130 -0
  62. helix_grounding-0.1.0/tests/test_grounding.py +357 -0
  63. helix_grounding-0.1.0/tests/test_invoice_domain.py +304 -0
  64. helix_grounding-0.1.0/tests/test_offline_guarantee.py +148 -0
  65. helix_grounding-0.1.0/tests/test_sandbox_suite.py +51 -0
@@ -0,0 +1,34 @@
1
+ # Secrets — never commit. There is a populated .env in AI_CODE/; committing it
2
+ # would put the key in history permanently, where deleting the file later does
3
+ # not remove it.
4
+ .env
5
+ .env.*
6
+ !.env.example
7
+ *.pem
8
+ *.key
9
+
10
+ # Build artefacts
11
+ dist/
12
+ build/
13
+ *.egg-info/
14
+
15
+ # Python
16
+ __pycache__/
17
+ *.py[cod]
18
+ *.egg-info/
19
+ .venv/
20
+ venv/
21
+ .pytest_cache/
22
+ .mypy_cache/
23
+ .ruff_cache/
24
+
25
+ # Local databases and generated output
26
+ *.sqlite
27
+ *.sqlite3
28
+ *.db
29
+ diagram_output/
30
+
31
+ # OS
32
+ Thumbs.db
33
+ desktop.ini
34
+ .DS_Store
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Robert Brandon Spiva
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,225 @@
1
+ Metadata-Version: 2.5
2
+ Name: helix-grounding
3
+ Version: 0.1.0
4
+ Summary: Catch the numbers an AI made up, without asking another AI
5
+ Project-URL: Documentation, https://github.com/CARC-Program/helix-grounding#readme
6
+ Project-URL: Source, https://github.com/CARC-Program/helix-grounding
7
+ Project-URL: Changelog, https://github.com/CARC-Program/helix-grounding/blob/main/docs/DECISION_LOG.md
8
+ Author: Helix Labs
9
+ License-Expression: MIT
10
+ License-File: LICENSE
11
+ Keywords: ai-safety,bom,evals,grounding,guardrails,hallucination,llm,validation,verification
12
+ Classifier: Development Status :: 3 - Alpha
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: Programming Language :: Python :: 3
15
+ Classifier: Programming Language :: Python :: 3.10
16
+ Classifier: Programming Language :: Python :: 3.11
17
+ Classifier: Programming Language :: Python :: 3.12
18
+ Classifier: Programming Language :: Python :: 3.13
19
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
20
+ Classifier: Topic :: Software Development :: Quality Assurance
21
+ Classifier: Typing :: Typed
22
+ Requires-Python: >=3.10
23
+ Provides-Extra: dev
24
+ Requires-Dist: build; extra == 'dev'
25
+ Requires-Dist: pytest>=8; extra == 'dev'
26
+ Requires-Dist: twine; extra == 'dev'
27
+ Provides-Extra: llm
28
+ Requires-Dist: anthropic>=0.40; extra == 'llm'
29
+ Requires-Dist: ollama>=0.3; extra == 'llm'
30
+ Requires-Dist: python-dotenv>=1.0; extra == 'llm'
31
+ Description-Content-Type: text/markdown
32
+
33
+ # helix-grounding
34
+
35
+ **Catch the numbers an AI made up — without asking another AI.**
36
+
37
+ A language model states a figure that isn't in its source data. In anything
38
+ touching money, specifications, or deadlines, that's not a quality issue —
39
+ it's a liability.
40
+
41
+ The usual defence is to check the output with another model: LLM-as-judge,
42
+ semantic entailment, embedding similarity. All three are probabilistic, all
43
+ three cost an inference call, and all three can be wrong themselves.
44
+
45
+ This doesn't do that. It extracts every currency amount, measurement,
46
+ identifier, quantity, percentage and date from generated text and checks each
47
+ against values computed from your source data. For that class of claim the
48
+ answer is decidable: a value is in the set or it isn't. **No model call, no
49
+ judgement, no confidence score.**
50
+
51
+ ```bash
52
+ pip install helix-grounding
53
+ helix-bom demo # see it catch something, no file needed
54
+ ```
55
+
56
+ ```python
57
+ from helix_grounding import Verifier, GroundTruth, ClaimKind
58
+
59
+ truth = GroundTruth().allow_many(ClaimKind.CURRENCY, [18.00, 22.00, 40.00])
60
+ report = Verifier().verify(model_output, truth)
61
+
62
+ if not report.is_grounded:
63
+ print(report.summary())
64
+ # -> UNGROUNDED: 1 of 4 claims not found in source data — $36.00 (currency)
65
+ retry = base_prompt + report.correction_note()
66
+ ```
67
+
68
+ The correction names the specific invented value and quotes the sentence it
69
+ appeared in, because a blind re-roll reproduces the same error at roughly the
70
+ same rate.
71
+
72
+ ---
73
+
74
+ ## See it work on your own file
75
+
76
+ The package ships a complete worked example: a bill-of-materials reviewer
77
+ built on the library. `helix-bom demo` runs it against a bundled sample;
78
+ point it at your own CSV export when you want a real answer.
79
+
80
+ ```bash
81
+ helix-bom review my_bom.csv --budget 10
82
+ ```
83
+
84
+ ```
85
+ BOM total: $13.81 (budget $10.00)
86
+
87
+ Findings:
88
+ [CRITICAL] BOM total ($13.81) exceeds stated budget ($10.00) by $3.81.
89
+ [WARNING] ARM Cortex-M4 MCU has a stated lead time of 120 days — this is a
90
+ real supply-chain risk that can silently become the critical path.
91
+
92
+ NOT CHECKED (3):
93
+ physical fit
94
+ no component dimensions in the submitted data — standard EDA exports
95
+ carry footprints, not millimetres
96
+
97
+ These are not passes. Supply the missing columns to check them.
98
+ ```
99
+
100
+ It reads what KiCad, Altium and spreadsheets actually export: preamble lines
101
+ before the header, semicolon delimiters, do-not-populate rows, and `1.234,56`
102
+ versus `1,234.56` decided per file rather than per cell.
103
+
104
+ **A check that couldn't run is never reported as a pass.** `--strict` makes
105
+ "couldn't check" a non-zero exit; `--json` emits the same for a machine.
106
+
107
+ ### Your BOM never leaves your machine
108
+
109
+ A bill of materials exposes a design, its costs and its suppliers. Reading
110
+ and reviewing one here is **entirely offline** — no upload, no telemetry, no
111
+ account, no network call of any kind.
112
+
113
+ That is not a promise, it is a test. `tests/test_offline_guarantee.py`
114
+ disables Python's socket layer outright and then runs the real code path
115
+ end to end, so any attempt to reach the network by any library at any depth
116
+ is a hard failure rather than a quiet one. It also asserts the block itself
117
+ works, because a guard that silently stops guarding is worse than none.
118
+
119
+ The only component that can reach out is the optional narrative writer, and
120
+ it defaults to a model running on your own hardware.
121
+
122
+ ---
123
+
124
+ ## A real fabrication, caught
125
+
126
+ Not a demo — a model actually wrote both of these while reviewing a BOM:
127
+
128
+ > "the Bosch BME680 at **$3.10** is slightly cheaper than your current part at
129
+ > **$2.40**"
130
+
131
+ > "The ESP32-S3 module at **$3.40** has a lead time concern"
132
+
133
+ The second is caught: $3.20 is the real price, and $3.40 appears nowhere in
134
+ the source data.
135
+
136
+ **The first passes the check — and should.** Both numbers are real. What's
137
+ false is the word *cheaper*, a claim about the *relation* between two values.
138
+ No value-checker can see that, and a library claiming otherwise would be
139
+ misrepresenting its own scope. It's prevented a different way: the comparison
140
+ is computed in Python before the prompt is built, so the model is only asked
141
+ to phrase an answer that's already correct.
142
+
143
+ Reproduce both yourself:
144
+
145
+ ```bash
146
+ python scripts/reproduce_d036.py
147
+ ```
148
+
149
+ Full write-up: `docs/CASE_STUDY.html`.
150
+
151
+ ---
152
+
153
+ ## What it can't do
154
+
155
+ Stated plainly, because a validation layer that quietly misses a category is
156
+ worse than none — it manufactures false confidence.
157
+
158
+ - **Judgement claims are out of scope.** Whether advice is good, whether a
159
+ summary is complete, whether a conclusion follows. Those need an
160
+ LLM-as-judge layer. This is not one.
161
+ - **Identifiers need a vocabulary.** No lexical rule separates a part number
162
+ from a standards name — `RS485` and `BME280` are the same shape. A default
163
+ vocabulary of known non-identifiers ships in, and is meant to be extended.
164
+ - **Amounts written as words** ("thirty-six dollars") aren't caught. Symbol
165
+ and suffix forms are: `$36`, `36 dollars`, `36 USD`.
166
+ - **Relative dates are out of scope** ("next Tuesday", "in 30 days") — those
167
+ depend on what *now* means, which makes them judgement claims.
168
+
169
+ ---
170
+
171
+ ## Your own data
172
+
173
+ A domain adapter turns your data into a `GroundTruth`. The core never learns
174
+ what your data is — two ship as reference implementations, and a third is a
175
+ new file, not a change to the verifier.
176
+
177
+ ```python
178
+ from helix_grounding.domains.invoice import ground_truth_for_invoice
179
+
180
+ report = Verifier().verify(summary, ground_truth_for_invoice(invoice))
181
+ ```
182
+
183
+ Invoices exercise a shape a BOM never does: a *chain*, where line totals feed
184
+ a subtotal, the subtotal feeds a discount, the remainder feeds a tax. Every
185
+ intermediate is a figure a model will quote, so the adapter permits the whole
186
+ working — not just the answer.
187
+
188
+ Adding that second domain is what forced date support into the core. Before
189
+ it, a fabricated due date produced no claim at all and passed straight
190
+ through.
191
+
192
+ **Zero runtime dependencies, deliberately.** The argument for this library is
193
+ that checking a model's output shouldn't require another model. A dependency
194
+ on an inference client would undercut that.
195
+
196
+ ---
197
+
198
+ ## Development
199
+
200
+ Python 3.10+.
201
+
202
+ ```bash
203
+ pip install -e ".[dev]"
204
+ pytest
205
+ ```
206
+
207
+ 161 tests, nothing skipped, no database and no services required.
208
+
209
+ ```
210
+ src/helix_grounding/ the library
211
+ domains/ bom.py, invoice.py — add a vertical here
212
+ src/helix_bom/ the worked example: ingest, checks, CLI
213
+ src/helix_llm/ optional model client (local Ollama, or Anthropic)
214
+ docs/ decision log, architecture, business model, case study
215
+ PUBLISHING.md — GitHub + PyPI release checklist
216
+ FIRST_USERS.md — how to get the first users
217
+ ```
218
+
219
+ `docs/DECISION_LOG.md` is 45 decisions with the reasoning attached, including
220
+ the bugs that produced the design above. It is the most useful file here for
221
+ understanding *why* rather than *what*.
222
+
223
+ ## Licence
224
+
225
+ MIT.
@@ -0,0 +1,193 @@
1
+ # helix-grounding
2
+
3
+ **Catch the numbers an AI made up — without asking another AI.**
4
+
5
+ A language model states a figure that isn't in its source data. In anything
6
+ touching money, specifications, or deadlines, that's not a quality issue —
7
+ it's a liability.
8
+
9
+ The usual defence is to check the output with another model: LLM-as-judge,
10
+ semantic entailment, embedding similarity. All three are probabilistic, all
11
+ three cost an inference call, and all three can be wrong themselves.
12
+
13
+ This doesn't do that. It extracts every currency amount, measurement,
14
+ identifier, quantity, percentage and date from generated text and checks each
15
+ against values computed from your source data. For that class of claim the
16
+ answer is decidable: a value is in the set or it isn't. **No model call, no
17
+ judgement, no confidence score.**
18
+
19
+ ```bash
20
+ pip install helix-grounding
21
+ helix-bom demo # see it catch something, no file needed
22
+ ```
23
+
24
+ ```python
25
+ from helix_grounding import Verifier, GroundTruth, ClaimKind
26
+
27
+ truth = GroundTruth().allow_many(ClaimKind.CURRENCY, [18.00, 22.00, 40.00])
28
+ report = Verifier().verify(model_output, truth)
29
+
30
+ if not report.is_grounded:
31
+ print(report.summary())
32
+ # -> UNGROUNDED: 1 of 4 claims not found in source data — $36.00 (currency)
33
+ retry = base_prompt + report.correction_note()
34
+ ```
35
+
36
+ The correction names the specific invented value and quotes the sentence it
37
+ appeared in, because a blind re-roll reproduces the same error at roughly the
38
+ same rate.
39
+
40
+ ---
41
+
42
+ ## See it work on your own file
43
+
44
+ The package ships a complete worked example: a bill-of-materials reviewer
45
+ built on the library. `helix-bom demo` runs it against a bundled sample;
46
+ point it at your own CSV export when you want a real answer.
47
+
48
+ ```bash
49
+ helix-bom review my_bom.csv --budget 10
50
+ ```
51
+
52
+ ```
53
+ BOM total: $13.81 (budget $10.00)
54
+
55
+ Findings:
56
+ [CRITICAL] BOM total ($13.81) exceeds stated budget ($10.00) by $3.81.
57
+ [WARNING] ARM Cortex-M4 MCU has a stated lead time of 120 days — this is a
58
+ real supply-chain risk that can silently become the critical path.
59
+
60
+ NOT CHECKED (3):
61
+ physical fit
62
+ no component dimensions in the submitted data — standard EDA exports
63
+ carry footprints, not millimetres
64
+
65
+ These are not passes. Supply the missing columns to check them.
66
+ ```
67
+
68
+ It reads what KiCad, Altium and spreadsheets actually export: preamble lines
69
+ before the header, semicolon delimiters, do-not-populate rows, and `1.234,56`
70
+ versus `1,234.56` decided per file rather than per cell.
71
+
72
+ **A check that couldn't run is never reported as a pass.** `--strict` makes
73
+ "couldn't check" a non-zero exit; `--json` emits the same for a machine.
74
+
75
+ ### Your BOM never leaves your machine
76
+
77
+ A bill of materials exposes a design, its costs and its suppliers. Reading
78
+ and reviewing one here is **entirely offline** — no upload, no telemetry, no
79
+ account, no network call of any kind.
80
+
81
+ That is not a promise, it is a test. `tests/test_offline_guarantee.py`
82
+ disables Python's socket layer outright and then runs the real code path
83
+ end to end, so any attempt to reach the network by any library at any depth
84
+ is a hard failure rather than a quiet one. It also asserts the block itself
85
+ works, because a guard that silently stops guarding is worse than none.
86
+
87
+ The only component that can reach out is the optional narrative writer, and
88
+ it defaults to a model running on your own hardware.
89
+
90
+ ---
91
+
92
+ ## A real fabrication, caught
93
+
94
+ Not a demo — a model actually wrote both of these while reviewing a BOM:
95
+
96
+ > "the Bosch BME680 at **$3.10** is slightly cheaper than your current part at
97
+ > **$2.40**"
98
+
99
+ > "The ESP32-S3 module at **$3.40** has a lead time concern"
100
+
101
+ The second is caught: $3.20 is the real price, and $3.40 appears nowhere in
102
+ the source data.
103
+
104
+ **The first passes the check — and should.** Both numbers are real. What's
105
+ false is the word *cheaper*, a claim about the *relation* between two values.
106
+ No value-checker can see that, and a library claiming otherwise would be
107
+ misrepresenting its own scope. It's prevented a different way: the comparison
108
+ is computed in Python before the prompt is built, so the model is only asked
109
+ to phrase an answer that's already correct.
110
+
111
+ Reproduce both yourself:
112
+
113
+ ```bash
114
+ python scripts/reproduce_d036.py
115
+ ```
116
+
117
+ Full write-up: `docs/CASE_STUDY.html`.
118
+
119
+ ---
120
+
121
+ ## What it can't do
122
+
123
+ Stated plainly, because a validation layer that quietly misses a category is
124
+ worse than none — it manufactures false confidence.
125
+
126
+ - **Judgement claims are out of scope.** Whether advice is good, whether a
127
+ summary is complete, whether a conclusion follows. Those need an
128
+ LLM-as-judge layer. This is not one.
129
+ - **Identifiers need a vocabulary.** No lexical rule separates a part number
130
+ from a standards name — `RS485` and `BME280` are the same shape. A default
131
+ vocabulary of known non-identifiers ships in, and is meant to be extended.
132
+ - **Amounts written as words** ("thirty-six dollars") aren't caught. Symbol
133
+ and suffix forms are: `$36`, `36 dollars`, `36 USD`.
134
+ - **Relative dates are out of scope** ("next Tuesday", "in 30 days") — those
135
+ depend on what *now* means, which makes them judgement claims.
136
+
137
+ ---
138
+
139
+ ## Your own data
140
+
141
+ A domain adapter turns your data into a `GroundTruth`. The core never learns
142
+ what your data is — two ship as reference implementations, and a third is a
143
+ new file, not a change to the verifier.
144
+
145
+ ```python
146
+ from helix_grounding.domains.invoice import ground_truth_for_invoice
147
+
148
+ report = Verifier().verify(summary, ground_truth_for_invoice(invoice))
149
+ ```
150
+
151
+ Invoices exercise a shape a BOM never does: a *chain*, where line totals feed
152
+ a subtotal, the subtotal feeds a discount, the remainder feeds a tax. Every
153
+ intermediate is a figure a model will quote, so the adapter permits the whole
154
+ working — not just the answer.
155
+
156
+ Adding that second domain is what forced date support into the core. Before
157
+ it, a fabricated due date produced no claim at all and passed straight
158
+ through.
159
+
160
+ **Zero runtime dependencies, deliberately.** The argument for this library is
161
+ that checking a model's output shouldn't require another model. A dependency
162
+ on an inference client would undercut that.
163
+
164
+ ---
165
+
166
+ ## Development
167
+
168
+ Python 3.10+.
169
+
170
+ ```bash
171
+ pip install -e ".[dev]"
172
+ pytest
173
+ ```
174
+
175
+ 161 tests, nothing skipped, no database and no services required.
176
+
177
+ ```
178
+ src/helix_grounding/ the library
179
+ domains/ bom.py, invoice.py — add a vertical here
180
+ src/helix_bom/ the worked example: ingest, checks, CLI
181
+ src/helix_llm/ optional model client (local Ollama, or Anthropic)
182
+ docs/ decision log, architecture, business model, case study
183
+ PUBLISHING.md — GitHub + PyPI release checklist
184
+ FIRST_USERS.md — how to get the first users
185
+ ```
186
+
187
+ `docs/DECISION_LOG.md` is 45 decisions with the reasoning attached, including
188
+ the bugs that produced the design above. It is the most useful file here for
189
+ understanding *why* rather than *what*.
190
+
191
+ ## Licence
192
+
193
+ MIT.