medharness 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.
- medharness-0.1.0/LICENSE +21 -0
- medharness-0.1.0/PKG-INFO +199 -0
- medharness-0.1.0/README.md +154 -0
- medharness-0.1.0/dhfkit/__init__.py +36 -0
- medharness-0.1.0/dhfkit/__main__.py +5 -0
- medharness-0.1.0/dhfkit/api.py +88 -0
- medharness-0.1.0/dhfkit/artifact_fetcher.py +509 -0
- medharness-0.1.0/dhfkit/change_requests.py +147 -0
- medharness-0.1.0/dhfkit/cli.py +366 -0
- medharness-0.1.0/dhfkit/document_generation.py +194 -0
- medharness-0.1.0/dhfkit/exceptions.py +6 -0
- medharness-0.1.0/dhfkit/id_generator.py +116 -0
- medharness-0.1.0/dhfkit/junit_parser.py +129 -0
- medharness-0.1.0/dhfkit/lifecycle.py +149 -0
- medharness-0.1.0/dhfkit/local_adapter.py +553 -0
- medharness-0.1.0/dhfkit/models/__init__.py +1 -0
- medharness-0.1.0/dhfkit/models/config.py +167 -0
- medharness-0.1.0/dhfkit/models/item.py +95 -0
- medharness-0.1.0/dhfkit/repository/__init__.py +1 -0
- medharness-0.1.0/dhfkit/repository/git.py +121 -0
- medharness-0.1.0/dhfkit/repository/loader.py +241 -0
- medharness-0.1.0/dhfkit/repository/saver.py +164 -0
- medharness-0.1.0/dhfkit/result_store.py +205 -0
- medharness-0.1.0/dhfkit/templates/AI-harness/context.md +36 -0
- medharness-0.1.0/dhfkit/templates/README.md +142 -0
- medharness-0.1.0/dhfkit/templates/config/doc_types/cr.yaml +83 -0
- medharness-0.1.0/dhfkit/templates/config/doc_types/crs.yaml +46 -0
- medharness-0.1.0/dhfkit/templates/config/doc_types/def.yaml +123 -0
- medharness-0.1.0/dhfkit/templates/config/doc_types/rcm.yaml +44 -0
- medharness-0.1.0/dhfkit/templates/config/doc_types/rel.yaml +50 -0
- medharness-0.1.0/dhfkit/templates/config/doc_types/risk.yaml +67 -0
- medharness-0.1.0/dhfkit/templates/config/doc_types/soup.yaml +45 -0
- medharness-0.1.0/dhfkit/templates/config/doc_types/srs.yaml +30 -0
- medharness-0.1.0/dhfkit/templates/config/doc_types/swdd.yaml +32 -0
- medharness-0.1.0/dhfkit/templates/config/doc_types/sys.yaml +77 -0
- medharness-0.1.0/dhfkit/templates/config/doc_types/sysarch.yaml +23 -0
- medharness-0.1.0/dhfkit/templates/config/doc_types/uc.yaml +15 -0
- medharness-0.1.0/dhfkit/templates/config/global.yaml +168 -0
- medharness-0.1.0/dhfkit/templates/github/prompts/cr-analyze.md +69 -0
- medharness-0.1.0/dhfkit/templates/github/prompts/cr-develop.md +21 -0
- medharness-0.1.0/dhfkit/templates/github/workflows/dhf/ci.yml +108 -0
- medharness-0.1.0/dhfkit/templates/github/workflows/dhf/cr-analyze.yml +166 -0
- medharness-0.1.0/dhfkit/templates/github/workflows/dhf/cr-develop.yml +190 -0
- medharness-0.1.0/dhfkit/templates/github/workflows/dhf/cr-spec-iterate.yml +52 -0
- medharness-0.1.0/dhfkit/templates/github/workflows/dhf/cr-transition.yml +88 -0
- medharness-0.1.0/dhfkit/templates/github/workflows/product/cr-complete.yml +57 -0
- medharness-0.1.0/dhfkit/templates/github/workflows/product/review-pr.yml +89 -0
- medharness-0.1.0/dhfkit/templates/items/00_uc/UC-001.yaml +5 -0
- medharness-0.1.0/dhfkit/templates/items/01_crs/CRS-001.yaml +9 -0
- medharness-0.1.0/dhfkit/templates/items/02_sys/SYS-001.yaml +11 -0
- medharness-0.1.0/dhfkit/templates/items/03_srs/SRS-001.yaml +7 -0
- medharness-0.1.0/dhfkit/templates/items/04_swdd/SWDD-001.yaml +7 -0
- medharness-0.1.0/dhfkit/templates/items/05_sysarch/SYSARCH-001.yaml +7 -0
- medharness-0.1.0/dhfkit/templates/items/06_cr/CR-001.yaml +8 -0
- medharness-0.1.0/dhfkit/templates/items/07_rel/REL-001.yaml +6 -0
- medharness-0.1.0/dhfkit/templates/items/08_soup/SOUP-001.yaml +11 -0
- medharness-0.1.0/dhfkit/templates/items/09_risk/RISK-001.yaml +10 -0
- medharness-0.1.0/dhfkit/templates/items/10_rcm/RCM-001.yaml +9 -0
- medharness-0.1.0/dhfkit/templates/items/11_def/DEF-001.yaml +5 -0
- medharness-0.1.0/dhfkit/templates/plans/configuration_management_plan.md +48 -0
- medharness-0.1.0/dhfkit/templates/plans/development_plan.md +226 -0
- medharness-0.1.0/dhfkit/templates/plans/integration_plan.md +35 -0
- medharness-0.1.0/dhfkit/templates/plans/maintenance_plan.md +28 -0
- medharness-0.1.0/dhfkit/templates/plans/risk_management_plan.md +46 -0
- medharness-0.1.0/dhfkit/templates/plans/validation_plan.md +18 -0
- medharness-0.1.0/dhfkit/templates/plans/verification_plan.md +30 -0
- medharness-0.1.0/dhfkit/templates/specs/architecture_design_specification.md.j2 +179 -0
- medharness-0.1.0/dhfkit/templates/specs/change_request_specification.md.j2 +129 -0
- medharness-0.1.0/dhfkit/templates/specs/customer_requirement_specification.md.j2 +172 -0
- medharness-0.1.0/dhfkit/templates/specs/rcm_specification.md.j2 +112 -0
- medharness-0.1.0/dhfkit/templates/specs/requirements_specification.md.j2 +98 -0
- medharness-0.1.0/dhfkit/templates/specs/risk_specification.md.j2 +120 -0
- medharness-0.1.0/dhfkit/templates/specs/styles/default.css +200 -0
- medharness-0.1.0/dhfkit/templates/specs/test_specification.md.j2 +123 -0
- medharness-0.1.0/dhfkit/templates/specs/traceability_matrix.md.j2 +83 -0
- medharness-0.1.0/dhfkit/traceability.py +214 -0
- medharness-0.1.0/medharness/__init__.py +5 -0
- medharness-0.1.0/medharness/__main__.py +5 -0
- medharness-0.1.0/medharness/_helpers.py +476 -0
- medharness-0.1.0/medharness/adapters/__init__.py +1 -0
- medharness-0.1.0/medharness/adapters/protocol.py +86 -0
- medharness-0.1.0/medharness/cli/__init__.py +31 -0
- medharness-0.1.0/medharness/cli/ci.py +320 -0
- medharness-0.1.0/medharness/cli/cr.py +157 -0
- medharness-0.1.0/medharness/cli/dhf.py +375 -0
- medharness-0.1.0/medharness/cli/init.py +11 -0
- medharness-0.1.0/medharness/client.py +69 -0
- medharness-0.1.0/medharness/commands/__init__.py +1 -0
- medharness-0.1.0/medharness/commands/cr.py +246 -0
- medharness-0.1.0/medharness/core.py +676 -0
- medharness-0.1.0/medharness/graph.py +228 -0
- medharness-0.1.0/medharness/services/__init__.py +1 -0
- medharness-0.1.0/medharness/services/ci.py +342 -0
- medharness-0.1.0/medharness/services/git.py +52 -0
- medharness-0.1.0/medharness/services/github_event.py +129 -0
- medharness-0.1.0/medharness/services/github_session.py +59 -0
- medharness-0.1.0/medharness/services/spec_validation.py +131 -0
- medharness-0.1.0/medharness/workflows/__init__.py +1 -0
- medharness-0.1.0/medharness/workflows/cr_intake.py +147 -0
- medharness-0.1.0/medharness/workflows/init.py +470 -0
- medharness-0.1.0/medharness.egg-info/PKG-INFO +199 -0
- medharness-0.1.0/medharness.egg-info/SOURCES.txt +106 -0
- medharness-0.1.0/medharness.egg-info/dependency_links.txt +1 -0
- medharness-0.1.0/medharness.egg-info/entry_points.txt +4 -0
- medharness-0.1.0/medharness.egg-info/requires.txt +24 -0
- medharness-0.1.0/medharness.egg-info/top_level.txt +2 -0
- medharness-0.1.0/pyproject.toml +80 -0
- medharness-0.1.0/setup.cfg +4 -0
medharness-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 CompliantFlow contributors
|
|
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,199 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: medharness
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Open-source design-controlled development infrastructure for medical device and SaMD teams — includes dhfkit
|
|
5
|
+
Author: MedHarness Contributors
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/itercharles/MedHarness
|
|
8
|
+
Project-URL: Source, https://github.com/itercharles/MedHarness
|
|
9
|
+
Project-URL: Bug Tracker, https://github.com/itercharles/MedHarness/issues
|
|
10
|
+
Project-URL: Documentation, https://github.com/itercharles/MedHarness#readme
|
|
11
|
+
Keywords: medical-device,iec-62304,iso-14971,iec-82304-1,dhf,design-history-file,traceability,compliance,samd
|
|
12
|
+
Classifier: Development Status :: 3 - Alpha
|
|
13
|
+
Classifier: Intended Audience :: Healthcare Industry
|
|
14
|
+
Classifier: Intended Audience :: Developers
|
|
15
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
16
|
+
Classifier: Operating System :: OS Independent
|
|
17
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
20
|
+
Classifier: Topic :: Software Development :: Quality Assurance
|
|
21
|
+
Requires-Python: >=3.11
|
|
22
|
+
Description-Content-Type: text/markdown
|
|
23
|
+
License-File: LICENSE
|
|
24
|
+
Requires-Dist: pydantic>=2.0
|
|
25
|
+
Requires-Dist: click
|
|
26
|
+
Requires-Dist: networkx
|
|
27
|
+
Requires-Dist: pyyaml
|
|
28
|
+
Requires-Dist: python-frontmatter
|
|
29
|
+
Requires-Dist: jinja2
|
|
30
|
+
Requires-Dist: python-docx
|
|
31
|
+
Requires-Dist: gitpython
|
|
32
|
+
Requires-Dist: python-dateutil
|
|
33
|
+
Requires-Dist: python-dotenv
|
|
34
|
+
Requires-Dist: markdown
|
|
35
|
+
Provides-Extra: ai
|
|
36
|
+
Requires-Dist: google-genai; extra == "ai"
|
|
37
|
+
Provides-Extra: docs
|
|
38
|
+
Requires-Dist: weasyprint; extra == "docs"
|
|
39
|
+
Provides-Extra: dev
|
|
40
|
+
Requires-Dist: pytest; extra == "dev"
|
|
41
|
+
Requires-Dist: pytest-cov; extra == "dev"
|
|
42
|
+
Provides-Extra: full
|
|
43
|
+
Requires-Dist: medharness[ai,docs]; extra == "full"
|
|
44
|
+
Dynamic: license-file
|
|
45
|
+
|
|
46
|
+
# MedHarness
|
|
47
|
+
|
|
48
|
+
**AI harness and DHF tooling for medical device software teams.**
|
|
49
|
+
|
|
50
|
+
MedHarness is an open-source framework for building AI-driven engineering workflows on IEC 62304 /
|
|
51
|
+
FDA-regulated software projects. It combines two things:
|
|
52
|
+
|
|
53
|
+
1. **`medharness`** — a CI harness that structures how AI agents (Claude Code) interact with a
|
|
54
|
+
Design History File: pre-computing context, enforcing approval gates, persisting decisions,
|
|
55
|
+
and generating audit-ready evidence.
|
|
56
|
+
|
|
57
|
+
2. **`dhfkit`** — a standalone DHF engine for managing items, enforcing traceability
|
|
58
|
+
(UC → CRS → SRS → SWDD → TC), validating schema, and generating specification documents.
|
|
59
|
+
|
|
60
|
+
[](LICENSE)
|
|
61
|
+
[](https://python.org)
|
|
62
|
+
|
|
63
|
+
> **Harness engineering:** Rather than prompting an AI to "do compliance," MedHarness
|
|
64
|
+
> pre-computes the DHF context, injects it into the agent environment, defines approval gates
|
|
65
|
+
> the agent must pass through, and captures the agent's decisions back into the DHF — so the
|
|
66
|
+
> engineer controls the loop, not the agent.
|
|
67
|
+
|
|
68
|
+
---
|
|
69
|
+
|
|
70
|
+
## Install
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
# From source (not yet on PyPI):
|
|
74
|
+
git clone https://github.com/itercharles/MedHarness
|
|
75
|
+
cd MedHarness
|
|
76
|
+
pip install -e .
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
Verify:
|
|
80
|
+
|
|
81
|
+
```bash
|
|
82
|
+
medharness --help
|
|
83
|
+
dhfkit --help
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
---
|
|
87
|
+
|
|
88
|
+
## Quick Start
|
|
89
|
+
|
|
90
|
+
```bash
|
|
91
|
+
medharness init
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
Interactively scaffolds two repos:
|
|
95
|
+
|
|
96
|
+
- **DHF repo** — `DHF/config/`, item YAML templates, spec/plan Jinja2 templates,
|
|
97
|
+
GitHub Actions workflows for CR analysis, design, and CI validation
|
|
98
|
+
- **Product repo files** — `CLAUDE.md`, `engineering-control.yml`, `cr-complete.yml`,
|
|
99
|
+
Claude Code skills (`.claude/skills/`)
|
|
100
|
+
|
|
101
|
+
---
|
|
102
|
+
|
|
103
|
+
## How it works
|
|
104
|
+
|
|
105
|
+
A Change Request flows through five AI-assisted stages, each enforced by GitHub Actions:
|
|
106
|
+
|
|
107
|
+
```
|
|
108
|
+
Issue → cr-analyze (AI spec) → cr-design (AI DHF items) → cr-develop (AI code) → cr-complete
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
At each stage MedHarness:
|
|
112
|
+
- **Pre-computes DHF context** (`medharness dhf context overview`) and injects it as `$DHF_CONTEXT`
|
|
113
|
+
- **Runs Claude** with `--dangerously-skip-permissions` inside the DHF repo
|
|
114
|
+
- **Commits transitions** back to the DHF (`medharness dhf item transition --commit --push`)
|
|
115
|
+
- **Stores session IDs** in PR comments for iterative review (`medharness ci claude-session put/get`)
|
|
116
|
+
|
|
117
|
+
---
|
|
118
|
+
|
|
119
|
+
## CLI surface
|
|
120
|
+
|
|
121
|
+
```
|
|
122
|
+
medharness init
|
|
123
|
+
|
|
124
|
+
# DHF operations (run from DHF repo with --dhf DHF)
|
|
125
|
+
medharness --dhf DHF dhf item list|get|create|update|delete|transitions|transition
|
|
126
|
+
medharness --dhf DHF dhf validate schema|traceability
|
|
127
|
+
medharness --dhf DHF dhf doc list|generate|export
|
|
128
|
+
medharness --dhf DHF dhf test list
|
|
129
|
+
medharness --dhf DHF dhf context overview|implementation
|
|
130
|
+
medharness --dhf DHF dhf config doc-types
|
|
131
|
+
|
|
132
|
+
# CI gates (run from product repo)
|
|
133
|
+
medharness ci dhf-validate --dhf DHF
|
|
134
|
+
medharness ci test-coverage --dhf DHF
|
|
135
|
+
medharness ci evidence bundle --dhf DHF --out-dir ...
|
|
136
|
+
medharness ci artifacts generate --dhf DHF --out-dir ...
|
|
137
|
+
|
|
138
|
+
# GitHub Actions helpers
|
|
139
|
+
medharness ci github-event --github-output "$GITHUB_OUTPUT"
|
|
140
|
+
medharness ci claude-session put <pr_number> <session_id>
|
|
141
|
+
medharness ci claude-session get <pr_number>
|
|
142
|
+
|
|
143
|
+
# CR workflow
|
|
144
|
+
medharness cr workflow intake-github-issue-ci
|
|
145
|
+
medharness cr workflow complete-from-github-pr
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
---
|
|
149
|
+
|
|
150
|
+
## Python API
|
|
151
|
+
|
|
152
|
+
Use `dhfkit` directly in product repo automation without shelling out:
|
|
153
|
+
|
|
154
|
+
```python
|
|
155
|
+
from medharness.client import DHFClient
|
|
156
|
+
|
|
157
|
+
client = DHFClient(Path("../my-project-DHF/DHF"))
|
|
158
|
+
cr = client.get_item("CR-034")
|
|
159
|
+
context = client.get_cr_context("CR-034") # {"cr": {...}, "spec": "..."}
|
|
160
|
+
client.transition_item("CR-034", "in_review", performed_by="alice")
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
Or use `dhfkit` standalone (no dependency on `medharness`):
|
|
164
|
+
|
|
165
|
+
```python
|
|
166
|
+
from dhfkit.local_adapter import LocalDHFAdapter
|
|
167
|
+
|
|
168
|
+
adapter = LocalDHFAdapter(Path("DHF"))
|
|
169
|
+
items = adapter.list_items("SRS")
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
---
|
|
173
|
+
|
|
174
|
+
## Repository layout
|
|
175
|
+
|
|
176
|
+
| Directory | Purpose |
|
|
177
|
+
|-----------|---------|
|
|
178
|
+
| `medharness/` | CLI harness, CI gates, CR workflows, `init` scaffolding |
|
|
179
|
+
| `dhfkit/` | DHF engine: items, lifecycle, traceability, document generation |
|
|
180
|
+
| `dhfkit/templates/` | Starter DHF scaffold — config, specs, plans, sample items |
|
|
181
|
+
| `docs/` | Architecture, ADRs, compatibility contracts, roadmap |
|
|
182
|
+
|
|
183
|
+
`dhfkit` has no dependency on `medharness` and can be used standalone.
|
|
184
|
+
|
|
185
|
+
---
|
|
186
|
+
|
|
187
|
+
## Docs
|
|
188
|
+
|
|
189
|
+
- [docs/roadmap.md](docs/roadmap.md) — vision and milestone plan
|
|
190
|
+
- [docs/architecture.md](docs/architecture.md) — packages, scaffold model, DHF lifecycle
|
|
191
|
+
- [docs/compatibility-contracts.md](docs/compatibility-contracts.md) — stable public contracts
|
|
192
|
+
- [docs/adr/](docs/adr/) — architecture decision records
|
|
193
|
+
- [CHANGELOG.md](CHANGELOG.md) — version history
|
|
194
|
+
|
|
195
|
+
---
|
|
196
|
+
|
|
197
|
+
## License
|
|
198
|
+
|
|
199
|
+
MIT — see [LICENSE](LICENSE).
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
# MedHarness
|
|
2
|
+
|
|
3
|
+
**AI harness and DHF tooling for medical device software teams.**
|
|
4
|
+
|
|
5
|
+
MedHarness is an open-source framework for building AI-driven engineering workflows on IEC 62304 /
|
|
6
|
+
FDA-regulated software projects. It combines two things:
|
|
7
|
+
|
|
8
|
+
1. **`medharness`** — a CI harness that structures how AI agents (Claude Code) interact with a
|
|
9
|
+
Design History File: pre-computing context, enforcing approval gates, persisting decisions,
|
|
10
|
+
and generating audit-ready evidence.
|
|
11
|
+
|
|
12
|
+
2. **`dhfkit`** — a standalone DHF engine for managing items, enforcing traceability
|
|
13
|
+
(UC → CRS → SRS → SWDD → TC), validating schema, and generating specification documents.
|
|
14
|
+
|
|
15
|
+
[](LICENSE)
|
|
16
|
+
[](https://python.org)
|
|
17
|
+
|
|
18
|
+
> **Harness engineering:** Rather than prompting an AI to "do compliance," MedHarness
|
|
19
|
+
> pre-computes the DHF context, injects it into the agent environment, defines approval gates
|
|
20
|
+
> the agent must pass through, and captures the agent's decisions back into the DHF — so the
|
|
21
|
+
> engineer controls the loop, not the agent.
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
## Install
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
# From source (not yet on PyPI):
|
|
29
|
+
git clone https://github.com/itercharles/MedHarness
|
|
30
|
+
cd MedHarness
|
|
31
|
+
pip install -e .
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
Verify:
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
medharness --help
|
|
38
|
+
dhfkit --help
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
---
|
|
42
|
+
|
|
43
|
+
## Quick Start
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
medharness init
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
Interactively scaffolds two repos:
|
|
50
|
+
|
|
51
|
+
- **DHF repo** — `DHF/config/`, item YAML templates, spec/plan Jinja2 templates,
|
|
52
|
+
GitHub Actions workflows for CR analysis, design, and CI validation
|
|
53
|
+
- **Product repo files** — `CLAUDE.md`, `engineering-control.yml`, `cr-complete.yml`,
|
|
54
|
+
Claude Code skills (`.claude/skills/`)
|
|
55
|
+
|
|
56
|
+
---
|
|
57
|
+
|
|
58
|
+
## How it works
|
|
59
|
+
|
|
60
|
+
A Change Request flows through five AI-assisted stages, each enforced by GitHub Actions:
|
|
61
|
+
|
|
62
|
+
```
|
|
63
|
+
Issue → cr-analyze (AI spec) → cr-design (AI DHF items) → cr-develop (AI code) → cr-complete
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
At each stage MedHarness:
|
|
67
|
+
- **Pre-computes DHF context** (`medharness dhf context overview`) and injects it as `$DHF_CONTEXT`
|
|
68
|
+
- **Runs Claude** with `--dangerously-skip-permissions` inside the DHF repo
|
|
69
|
+
- **Commits transitions** back to the DHF (`medharness dhf item transition --commit --push`)
|
|
70
|
+
- **Stores session IDs** in PR comments for iterative review (`medharness ci claude-session put/get`)
|
|
71
|
+
|
|
72
|
+
---
|
|
73
|
+
|
|
74
|
+
## CLI surface
|
|
75
|
+
|
|
76
|
+
```
|
|
77
|
+
medharness init
|
|
78
|
+
|
|
79
|
+
# DHF operations (run from DHF repo with --dhf DHF)
|
|
80
|
+
medharness --dhf DHF dhf item list|get|create|update|delete|transitions|transition
|
|
81
|
+
medharness --dhf DHF dhf validate schema|traceability
|
|
82
|
+
medharness --dhf DHF dhf doc list|generate|export
|
|
83
|
+
medharness --dhf DHF dhf test list
|
|
84
|
+
medharness --dhf DHF dhf context overview|implementation
|
|
85
|
+
medharness --dhf DHF dhf config doc-types
|
|
86
|
+
|
|
87
|
+
# CI gates (run from product repo)
|
|
88
|
+
medharness ci dhf-validate --dhf DHF
|
|
89
|
+
medharness ci test-coverage --dhf DHF
|
|
90
|
+
medharness ci evidence bundle --dhf DHF --out-dir ...
|
|
91
|
+
medharness ci artifacts generate --dhf DHF --out-dir ...
|
|
92
|
+
|
|
93
|
+
# GitHub Actions helpers
|
|
94
|
+
medharness ci github-event --github-output "$GITHUB_OUTPUT"
|
|
95
|
+
medharness ci claude-session put <pr_number> <session_id>
|
|
96
|
+
medharness ci claude-session get <pr_number>
|
|
97
|
+
|
|
98
|
+
# CR workflow
|
|
99
|
+
medharness cr workflow intake-github-issue-ci
|
|
100
|
+
medharness cr workflow complete-from-github-pr
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
---
|
|
104
|
+
|
|
105
|
+
## Python API
|
|
106
|
+
|
|
107
|
+
Use `dhfkit` directly in product repo automation without shelling out:
|
|
108
|
+
|
|
109
|
+
```python
|
|
110
|
+
from medharness.client import DHFClient
|
|
111
|
+
|
|
112
|
+
client = DHFClient(Path("../my-project-DHF/DHF"))
|
|
113
|
+
cr = client.get_item("CR-034")
|
|
114
|
+
context = client.get_cr_context("CR-034") # {"cr": {...}, "spec": "..."}
|
|
115
|
+
client.transition_item("CR-034", "in_review", performed_by="alice")
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
Or use `dhfkit` standalone (no dependency on `medharness`):
|
|
119
|
+
|
|
120
|
+
```python
|
|
121
|
+
from dhfkit.local_adapter import LocalDHFAdapter
|
|
122
|
+
|
|
123
|
+
adapter = LocalDHFAdapter(Path("DHF"))
|
|
124
|
+
items = adapter.list_items("SRS")
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
---
|
|
128
|
+
|
|
129
|
+
## Repository layout
|
|
130
|
+
|
|
131
|
+
| Directory | Purpose |
|
|
132
|
+
|-----------|---------|
|
|
133
|
+
| `medharness/` | CLI harness, CI gates, CR workflows, `init` scaffolding |
|
|
134
|
+
| `dhfkit/` | DHF engine: items, lifecycle, traceability, document generation |
|
|
135
|
+
| `dhfkit/templates/` | Starter DHF scaffold — config, specs, plans, sample items |
|
|
136
|
+
| `docs/` | Architecture, ADRs, compatibility contracts, roadmap |
|
|
137
|
+
|
|
138
|
+
`dhfkit` has no dependency on `medharness` and can be used standalone.
|
|
139
|
+
|
|
140
|
+
---
|
|
141
|
+
|
|
142
|
+
## Docs
|
|
143
|
+
|
|
144
|
+
- [docs/roadmap.md](docs/roadmap.md) — vision and milestone plan
|
|
145
|
+
- [docs/architecture.md](docs/architecture.md) — packages, scaffold model, DHF lifecycle
|
|
146
|
+
- [docs/compatibility-contracts.md](docs/compatibility-contracts.md) — stable public contracts
|
|
147
|
+
- [docs/adr/](docs/adr/) — architecture decision records
|
|
148
|
+
- [CHANGELOG.md](CHANGELOG.md) — version history
|
|
149
|
+
|
|
150
|
+
---
|
|
151
|
+
|
|
152
|
+
## License
|
|
153
|
+
|
|
154
|
+
MIT — see [LICENSE](LICENSE).
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
"""dhfkit — standalone data-layer package for DHF repositories.
|
|
2
|
+
|
|
3
|
+
Public API
|
|
4
|
+
----------
|
|
5
|
+
Shared data types (safe to import anywhere):
|
|
6
|
+
Item, ProjectConfig, DocTypeConfig, ValidationError
|
|
7
|
+
|
|
8
|
+
DHF I/O utilities (for direct DHF-layer consumers such as tests and adapters):
|
|
9
|
+
ItemLoader, ResultStore, parse_junit_xml, ExecutionResult
|
|
10
|
+
|
|
11
|
+
Internal (not part of the public API):
|
|
12
|
+
ItemSaver, GitRepository, DocumentGenerator
|
|
13
|
+
— these are implementation details of the adapter layer.
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
from dhfkit.models.item import Item
|
|
17
|
+
from dhfkit.models.config import ProjectConfig, DocTypeConfig
|
|
18
|
+
from dhfkit.exceptions import ValidationError
|
|
19
|
+
from dhfkit.result_store import ResultStore
|
|
20
|
+
from dhfkit.junit_parser import parse_junit_xml, ExecutionResult
|
|
21
|
+
from dhfkit.repository.loader import ItemLoader
|
|
22
|
+
from dhfkit.artifact_fetcher import GitHubArtifactFetcher
|
|
23
|
+
from dhfkit.local_adapter import LocalDHFAdapter
|
|
24
|
+
|
|
25
|
+
__all__ = [
|
|
26
|
+
"Item",
|
|
27
|
+
"ProjectConfig",
|
|
28
|
+
"DocTypeConfig",
|
|
29
|
+
"ValidationError",
|
|
30
|
+
"ResultStore",
|
|
31
|
+
"parse_junit_xml",
|
|
32
|
+
"ExecutionResult",
|
|
33
|
+
"ItemLoader",
|
|
34
|
+
"GitHubArtifactFetcher",
|
|
35
|
+
"LocalDHFAdapter",
|
|
36
|
+
]
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
"""dhfkit API — reusable Python functions for DHF operations.
|
|
2
|
+
|
|
3
|
+
All functions accept a DHF root path and return structured data.
|
|
4
|
+
No Click, no stdout/stderr, no CLI concerns.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
from typing import Optional
|
|
9
|
+
|
|
10
|
+
from dhfkit.local_adapter import LocalDHFAdapter
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def _adapter(dhf_root: Path) -> LocalDHFAdapter:
|
|
14
|
+
return LocalDHFAdapter(dhf_root, auto_commit=False)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
# -- Item operations ----------------------------------------------------------
|
|
18
|
+
|
|
19
|
+
def get_item(dhf_root: Path, item_id: str) -> Optional[dict]:
|
|
20
|
+
return _adapter(dhf_root).get_item(item_id)
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def list_items(dhf_root: Path, doc_type: Optional[str] = None) -> list[dict]:
|
|
24
|
+
return _adapter(dhf_root).list_items(doc_type)
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def create_item(dhf_root: Path, data: dict, author: str = "system",
|
|
28
|
+
cr_id: Optional[str] = None) -> dict:
|
|
29
|
+
return _adapter(dhf_root).create_item(data, author=author, cr_id=cr_id)
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def update_item(dhf_root: Path, item_id: str, data: dict,
|
|
33
|
+
author: Optional[str] = None,
|
|
34
|
+
cr_id: Optional[str] = None) -> Optional[dict]:
|
|
35
|
+
return _adapter(dhf_root).update_item(item_id, data, author=author, cr_id=cr_id)
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def delete_item(dhf_root: Path, item_id: str, author: Optional[str] = None) -> bool:
|
|
39
|
+
return _adapter(dhf_root).delete_item(item_id, author=author)
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def get_item_transitions(dhf_root: Path, item_id: str) -> list[dict]:
|
|
43
|
+
return _adapter(dhf_root).get_available_transitions(item_id)
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def transition_item(dhf_root: Path, item_id: str, to_state: str,
|
|
47
|
+
performed_by: Optional[str] = None) -> dict:
|
|
48
|
+
return _adapter(dhf_root).execute_transition(item_id, to_state, performed_by=performed_by)
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
# -- Validation operations ----------------------------------------------------
|
|
52
|
+
|
|
53
|
+
def validate_schema(dhf_root: Path) -> dict:
|
|
54
|
+
return _adapter(dhf_root).validate_schema()
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def validate_traceability(dhf_root: Path) -> dict:
|
|
58
|
+
return _adapter(dhf_root).validate_traceability()
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
# -- Document operations ------------------------------------------------------
|
|
62
|
+
|
|
63
|
+
def list_doc_types(dhf_root: Path) -> list[str]:
|
|
64
|
+
return _adapter(dhf_root).get_available_doc_types()
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def generate_doc(dhf_root: Path, doc_type_code: str) -> dict:
|
|
68
|
+
return _adapter(dhf_root).generate_doc(doc_type_code)
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
def export_pdf(dhf_root: Path, doc_type_code: str) -> dict:
|
|
72
|
+
return _adapter(dhf_root).export_pdf(doc_type_code)
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
# -- Test result operations ---------------------------------------------------
|
|
76
|
+
|
|
77
|
+
def get_test_status(dhf_root: Path, tc_id: str) -> Optional[dict]:
|
|
78
|
+
return _adapter(dhf_root).get_test_result(tc_id)
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
def list_test_results(dhf_root: Path, status_filter: Optional[str] = None) -> dict[str, dict]:
|
|
82
|
+
return _adapter(dhf_root).get_all_test_results(status_filter)
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
# -- Config operations --------------------------------------------------------
|
|
86
|
+
|
|
87
|
+
def list_doc_type_configs(dhf_root: Path) -> list[dict]:
|
|
88
|
+
return _adapter(dhf_root).list_item_types()
|