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 toolsexit 0
$ 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 callexit 0
$ 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_npiexit 0
$ 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_ladderexit 0
$ 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 initexit 0
$ 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 lock init (one source unreachable)exit 2
$ 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 doctorexit 0
$ 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:

0Every canary matched the lockfile. Ship.
1Drift or schema change. The report names the canary, the observed and expected values, and the exact remediation.
2Unreachable, 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.
3Observed, 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.
4Matched, 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 (one canary unpinned)exit 3
$ 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 job

On 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 doctor (planted V1 listing)exit 1
$ 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 | sign | verifyexit 0
$ 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"]
    }
  }
}