Help
Support and contributing
Where to file, what to include, and what a change has to satisfy before it can land. Reports that quote a spec section number get fixed fastest.
Where to file
The workspace is github.com/hl7-rust/hl7-rust, and the organization
around it — including the archived predecessor repositories — is at github.com/hl7-rust. The ER7 encoding layer is elsewhere again: er7-rust/er7-rust, its own organization, so file
encoding-level bugs there rather than here.
File against the workspace, not against a crate's archived former repository — those still carry
the old hl7-v2* names and are kept only so their history stays reachable.
What to include in a report
- The crate and its version.
cargo tree -p hl7-2if you are not sure what resolved. - A minimal message that reproduces it, redacted — see below. One segment is often enough.
- What you expected and what you got. The output of
hl7-v2 --pathson the message is usually the clearest way to show both. - The spec section, if you can find it. Each crate's
spec/index.mdis numbered specifically so it can be cited — “§4.2 says positional names are used here, but the output has …” turns a discussion into a fix. - Your Rust version, if it is a build failure.
Do not paste patient data
HL7 messages are clinical records. An issue tracker is public and permanent, and a message pasted into one cannot be unpasted.
Redact identifying values; keep the structure
MSH|^~\&|LAB|ACME|EHR|CLINIC|20260814080000||ORU^R01|MSG00042|P|2.5
PID|1||REDACTED^^^ACME&1.2.3.4&ISO^MR||REDACTED^REDACTED||REDACTED|F
OBX|1|NM|2093-3^Cholesterol^LN||187|mg/dL|<200|N|||FStructure is what reproduces a parsing bug — the delimiters, the field positions, the repetition separators, the component depth. Names, identifiers, dates of birth, and addresses are not. Replace them and the report still works.
If a bug genuinely depends on a specific byte sequence in a value — an unusual escape, a non-ASCII character set — describe the byte sequence rather than the record it appeared in.
How the repository is laid out
Cargo.toml the workspace: [workspace] members, nothing else
Cargo.lock one, at the root — never one inside a member
spec/ workspace-wide specs (the MSRV policy)
<crate>/
Cargo.toml the member's own manifest
README.md a tour
spec/index.md the normative specification, where behavior is normative
AGENTS.md conventions and required checks for changing this crate
CLAUDE.md points at AGENTS.md
LICENSE.md the same five-way boilerplate, byte for byte
samples/ example inputs, where the crate has themMost crate directories are former standalone repositories, merged in with git subtree so their commit history survived the move — which means git log <crate>/ reaches back before the workspace existed.
Member crates depend on each other by relative path, and the flat one-directory-per-crate layout was kept specifically so those paths did not have to change.
Conventions a change has to meet
Read the crate's own AGENTS.md before working in it — the workspace-level AGENTS.md covers only workspace-wide concerns. The checks every crate expects:
cargo test # unit and integration tests
cargo clippy --all-targets -- -D warnings # lint-clean
cargo fmt --check # formatting
cargo rustdoc --lib -- -W missing-docs # every public item documented
# And against the minimum supported Rust version
cargo +1.95 check --workspace --all-targets- One
Cargo.lock, at the root. Do not add one inside a member directory. - No
[workspace.package]inheritance or shared[workspace.dependencies]without discussion — either would touch every member's manifest at once. - MSRV is current stable minus three. Raising the floor is a breaking change and belongs in a release allowed to break.
- Licensing boilerplate is byte-for-byte identical in every crate. Do not invent different text for a new one.
- A change that spans crates updates every affected crate's
AGENTS.mdandspec/index.mdin the same change. - Behavior changes go in the spec first. The spec is the source of truth, so a code change that contradicts it is either a bug fix or an unstated spec change.
Adding dictionary coverage
Dictionary gaps are the most useful contribution, and the cheapest: filling one means editing one
JSON file under hl7-2/schemas/ and adding a test.
Add coverage when a real message motivates it, rather than speculatively — the crate's own spec says so, and a table filled in from the standard without a message behind it is a table nobody can check.
Before filing, consider whether it is a gap at all. An unmodelled difference between releases shows up as a positional name rather than a typed one, or as a missing warning — never as a rejected message or a lost value. That is honest incompleteness, and the spec says which differences each release currently claims.
Fixing this website
This site lives in the hl7-rust.github.io directory of the same workspace, built
with SvelteKit's static adapter and the Lily Design System headless Svelte components.
It deploys to GitHub Pages on every push to main.
Nothing here is normative — the site summarises the crates' READMEs and specs and links back to them. So a correction here is a documentation fix; a correction to the underlying behavior belongs against the crate.
Licensing your contribution
Everything in the workspace is offered under MIT, Apache-2.0, BSD-3-Clause, GPL-2.0-only, or GPL-3.0-only, at the user's option. A contribution is offered on the same terms, so that the choice stays available to everyone downstream.
Contact: joel@joelparkerhenderson.com.