fhir-pkg-cli
2026.901.1609
dotnet tool install --global fhir-pkg-cli --version 2026.901.1609
dotnet new tool-manifest
dotnet tool install --local fhir-pkg-cli --version 2026.901.1609
#tool dotnet:?package=fhir-pkg-cli&version=2026.901.1609
nuke :add-package fhir-pkg-cli --version 2026.901.1609
FhirPkg
A C# SDK and CLI tool for discovering, resolving, downloading, caching, and managing FHIR packages from multiple registries.
Packages
| Package | Description | Status |
|---|---|---|
| fhir-pkg-lib | SDK library - add to your .NET projects | |
| fhir-pkg-cli | CLI tool - installs the fhir-pkg command |
Features
- Multi-registry resolution - queries the primary FHIR registry
(
packages.fhir.org), secondary registry, CI builds (build.fhir.org), HL7 website, NPM registries, and custom/private registries with automatic fallback. - Local disk cache - stores packages in the standard
~/.fhir/packageslayout with validated reads, transactional replacement, crash recovery, and same-identity coordination across SDK processes. - Hardened package sources - safely installs expected-identity or manifest-discovered packages from caller-owned streams and absolute HTTP/HTTPS URIs under finite compressed/archive limits.
- Dependency resolution - resolves full transitive dependency closures, retains every required exact package version, and uses conflict strategies only to select the preferred name-keyed projection.
- Always-live restore - resolves each project restore from the current manifest plus registry/cache state and installs coexisting exact versions.
- FHIR-aware versioning - understands pre-release hierarchies, wildcards, ranges, CI builds, and branch-specific builds.
- Resource indexing - indexes FHIR resources inside packages with fast lookup by resource type, canonical URL, or StructureDefinition flavor.
- Publish - publish package tarballs to a registry.
- Async & DI-ready - fully async with
CancellationTokensupport and first-classIServiceCollectionintegration.
Quick Start
CLI
# Install the tool
dotnet tool install --global fhir-pkg-cli
# Install a FHIR package
fhir-pkg install hl7.fhir.r4.core#4.0.1
# Install with transitive dependencies
fhir-pkg install hl7.fhir.us.core#6.1.0 --with-dependencies
# Restore project dependencies from package.json
fhir-pkg restore ./my-ig-project
# Search registries
fhir-pkg search --name hl7.fhir.us --fhir-version R4
# List cached packages
fhir-pkg list
# Get package info
fhir-pkg info hl7.fhir.us.core --versions
SDK
dotnet add package fhir-pkg-lib
using System.Text.Json.Nodes;
using FhirPkg;
using FhirPkg.Indexing;
using FhirPkg.Models;
// Create a manager with default options
using var manager = new FhirPackageManager();
// Use your own cancellation token where you have one
CancellationToken cancellationToken = default;
// Install a package
var record = await manager.InstallAsync("hl7.fhir.r4.core#4.0.1");
Console.WriteLine($"Installed to {record?.ContentPath}");
// Install caller-owned content from its current stream position.
// The manager leaves the stream open.
await using FileStream packageStream = File.OpenRead("./package.tgz");
PackageRecord direct = await manager.InstallAsync(
new PackageReference("example.package", "1.0.0"),
packageStream,
new PackageSourceInstallOptions
{
ExpectedSha256 = "..."
},
cancellationToken);
// Or discover the validated identity from a URI package manifest.
PackageRecord imported = await manager.ImportAsync(
new Uri("https://packages.example.test/package.tgz"),
options: null,
cancellationToken);
// Search registries
var results = await manager.SearchAsync(
new PackageSearchCriteria { Name = "hl7.fhir.us", FhirVersion = "R4" });
// Resolve without downloading
var resolved = await manager.ResolveAsync("hl7.fhir.us.core#latest");
// Search cached package resources. Missing indexes are generated and persisted
// lazily; newly installed packages are indexed eagerly.
ResourceInfo? profile = await manager.FindByCanonicalUrlAsync(
"http://hl7.org/fhir/StructureDefinition/Patient",
"hl7.fhir.r4.core#4.0.1");
JsonNode? resource = profile is null
? null
: await manager.ReadResourceAsync(profile);
Dependency Injection
services.AddFhirPackageManagement(options =>
{
options.CachePath = "/my/cache";
options.IncludeCiBuilds = false;
options.Registries.Add(new RegistryEndpoint
{
Url = "https://my-registry.example.com",
Type = RegistryType.FhirNpm,
AuthHeaderValue = "Bearer my-token",
});
});
// IFhirPackageManager exposes resource operations through additive extension
// methods. IFhirPackageResourceManager can also be injected directly; both
// resolve to the same singleton.
FhirPackageManager implements IHardenedFhirPackageManager, and the default
DiskPackageCache implements IHardenedPackageCache. Custom cache
implementations must advertise the hardened capability before any manager
install source is read. URI requests use the configured HttpClient,
ResponseHeadersRead, redirect policy, and a timeout covering the response
body copy. Network allow-list, proxy, and credential policy remain application
responsibilities.
Package acquisition and extraction are finite by default and can be tightened
with FhirPackageManagerOptions.InstallLimits, per-call InstallLimits, or the
FHIRPKG_MAX_* environment variables. Cache coordination applies to SDK users
of the same cache root; external tools that ignore .fhirpkg/locks are outside
that coordination boundary.
Resource indexes are derivative cache data. The manager validates existing
schema-v2 .index.json files, regenerates missing or invalid indexes under the
package identity lease, and atomically persists them before making them
searchable. Indexing failures from explicit or lazy queries are surfaced and
can be retried; eager post-install indexing failures are logged without
changing installation success. Parsed resources use an identity-aware LRU
cache controlled by ResourceCacheSize and ResourceCacheSafeMode. Custom
IPackageCache implementations without the SDK's generation-aware read
capability bypass parsed-resource caching.
Prerequisites
- .NET 8.0 SDK or later (8, 9, and 10 are supported; .NET 10 is recommended)
Building from Source
git clone https://github.com/GinoCanessa/dotnet-fhir-packages.git
cd dotnet-fhir-packages
dotnet build FhirPkg.sln
Running Tests
# Unit tests
dotnet test test/FhirPkg.Tests
# Integration tests (offline / recorded mode)
dotnet test test/FhirPkg.IntegrationTests
Documentation
| Document | Description |
|---|---|
| Documentation Index | Landing page for all developer docs |
| Changelog | User-visible changes for both packages, by release. |
| SDK Overview | Introduction, quick start, DI setup, configuration |
| SDK API Reference | Reference for the supported public surface — interfaces, models, and enums |
| Package Request Process | End-to-end walkthrough of resolution, download, extraction, caching, and indexing. |
| Version Resolution Policy | Configuration snapshots, fixups, pre-release rules, and FHIR-release filtering. |
| Release Process and Evidence | Exact-commit source CI, immutable candidate handoff, 3 x 3 qualification, publication gates, and evidence. |
| CLI Overview | Installation, quick start, command summary |
| CLI Reference | All commands, options, exit codes, and config |
| FHIR Package Reference | Package naming, versioning, resolution, registry API, caching, dependencies, client implementations, security, and errors. |
License
This project is licensed under the MIT License.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 is compatible. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
This package has no dependencies.
| Version | Downloads | Last Updated |
|---|---|---|
| 2026.901.1609 | 103 | 9/1/2026 |
| 2026.803.800 | 127 | 8/3/2026 |
| 2026.622.1701 | 144 | 6/22/2026 |
| 2026.324.1648 | 156 | 3/24/2026 |
### Added
- Added the tested `FhirPkg.Release` C# tool for validating release inputs,
package and symbol contents, synchronized candidates, publication state, and
published package provenance.
- Restore output now lists every exact resolved package identity, including
coexisting versions of the same package, in console and JSON formats.
- Added `ResolvedDirective.ResolutionWarnings`, an additive, null-defaulted list
of non-fatal diagnostics describing how a package source was chosen. The CLI's
`resolve` command prints each warning, and `--json` emits them as a
`resolutionWarnings` array.
- Added `FhirPackageManagerOptions.GitHubToken`, the CLI's `--github-token`
global option, and the `.fhir-pkg.json` `githubToken` key, which authenticate
the `api.github.com` repository lookups used when choosing the canonical
repository for a CI build. `null` — the default — keeps those lookups
unauthenticated and sends no `Authorization` header.
### Changed
- Pack, qualify, publish, and independently verify `fhir-pkg-lib` and
`fhir-pkg-cli` as one synchronized release candidate, with safe recovery from
partial NuGet publication.
- Migrated release workflow validation from PowerShell scripts to the C#
release tool.
- Updated GitHub workflows to the Node 24-compatible `actions/checkout@v6` and
`actions/setup-dotnet@v5`.
- Relaxed the `global.json` SDK policy from `rollForward: disable` to
`latestFeature`, so building from source no longer requires the exact
`10.0.302` patch and any `10.0.3xx`-or-later SDK works. CI still installs and
resolves `10.0.302` exactly.
- Audited the documentation set for currency, completeness, and correctness
ahead of this release: the CLI and SDK overviews now mirror their reference
documents and cover `--github-token` / `githubToken` / `GitHubToken`,
`docs/sdk-api-reference.md` carries a public-surface coverage table, and
`README.md`'s links resolve from the NuGet package page.
### Fixed
- Fixed the deployment regression that could publish the SDK without the CLI.
- Made transient Windows cache-replacement retries asynchronous and
cancellation-aware.
- Restored the defined FHIR/FHIRsmith wildcard grammar, including exact
two-part versions, part-specific numeric/label/build wildcards, and trailing
`?` remainder matching.
- Preserved and installed every required exact package version and its transitive
subgraph during recursive dependency resolution.
- Fixed `@current` implementation-guide resolution selecting an arbitrary fork or
feature branch. A plain `@current` now resolves the canonical repository's
default build — chosen by a package-id prefix table, then a GitHub non-fork
check, then the oldest build — and takes its version and date from that
repository's `package.manifest.json`. Previously the most recent build from any
publisher won, which made `hl7.fhir.uv.subscriptions-backport@current` fail to
install outright and silently mislabelled roughly 139 other packages.
- Fixed branch-qualified CI build URLs being collapsed to the default-branch
form. The winning record's branch is no longer discarded, so
`@current$branch` emits `.../branches/{branch}/package.tgz`.
- Fixed CI build dates being ranked by a lexical string comparison across two
incompatible published formats. Dates are now parsed to instants before
comparison.
### Removed
- Removed SDK and CLI project restore-lock APIs and options. Restore now always
resolves the live manifest, registry, and cache graph.