Quickstart
Every command on this page was run against the current build on 2026-08-01, and the output is pasted verbatim. If your output differs, that is a finding; tell us.
Install
SourceLock is a Python package; it requires Python 3.11 or newer. Install it with pipx from a checkout of the repository (there is no PyPI release yet, and this page will not pretend otherwise):
$ pipx install ./sourcelock
This puts one executable on your PATH: hc-source.
List tools
Adapters are discovered automatically; each one contributes tools under its source id: CMS coverage policy (coverage.*), NPPES/PECOS (provider.*), ICD-10-CM/HCPCS (codes.*), CMS-HCC (hcc.*), the OIG LEIE (leie.*), and the packaged reference adapter (demo.*). A new adapter registers the same way and appears in this list without any configuration. An adapter that fails to import does not vanish quietly: hc-source tools exits 2 and names the module, and hc-source mcp refuses to start, because a broken adapter looks exactly like one that was never installed.
$ hc-source tools hc-source tools ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ ┃ tool ┃ parameters ┃ description ┃ ┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┩ │ codes.hcpcs_lookup │ code, date │ Look up a HCPCS Level II code or modifier │ │ │ │ in the pinned quarterly file; with a date │ │ │ │ of service, adds a validity verdict from │ │ │ │ the record's code-added/termination │ │ │ │ interval. │ │ codes.latest_release │ - │ Detect the current and staged │ │ │ │ ICD-10-CM/HCPCS releases: what governs │ │ │ │ today (from the vendored manifest) and what │ │ │ │ is posted upstream (live CDC/CMS probe), │ │ │ │ with staged-release warnings. │ │ codes.lookup │ code, date │ Look up an ICD-10-CM code's description │ │ │ │ with full release provenance, from the │ │ │ │ release governing the given (or today's) │ │ │ │ date of service. │ │ codes.valid_on │ code, date │ Answer whether an ICD-10-CM code is │ │ │ │ valid/billable on a date of service, from │ │ │ │ the vendored release governing that date; │ │ │ │ fails closed when no vendored release │ │ │ │ provably governs it. │ │ coverage.companion_articles │ lcd_id, version │ Resolve an LCD's companion │ │ │ │ Billing-and-Coding Article(s) via the │ │ │ │ LCD<->Article crosswalk (keyless bulk │ │ │ │ export, or the live endpoint under an │ │ │ │ operator-supplied license token). │ │ coverage.lookup_lcd │ lcd_id, state │ Look up a Local Coverage Determination by │ │ │ │ L-number in the current weekly snapshot, │ │ │ │ jurisdiction-aware via an optional state │ │ │ │ filter. │ │ coverage.lookup_ncd │ section, version │ Look up a National Coverage Determination │ │ │ │ by manual section number (e.g. 30.3); │ │ │ │ narrative is withheld when the NCD flags │ │ │ │ licensed AMA CPT content. │ │ coverage.search_documents │ keyword, document_type, │ Search NCD/LCD/Article titles by keyword in │ │ │ state, contractor_id, │ the current release, with │ │ │ status │ state/contractor/status filters for local │ │ │ │ documents. │ │ coverage.snapshot │ - │ Return the current weekly MCD │ │ │ │ local-coverage snapshot identity │ │ │ │ (data_captured_through / │ │ │ │ refreshed_on_date). │ │ coverage.whats_changed │ scope, days_back, │ What changed in Medicare coverage policy │ │ │ document_type, │ over the last N days, from the MCD │ │ │ contractor_id │ whats-new feeds (local weekly snapshot or │ │ │ │ national event stream). │ │ demo.get_release │ - │ Return the pinned demo release: id, │ │ │ │ effective dates, and column set. │ │ demo.lookup_code │ code, include_retired │ Look up one demo code in the pinned │ │ │ │ release. │ │ hcc.hierarchy_explain │ diagnoses, model │ Explain CMS-HCC hierarchy suppression for a │ │ │ │ diagnosis list: which HCCs were zeroed by │ │ │ │ which, under V24 or V28. │ │ hcc.map │ diagnoses, model │ Map ICD-10-CM codes to CMS-HCC payment HCCs │ │ │ │ (V24 or V28) with labels and per-mapping │ │ │ │ provenance to the exact CMS model-software │ │ │ │ file. │ │ hcc.release_probe │ - │ Live identity check of the pinned CMS │ │ │ │ model-software zips (Content-Length + │ │ │ │ Last-Modified via 1-byte ranged GETs) plus │ │ │ │ the PY2028 cycle probe -- the same │ │ │ │ identities the hcc.model_software_release │ │ │ │ canary pins, reported per artifact against │ │ │ │ the pins recorded in this module, with │ │ │ │ remediation. │ │ hcc.score │ diagnoses, model, │ Community continuing-enrollee RAF score for │ │ │ payment_year, age, sex, │ a diagnosis list under CMS-HCC V24 or V28 │ │ │ dual, orig_disabled │ for a payment year: mapping, mandatory │ │ │ │ edits, hierarchies, interactions, HCC │ │ │ │ counts, coefficient sum, and pinned │ │ │ │ normalization -- raw and normalized, │ │ │ │ clearly labeled. │ │ leie.candidate_search │ last_name, first_name, │ Name-based CANDIDATE matching in the LEIE │ │ │ business_name, state │ snapshot — candidates only, never identity │ │ │ │ verification; verify at │ │ │ │ https://exclusions.oig.hhs.gov/. │ │ leie.check_npi │ npi │ Deterministic NPI-exact check against the │ │ │ │ current monthly LEIE full-file snapshot; a │ │ │ │ miss never clears a provider (~89.5% of │ │ │ │ records carry no NPI). │ │ leie.refresh_status │ - │ Freshness of the LEIE snapshot versus OIG's │ │ │ │ monthly by-the-10th cadence, plus the │ │ │ │ 12-month supplement retention limit. │ │ provider.evidence_ladder │ npi │ Report NPI_EXISTS (NPPES) and │ │ │ │ PECOS_ENROLLED (PPEF snapshot) as separate │ │ │ │ facts with separate provenance -- never a │ │ │ │ merged score. │ │ provider.lookup_npi │ npi │ Look up one NPI in the NPPES NPI Registry │ │ │ │ API v2.1 (daily refresh): identity, status, │ │ │ │ taxonomies, practice locations. │ │ provider.pecos_enrollments │ npi │ List a provider's Medicare FFS enrollment │ │ │ │ records from the PECOS PPEF quarterly │ │ │ │ snapshot (latest alias) for one NPI. │ └─────────────────────────────┴──────────────────────────┴─────────────────────────────────────────────┘
Call a tool, read the receipt
hc-source call prints the result, then the evidence receipt, then the non-claims. The receipt is also machine-readable; hc-source receipt validates a saved one against the schema. retrieved_at is stamped when the bytes are read, not when the receipt is built, so a cached answer carries its real retrieval time.
$ hc-source call codes.valid_on --param code=E11.9 --param date=2026-07-15 { "code": "E11.9", "code_nodot": "E119", "code_system": "ICD-10-CM", "date": "2026-07-15", "valid": true, "description": "Type 2 diabetes mellitus without complications", "release": "fy2026-april", "release_effective_from": "2026-04-01", "release_effective_to": "2026-09-30" } receipt ┌───────────────────┬──────────────────────────────────────────────────────────────────┐ │ source │ codes │ │ route │ codes.valid_on │ │ source_version │ fy2026-april │ │ effective │ 2026-04-01 .. 2026-09-30 │ │ retrieved_at │ 2026-08-01T16:53:44.551404+00:00 │ │ upstream_status │ None │ │ raw_sha256 │ 44a789704dc44246388df49bcdb3a03cb65ea235bcbdae1ee4b318c02e4cf7c1 │ │ transform_version │ 2 │ │ fallback │ no (authority used) │ └───────────────────┴──────────────────────────────────────────────────────────────────┘ does not prove: - PHI_NOT_EXPECTED: this tool accepts only public typed parameters. - DOES_NOT_INCLUDE_CPT_DESCRIPTORS: no HCPCS Level I (CPT) record and no ADA CDT record is vendored here, and no AMA- or ADA-authored descriptor text is reproduced. What is served is government-authored: NCHS ICD-10-CM codes and descriptions, and CMS HCPCS Level II codes, modifiers and descriptions from the ANWEB master file, verified to contain zero numeric-leading CPT and zero D#### CDT records. 17 of those CMS descriptions cite CPT code numbers inside the government's own definition text -- G0317 reads "list separately in addition to cpt codes 99306, 99310" -- and the complete set is AT, G0279, G0316, G0317, G0318, G0500, G0561, G2058, G2212, M1483, M1485, QP, S8055, S9034, S9123, V2530, V2531. Those digits ship exactly as CMS published them, carry no AMA descriptor with them, and are listed on the record by codes.hcpcs_lookup. CPT is copyright the American Medical Association: nothing here conveys a licence to it. - DOES_NOT_PROVE_COVERAGE: a code being valid for a date of service says nothing about whether any payer covers, prices, or pays for it. - DOES_NOT_PROVE_CURRENCY: answers come from the release train vendored at build time; CMS reposts corrections in place at the same URLs, so the vendored tables may lag an unannounced correction. `hc-source doctor` checks the train.
A miss is not a clearance, and the tool that could be misread that way says so on the call rather than in a footnote:
$ hc-source call leie.check_npi --param npi=1003000126 null receipt ┌───────────────────┬──────────────────────────────────────────────────────────────────┐ │ source │ leie │ │ route │ leie.check_npi │ │ source_version │ 2026-07-10 │ │ effective │ 2026-07-10 .. open │ │ retrieved_at │ 2026-08-01T16:53:46.192548+00:00 │ │ upstream_status │ 200 │ │ raw_sha256 │ d9211e32313a494efaf603302842a9f7426efd744bbf3c0af6f0547778c9f51d │ │ transform_version │ 2 │ │ fallback │ no (authority used) │ └───────────────────┴──────────────────────────────────────────────────────────────────┘ warning: NPI 1003000126 not found in the LEIE full-file snapshot (2026-07-10). ~89.5% of LEIE records carry no NPI — run leie.candidate_search and verify identity at https://exclusions.oig.hhs.gov/ before treating this as clearance. does not prove: - PHI_NOT_EXPECTED: this tool accepts only public typed parameters. - DOES_NOT_COVER_STATE_EXCLUSIONS: the LEIE is the federal OIG exclusion list only; state Medicaid exclusion and termination lists are separate and are not checked here — an LEIE miss does not mean the provider is excluded nowhere. - DOES_NOT_PROVE_CURRENCY: this answer comes from the monthly LEIE full-file snapshot (replaced by the 10th of each month, data through the end of the prior month) and may lag OIG actions by up to a month. - DOES_NOT_PROVE_NEVER_EXCLUDED: reinstated individuals are removed from the monthly full file; absence from the current snapshot says nothing about past exclusions. - DOES_NOT_CLEAR_ON_NPI_MISS: ~89.5% of LEIE records carry no NPI, so an NPI-exact miss does not clear a provider — run leie.candidate_search and verify identity at the official OIG online workflow: https://exclusions.oig.hhs.gov/.
When one answer takes several fetches
A receipt has one raw_sha256, but some tools read more than one artifact. Rather than let the first hash stand in for all of them, every input gets its own PROVENANCE_ARTIFACT line and a matching entry under data.facts.*.provenance: source, URL, HTTP status, hash, retrieval time. The receipt also warns you which artifact its own top-level hash covers.
$ hc-source call provider.evidence_ladder --param npi=1003000126 { "npi": "1003000126", "facts": { "NPI_EXISTS": { "value": true, "detail": { "status": "A", "enumeration_type": "NPI-1", "enumeration_date": "2007-08-31" }, "provenance": [ { "source": "npi-registry-api-2.1", "url": "https://npiregistry.cms.hhs.gov/api/", "raw_sha256": "eb7b12a9a3d4ae4ee0eba728cdca6136e6916beb05dc5e0dbdd8f4ee42634b99", "upstream_status": 200, "retrieved_at": "2026-08-01T16:53:44.947797+00:00" } ] }, "PECOS_ENROLLED": { "value": true, "detail": { "snapshot": "2026.07.17", "enrollments_are_complete": true, "enrollment_count": 4, "enrollment_ids": [ "I20091005000100", "I20130530000085", "I20150824000105", "I20231208000285" ] }, "provenance": [ { "source": "pecos-ppef-2026.07.17:dataset-resources", "url": "https://data.cms.gov/data-api/v1/dataset-resources/2457ea29-fc82-48b0-86ec-3b0755de7515", "raw_sha256": "ee761084a4d984543fb6c29d0be20ebc126a2b8b525ba51cc8fed8dfb66a4a8b", "upstream_status": 200, "retrieved_at": "2026-08-01T16:53:44.991507+00:00" }, { "source": "pecos-ppef-2026.07.17:data-page-1", "url": "https://data.cms.gov/data-api/v1/dataset/2457ea29-fc82-48b0-86ec-3b0755de7515/data", "raw_sha256": "61a331be7b40785b4b82be2d4acf362bf001528c1a2d8cecc03165a1c9275056", "upstream_status": 200, "retrieved_at": "2026-08-01T16:53:45.051068+00:00" }, { "source": "pecos-ppef-2026.07.17:dataset-resources-recheck", "url": "https://data.cms.gov/data-api/v1/dataset-resources/2457ea29-fc82-48b0-86ec-3b0755de7515", "raw_sha256": "ee761084a4d984543fb6c29d0be20ebc126a2b8b525ba51cc8fed8dfb66a4a8b", "upstream_status": 200, "retrieved_at": "2026-08-01T16:53:45.099017+00:00" } ] } }, "ladder_note": "Distinct facts, deliberately not merged: NPI existence (NPPES, daily refresh) and Medicare FFS enrollment (PECOS PPEF, quarterly snapshot) are different assertions with different vintages." } receipt ┌───────────────────┬──────────────────────────────────────────────────────────────────┐ │ source │ provider │ │ route │ provider.evidence_ladder │ │ source_version │ npi-registry-api-2.1+pecos-ppef-2026.07.17 │ │ effective │ 2026-07-17 .. open │ │ retrieved_at │ 2026-08-01T16:53:45.051068+00:00 │ │ upstream_status │ 200 │ │ raw_sha256 │ 61a331be7b40785b4b82be2d4acf362bf001528c1a2d8cecc03165a1c9275056 │ │ transform_version │ 2 │ │ fallback │ no (authority used) │ └───────────────────┴──────────────────────────────────────────────────────────────────┘ warning: COMPOSITE_EVIDENCE: this receipt's raw_sha256/upstream_status cover the first PECOS PPEF data page only. Every artifact behind either fact -- the NPPES response, the PPEF dataset-resources metadata, each data page -- is listed below as a PROVENANCE_ARTIFACT line and inside data.facts.*.provenance. The two sources have different vintages. warning: PROVENANCE_ARTIFACT: source=npi-registry-api-2.1 url=https://npiregistry.cms.hhs.gov/api/ status=200 sha256=eb7b12a9a3d4ae4ee0eba728cdca6136e6916beb05dc5e0dbdd8f4ee42634b99 retrieved_at=2026-08-01T16:53:44.947797+00:00 warning: PROVENANCE_ARTIFACT: source=pecos-ppef-2026.07.17:dataset-resources url=https://data.cms.gov/data-api/v1/dataset-resources/2457ea29-fc82-48b0-86ec-3b0755de7515 status=200 sha256=ee761084a4d984543fb6c29d0be20ebc126a2b8b525ba51cc8fed8dfb66a4a8b retrieved_at=2026-08-01T16:53:44.991507+00:00 warning: PROVENANCE_ARTIFACT: source=pecos-ppef-2026.07.17:data-page-1 url=https://data.cms.gov/data-api/v1/dataset/2457ea29-fc82-48b0-86ec-3b0755de7515/data status=200 sha256=61a331be7b40785b4b82be2d4acf362bf001528c1a2d8cecc03165a1c9275056 retrieved_at=2026-08-01T16:53:45.051068+00:00 warning: PROVENANCE_ARTIFACT: source=pecos-ppef-2026.07.17:dataset-resources-recheck url=https://data.cms.gov/data-api/v1/dataset-resources/2457ea29-fc82-48b0-86ec-3b0755de7515 status=200 sha256=ee761084a4d984543fb6c29d0be20ebc126a2b8b525ba51cc8fed8dfb66a4a8b retrieved_at=2026-08-01T16:53:45.099017+00:00 does not prove: - PHI_NOT_EXPECTED: this tool accepts only public typed parameters. - NOT_A_SCORE: NPI_EXISTS and PECOS_ENROLLED are independent facts with independent vintages. SourceLock reports them separately and never merges them into a combined verdict; any downstream aggregation is the consumer's claim, not this receipt's. - NPI_PRESENT_IS_NOT_CREDENTIALED: an NPI record proves identity registration only. CMS states verbatim that issuance of an NPI does not ensure or validate that the provider is licensed or credentialed; NPPES license numbers are self-reported and unvalidated. - PECOS_ACTIVE_IS_NOT_ALL_PAYER_ACTIVE: a PPEF row means approved to bill Medicare fee-for-service (or an 855O on file) as of the quarterly extract date -- it says nothing about Medicaid, commercial payers, network participation, or today. - DOES_NOT_PROVE_MEDICARE_ENROLLMENT: an NPPES record says nothing about PECOS enrollment, Medicare billing privileges, or participation in any payer's network. - MAIN_FILE_ONLY: absence from the PPEF main enrollment extract is not proof of non-enrollment -- multi-NPI enrollments can carry an NPI only in the Additional NPIs sub-file, which this API filter does not search.
Pin your sources
From your repo root, observe every source now and pin what it says. Commit the resulting source-lock.json next to your other lockfiles.
$ hc-source lock init wrote /tmp/billing-service/source-lock.json -- 6 source(s), 23 canary expectation(s)
If a canary cannot be observed, lock init refuses to write and exits 2. That is deliberate. A run that pins what it can reach and drops the rest deletes exactly the pins that detect drift, and it does it when you are offline and least likely to notice. Existing pins are never removed:
$ HC_SOURCE_PROVIDER_NPPES_FILES_URL="file:///nonexistent/nope.html" \ hc-source lock init --source provider ! provider.nppes_v2_files: FileNotFoundError (previous pin kept) refusing to write /tmp/billing-service/source-lock.json: 1 canary/canaries could not be observed. Nothing was changed -- the existing pins are intact. Fix the source (or the adapter) and run again, or accept a partial pin with `hc-source lock init --allow-partial`.
Pass --allow-partial to accept the incomplete run. Previous pins are still carried forward, the output says so in as many words, and the exit code is still 2. The write itself is a temp file plus a rename, so an interrupted lock init never leaves half a lockfile behind.
Gate CI with doctor
Doctor runs every adapter's canaries, cheap upstream observations like a release id or a row count, and compares them to the lockfile. The via column names which source actually answered, so an ok from a fallback mirror while the authority is dark is visible rather than implied.
$ hc-source doctor hc-source doctor (source-lock.json) ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━┳━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┓ ┃ canary ┃ status ┃ via ┃ observed ┃ expected ┃ ┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━╇━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━┩ │ codes.cm_governing_release │ ok │ authority │ fy2026-april │ fy2026-april │ │ codes.cm_release_train │ ok │ authority │ latest_posted=fy2027;… │ latest_posted=fy2027;… │ │ codes.hcpcs_governing_quarter │ ok │ authority │ 2026q3 │ 2026q3 │ │ codes.hcpcs_release_train │ ok │ authority │ current=2026q3:posted… │ current=2026q3:posted… │ │ codes.vendored_tables │ ok │ authority │ 060a589c98b976bbdca89… │ 060a589c98b976bbdca89… │ │ coverage.api_contract │ ok │ authority │ openapi=3.0.3;title=C… │ openapi=3.0.3;title=C… │ │ │ │ │ API;required-paths=ok │ API;required-paths=ok │ │ coverage.bulk_export │ ok │ authority │ application/zip;size-… │ application/zip;size-… │ │ coverage.license_gate │ ok │ authority │ 401 │ 401 │ │ coverage.ncd_anchor │ ok │ authority │ 30.3|Acupuncture|100-3 │ 30.3|Acupuncture|100-3 │ │ coverage.reference_tables │ ok │ authority │ state6=California - │ state6=California - │ │ │ │ │ Entire │ Entire │ │ │ │ │ State;contract_types=… │ State;contract_types=… │ │ coverage.weekly_snapshot │ ok │ authority │ 20260730 │ 20260730 │ │ demo.record_count │ ok │ authority │ 3 │ 3 │ │ demo.release_id │ ok │ authority │ 2026.07 │ 2026.07 │ │ hcc.coefficient_spots │ ok │ authority │ 0.330|0.441|1.067|1.1… │ 0.330|0.441|1.067|1.1… │ │ hcc.model_software_release │ ok │ authority │ 733317@23 Dec │ 733317@23 Dec │ │ │ │ │ 2025|802577@10 Jan │ 2025|802577@10 Jan │ │ │ │ │ 2025|332632@02 Apr │ 2025|332632@02 Apr │ │ │ │ │ 2026 │ 2026 │ │ hcc.vendored_tables │ ok │ authority │ b7d1f22aa272f3cb │ b7d1f22aa272f3cb │ │ leie.content │ ok │ authority │ canonical:d3a4b7c963c… │ canonical:d3a4b7c963c… │ │ leie.full_file │ ok │ authority │ 2026-07-10 │ 2026-07-10 │ │ leie.header │ ok │ authority │ 18 │ 18 │ │ leie.waivers │ ok │ authority │ advisory │ advisory │ │ provider.npi_api_contract │ ok │ authority │ v2.1:1003000126:NPI-1… │ v2.1:1003000126:NPI-1… │ │ provider.nppes_v2_files │ ok │ authority │ NPPES_Data_Disseminat… │ NPPES_Data_Disseminat… │ │ provider.pecos_ppef │ ok │ authority │ ppef-2026.07.17:rows=… │ ppef-2026.07.17:rows=… │ └───────────────────────────────┴────────┴───────────┴────────────────────────┴────────────────────────┘ 23 ok, 0 drift, 0 unreachable, 0 schema_changed, 0 unpinned, 0 stale, 0 error note codes.cm_governing_release: ICD-10-CM release governing today's date, from the vendored manifest note codes.cm_release_train: latest ICD-10-CM FY and April update posted upstream (posted != effective) note codes.hcpcs_governing_quarter: HCPCS quarterly governing today's date, from the vendored manifest note codes.hcpcs_release_train: HCPCS quarterly slugs posted upstream (range-probe; posted != effective) note codes.vendored_tables: canonical content digest of 3 vendored derived tables note coverage.api_contract: spec v1.6, 97 total paths (policy: additions upstream are informational; only removal of a load-bearing path alarms) note coverage.bulk_export: 1276829 bytes, last-modified Thu, 30 Jul 2026 02:00:15 GMT (1-byte ranged probe; band 900000-2500000) note coverage.license_gate: unauthenticated LCD detail probe; 401 means the license gate is intact note coverage.ncd_anchor: document_version 2 (version bumps are routine policy updates and deliberately excluded from the pinned value) note coverage.reference_tables: MCD-internal keyspaces backing the jurisdiction joins (state_id is not FIPS) note coverage.weekly_snapshot: captured through 20260726 note demo.record_count: row count of the pinned release note demo.release_id: release id and declared column set note hcc.coefficient_spots: v28 CNA_F65_69 | v24 CFA_F65_69 | 2026/2024 normalization | payment-HCC counts note hcc.model_software_release: upstream Content-Length@Last-Modified of sw2026, sw2025, py2026, in that order note hcc.vendored_tables: canonicalized-content hash of the vendored mapping/coefficient tables note leie.content: records=83665 note leie.full_file: Last-Modified of UPDATED.csv; a new monthly release moves this forward note leie.header: column count of the UPDATED.csv header; the hash locks the exact names note leie.waivers: ok: 3/3 CSV waiver surnames found on the waivers page note provider.npi_api_contract: anchor NPI record and response shape note provider.nppes_v2_files: 1 monthly, 3 weekly, 1 deactivation file(s) listed note provider.pecos_ppef: latest-alias snapshot id, row count, and column set
Exit codes are the contract:
| 0 | Every canary matched the lockfile. Ship. |
| 1 | Drift or schema change. The report names the canary, the observed and expected values, and the exact remediation. |
| 2 | Unreachable, or the adapter itself failed. error is kept apart from unreachable because “CMS is down” and “our adapter has a bug” need opposite fixes and used to print the same line. |
| 3 | Observed, but nothing pinned it. This code exists because a missing or half-written source-lock.json used to report 23 ok, 0 drift at exit 0: a build that verified nothing, reporting green. |
| 4 | Matched, but what it read is out of date. The same failure wearing a friendlier face: a match against data the source stopped publishing. |
unpinned, stale and error are statuses as well as exit codes. Here is what an unpinned canary looks like, produced by deleting one entry from the lockfile:
$ hc-source doctor --source demo # after deleting demo.record_count from the lockfile hc-source doctor (source-lock.json) ┏━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━┳━━━━━━━━━━━┳━━━━━━━━━━┳━━━━━━━━━━┓ ┃ canary ┃ status ┃ via ┃ observed ┃ expected ┃ ┡━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━╇━━━━━━━━━━━╇━━━━━━━━━━╇━━━━━━━━━━┩ │ demo.record_count │ unpinned │ authority │ 3 │ - │ │ demo.release_id │ ok │ authority │ 2026.07 │ 2026.07 │ └───────────────────┴──────────┴───────────┴──────────┴──────────┘ 1 ok, 0 drift, 0 unreachable, 0 schema_changed, 1 unpinned, 0 stale, 0 error demo.record_count [unpinned]: This canary was observed but never compared: source-lock.json does not pin it, so this run cannot tell you whether upstream moved. Pin it with `hc-source lock init` (and commit the lockfile) before treating this run as a verification. note demo.record_count: row count of the pinned release note demo.record_count: not pinned in source-lock.json; run `hc-source lock init` to pin it so drift can be detected note demo.release_id: release id and declared column set
A minimal GitHub Actions step:
- name: Source assurance
run: hc-source doctor # any non-zero exit fails the jobOn GitHub, prefer the bundled composite action to wiring doctor by hand: it fails the job on drift and turns every failing canary into an error annotation carrying that canary's remediation text verbatim, so the person reading the red build sees the fix instead of a stack trace. It also refuses to trust the report on its own, requiring doctor's reported exit_code and the process's actual return code to agree. On the founding plan we run and maintain that wiring, with hosted canaries and update PRs; the raw step above works today with nothing but the CLI.
See drift happen
You do not have to wait for CMS to change something. NPPES really did retire its V1 bulk-file names on 2026-03-03, and pipelines that still generated V1 filenames silently got 404s. The repo carries a recording of what the listing page would look like if that class of change happened again. Point the provider adapter at it and watch doctor catch it:
$ pipx install . # from a sourcelock checkout $ hc-source lock init $ HC_SOURCE_PROVIDER_NPPES_FILES_URL="file://$PWD/tests/fixtures/provider/npi_files_v1_only.html" \ hc-source doctor --source provider # exits 1: provider.nppes_v2_files drifts, with the V1-retirement remediation verbatim
$ HC_SOURCE_PROVIDER_NPPES_FILES_URL="file://$PWD/tests/fixtures/provider/npi_files_v1_only.html" \ hc-source doctor --source provider hc-source doctor (source-lock.json) ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━┳━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━┓ ┃ canary ┃ status ┃ via ┃ observed ┃ expected ┃ ┡━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━╇━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━┩ │ provider.npi_api_contract │ ok │ authority │ v2.1:1003000126:NPI-1:A │ v2.1:1003000126:NPI-1:A │ │ provider.nppes_v2_files │ drift │ authority │ NPPES_Data_Disseminatio… │ NPPES_Data_Disseminatio… │ │ provider.pecos_ppef │ ok │ authority │ ppef-2026.07.17:rows=29… │ ppef-2026.07.17:rows=29… │ └───────────────────────────┴────────┴───────────┴──────────────────────────┴──────────────────────────┘ 2 ok, 1 drift, 0 unreachable, 0 schema_changed, 0 unpinned, 0 stale, 0 error note provider.npi_api_contract: anchor NPI record and response shape provider.nppes_v2_files [drift]: NPPES retired the V1 bulk files on 2026-03-03; only *_V2.zip names are published now (V2 extends the First Name and Legal Business Name field lengths). The listing this canary just read carries a V1-style name with no _V2 suffix, which means the page has regressed, a stale mirror is being served, or something upstream renamed the grammar again. Fix: open https://download.cms.gov/nppes/NPI_Files.html, read the 'Important Information' block (where CMS announced the V1 retirement), confirm the current version suffix, make sure nothing in your pipeline still generates V1 filenames (NPPES_Data_Dissemination_<Month>_<YYYY>.zip silently 404s), then re-pin with `hc-source lock init`. note provider.nppes_v2_files: 1 monthly, 3 weekly, 1 deactivation file(s) listed note provider.pecos_ppef: latest-alias snapshot id, row count, and column set
Run hc-source doctor again without the override and it goes back to green.
Sign a manifest
hc-source manifest builds an Ed25519-signed record of the current pins, vendored data hashes, and tool versions. The signature on its own proves that some lockfile was signed; --check-lock proves it was the one doctor is about to read, which is the only version of the claim worth anything in an audit.
$ hc-source manifest build wrote sourcelock-manifest.json -- 6 source(s), 6 vendored file(s), unsigned sign it with `hc-source manifest sign` before shipping it to anyone. $ hc-source manifest sign sourcelock-manifest.json --key ~/keys/manifest-signing.key signed sourcelock-manifest.json (Ed25519, key fingerprint e06b09c9da860420...) $ hc-source manifest verify sourcelock-manifest.json \ --key ~/keys/manifest-signing.pub --check-lock ./source-lock.json verification OK: signature valid (Ed25519, key fingerprint e06b09c9da860420...) manifest generated_at=2026-08-01T16:33:49.912188+00:00 sources=6 lockfile_sha256=c7a47183d521696b... signed_at=2026-08-01T16:33:50.118554+00:00 lockfile at source-lock.json matches the signed manifest.
Serve the same tools to an agent
hc-source mcp serves every discovered tool over MCP stdio, one MCP tool per adapter tool, with the same typed parameters, the same receipts, and the same refusals as the CLI. Your agent's answers arrive with their provenance attached. A typical client entry:
{
"mcpServers": {
"hc-source": {
"command": "hc-source",
"args": ["mcp"]
}
}
}