sct transcode
Map a stream of codes from one NHS terminology to another, pivoting through SNOMED CT. This is the sct equivalent of the NHS Data Migration Workbench TRANSCODE function - the workhorse of clinical data migration (forwarding legacy Read v2 / CTV3 GP records to SNOMED, or crosswalking SNOMED to ICD-10 / OPCS-4 for secondary-care reporting).
Composable by design: reads codes from stdin (or --input), writes TSV (or --json) to stdout, diagnostics to stderr - so it pipes straight into and out of sct ecl expand, cut, grep, jq, and sct codelist.
Prerequisite
The ICD-10 / OPCS-4 maps and concept history come from a database built with sct ndjson --refsets all:
sct ndjson --rf2 release.zip --refsets all --output snomed.ndjson
sct sqlite --input snomed.ndjson --output snomed.db
CTV3 / Read v2 maps (--from ctv3/read2 --to snomed) work on any snomed.db; ICD-10 / OPCS-4 and --forward-history need --refsets all. sct transcode fails with a clear message if the database lacks the required maps.
Usage
sct transcode --from <SYSTEM> --to <SYSTEM> [OPTIONS]
Systems: snomed, read2, ctv3, icd10, opcs4.
| Option | Description |
|---|---|
--from <SYSTEM> |
Source terminology of the input codes. |
--to <SYSTEM> |
Target terminology to map to. |
--input <FILE> |
Read codes from a file (leading token per line) instead of stdin. |
--forward-history |
Forward inactive SNOMED pivots to their replacement(s) via concept history. |
--json |
Emit JSON lines instead of TSV. |
--db <FILE> |
SNOMED CT database (auto-discovered when omitted). |
Output columns (TSV): input_code, target_code, snomed_pivot, display. One row per mapping (so many:one and one:many both expand to multiple rows).
Examples
# SNOMED -> ICD-10 for a list of concepts
printf '22298006\n73211009\n' | sct transcode --from snomed --to icd10
# Legacy GP migration: Read v2 -> SNOMED, forwarding any retired targets
cat read2_codes.csv | sct transcode --from read2 --to snomed --forward-history
# Two-hop: CTV3 -> (SNOMED) -> ICD-10
echo 'X200E' | sct transcode --from ctv3 --to icd10
# Compose with ECL: every descendant of Diabetes, as ICD-10
sct ecl expand '<<73211009' | sct transcode --from snomed --to icd10 --json
# Reverse lookup: which SNOMED concepts map to an ICD-10 code?
echo 'I219' | sct transcode --from icd10 --to snomed
How it works
Every mapping pivots through SNOMED CT:
- Source → SNOMED -
snomedpasses through;ctv3/read2resolve via theconcept_mapstable;icd10/opcs4reverse-resolve viacrossmaps. - (optional) history forwarding - if
--forward-historyand the pivot concept is inactive, it is forwarded to itsreplaced_by/same_as/possibly_equivalent_totarget(s) fromconcept_history. - SNOMED → target -
snomedpasses through;ctv3/read2viaconcept_maps;icd10/opcs4viacrossmaps.
See cross-terminology mapping for the full design and the DMWB-replacement context.