`sct` CHANGELOG and release announcements

Hi Open Health Hubbers,

sct has moved quite quickly since I first posted about it, so I am starting this topic as a plain-English changelog. I will add a reply here whenever a new release has something useful to say, concentrating on what people can now do rather than the internal plumbing.

The current release is v0.19.0. This is a snapshot of what sct can do today.

What sct can do now

  • Start with a raw SNOMED CT RF2 release, including a .zip straight from NHS TRUD, and turn it into something much easier to work with locally.
  • Produce a single readable NDJSON data file, a searchable SQLite database, Parquet for data analysis, or a folder of Markdown files. These are all local files that you control and can regenerate at any time.
  • Find concepts quickly by code, term or synonym, with exact search, typo-tolerant search, search-as-you-type and optional meaning-based search.
  • Browse concept hierarchies and relationships, run ECL queries, draw diagrams and compare two SNOMED CT releases to see what changed.
  • Work with reference sets, historical replacements and mappings between SNOMED CT, CTV3, Read v2, ICD-10 and OPCS-4.
  • Build and validate clinical code lists as ordinary text files that can live in Git, while still importing and exporting common formats.
  • Explore SNOMED CT through a terminal interface or local web interface instead of having to learn every command first.
  • Run a local FHIR R4 terminology server, either directly or with Docker.
  • Give AI assistants such as Claude and Cursor safe, local access to terminology lookup and search through MCP.
  • Use the same terminology engine from Rust applications through the new Rust SDK.
  • Install prebuilt releases on Linux, macOS and Windows, including Homebrew, Scoop, AUR, Cargo and the shell installers.

The important bit is that the terminology stays on your machine. There is no Java or Elasticsearch requirement, and ordinary use does not depend on a remote terminology server. sct does not bundle SNOMED CT content itself, so you still need access to an appropriately licensed release.

Questions, bug reports, ideas and examples of how you are using it are all very welcome in this category.

Here’s my original video on sct from back in March - it’s a reasonable intro, but I will be updating it soon with a new video as there has been a LOT of further work optimising and improving sct since then.

sct v0.20.1 is out.

The headline change is a much leaner sct ndjson: RF2 input and concept output are now streamed instead of building several complete in-memory copies. On the 837,930-concept UK Monolith, peak memory fell from 6.42 GiB to 3.73 GiB (42% lower), while the canonical output remained byte-identical. The same paired run completed in 44 seconds rather than 59 seconds.

This should make full-release builds much more practical on 8 GB machines such as Raspberry Pis, and avoid the swap thrashing that can make conversion look stuck on slower disks.

Release: Release v0.20.1 · pacharanero/sct · GitHub

Benchmark details: Benchmarks - sct

sct 0.21.0

Release notes and binaries · Documentation

Two user-facing changes worth knowing about, plus a batch of robustness fixes.

One-step TRUD setup

Getting a new machine ready used to mean creating ~/.config/sct/, creating config.toml, and hand-writing a [trud] section before your first download. Now:

sct trud auth < my-trud-key.txt

It checks the key against TRUD before storing it, so a typo is caught immediately rather than on your first download, and it writes the file with owner-only permissions. If you already have a config.toml, only the api_key line changes - your comments and other settings are left exactly as they were. Piping the key (or --api-key-file) keeps it out of your shell history; passing it as an argument works too, with a warning.

Artefact names now follow the release through the pipeline

Previously sct ndjson named its output after the RF2 release, and then every later command threw that away, so you ended up with a generic snomed.db and no way to tell which release it came from. Every build command now names its output after its input:

uk-monolith-42.ndjson  ->  uk-monolith-42.db
                           uk-monolith-42.parquet
                           uk-monolith-42.fst
                           uk-monolith-42-embeddings.arrow

The name chosen is printed as Output: … so it is never a surprise, and sct still finds your database automatically with no --db flag - sct paths will show you which file it picked and why.

Breaking change, worth checking if you script sct: commands no longer write a fixed snomed.db unless the input is itself named snomed.ndjson. If you have a script that builds from a differently named NDJSON and then refers to snomed.db, either pass --output snomed.db explicitly or read the printed name. Interactive use is unaffected.

Robustness fixes

  • ECL parser: deeply nested or very long expressions could overflow the stack and abort the process. Pathological input now returns a clean parse error.
  • MCP server: a malformed Content-Length header silently ended the session, and the message size was unbounded. Framing is now validated and capped, malformed JSON-RPC gets a proper error response instead of silence, and an unterminated line can no longer drive an unbounded allocation.
  • TRUD: your API key could leak into error output, because it forms part of the request URL and transport errors print the URI. It is now redacted.
  • Read v2 import: a malicious or corrupt zip could be decompressed without limit. Entry sizes are now capped.

Also

sct runs on Android under Termux, and there is now a page about it. The published linux-aarch64 binary is statically linked, so it cannot use Android’s DNS resolver and sct trud fails on it; building from source in Termux with cargo install sct-rs works. The error message now tells you this rather than leaving you guessing.

We also corrected a claim in our own documentation: sct told users that NHS TRUD has maintenance windows “weekdays 18:00-08:00 and midnight-06:00”. TRUD publishes no downtime schedule at all - the only thing it says is to run automation on weekdays between 8am-6pm or midnight-6am. Our message had inverted one of the recommended windows into a maintenance window. It now quotes the guidance and cites the source.

sct v0.22.0

Released 2026-08-07. Full release notes · compare v0.21.0…v0.22.0

Highlights:

  • sct codelist export --format ecl - export a codelist’s active members as a compact, exact ECL expression, reusing the existing sct ecl compress engine. Round-trips cleanly with sct codelist add --ecl (the active member set survives export → re-import unchanged - now covered by an integration test).
  • New SNOMED CT primer in the docs - a plain-language introduction to core concepts (concepts, descriptions, relationships, refsets, ECL) for newcomers.
  • New FST / search-internals diagram with worked SNOMED examples, for anyone curious how the lexical index works under the hood.
  • sct trud downloads are now fsync’d before being persisted, closing a small window where a crash or power loss right after download could leave a truncated file mistaken for a complete one.
  • sct serve now warns when bound to a non-loopback address, since the FHIR endpoint has no built-in authentication.
  • Routine dependency updates (GitHub Actions + Cargo).

Install/upgrade: the usual channels are live - binaries, cargo install sct-rs, cargo binstall, the Homebrew tap, Scoop bucket, Docker Hub/GHCR images, and Python wheels via PyPI. The AUR package update is delayed this release - the AUR was down for maintenance at publish time - and will follow once it’s back up.

sct v0.23.1

Released 2026-08-14. Release notes · compare v0.22.0…v0.23.1

Highlights:

  • sct history brings together the inactive-concept story: why a code was retired and the SNOMED CT replacement association, with the same lifecycle context available from search, refset output, FST indexes, embeddings, the Rust SDK, and FHIR $validate-code.
  • sct bench is a local, user-facing self-benchmark. It can compare CLI and SDK query paths and emit text, Markdown, JSON, or a standalone HTML report without exposing host-identifying details.
  • The local FHIR R4 terminology server’s ValueSet/$expand now supports activeOnly, displayLanguage, includeDesignations, includeDefinition, and check-system-version. Unsupported input is refused rather than silently widening an expansion.
  • sct lookup now validates SNOMED CT identifiers with the Verhoeff check digit; the Rust SDK adds proximal primitive supertypes.
  • The release pipeline now builds the pinned Rust toolchain correctly on every supported target, so the public binaries and packages are reproducible across Linux, macOS, and Windows.

Install/upgrade: see the Installation guide.

sct v0.24.0

Released 2026-08-20. Release notes · compare v0.23.2…v0.24.0

Highlights:

  • Model-aware semantic search. sct embed and sct semantic now understand several embedding models out of the box - Nomic v1.5, Nomic v2 MoE, Qwen3 Embedding 0.6B, and EmbeddingGemma - each with the correct query/document handling and vector dimensions. They now refuse to search an artefact built with one model using a different one, instead of quietly returning wrong results.
  • A semantic-search quality benchmark. A new sct bench semantic runs a versioned regression corpus and reports retrieval quality alongside separate query-embedding and scan timings, so changes to semantic search can be measured rather than guessed.
  • Tighter ECL compression. Turning a set of concepts back into an exact ECL expression now covers more cases (reference-set covers and straddling exclusions) and picks tighter expressions, so round-tripping a codelist to ECL stays compact and exact.
  • FHIR ValueSet improvements in sct serve. Stored ValueSets can override their canonical URL, you can filter by status (e.g. GET /ValueSet?status=draft), and duplicate canonical URLs are now rejected rather than silently colliding.

As always, everything runs locally - no terminology server and no network calls at runtime.

Install/upgrade: see the Installation guide.

sct v0.24.2 (rolling up v0.24.1)

Released 2026-08-24. Release notes · compare v0.24.0…v0.24.2

Highlights (v0.24.1 and v0.24.2):

  • MCP search is usable again in strict clients. Every list-returning MCP tool - search, children, ancestors, hierarchy, and reference-set members - now matches its declared output schema, so MCP clients that validate responses no longer reject each returned row. Lookup-by-name works again, not just lookup by known SCTID. Thanks to Greg at Tiny Medical Apps for an exemplary bug report.
  • A more honest FHIR terminology server. $lookup, $validate-code, $subsumes, and $translate now check the code system and version you pass and refuse inputs they cannot honour rather than silently answering a different question. $validate-code now actually checks a supplied display term, and a $translate bug that mistook a target value set for the target code system is fixed.
  • Easier install. All installation options now live on the home page, and the Windows path leads with a one-line installer that sets up your PATH for you.

As always, everything runs locally - no terminology server and no network calls at runtime.

Install/upgrade: see the Installation guide.

sct v0.24.3

Released 2026-08-28. Release notes · compare v0.24.2…v0.24.3

Highlights:

  • MCP snomed_hierarchy fixed. It was returning rows missing the active field its schema requires - a regression from the v0.24.1 MCP fix - so strict MCP clients rejected its results. It now includes active like the other list tools, and listing the concepts in a hierarchy works again in schema-validating clients. This traces back to Greg at Tiny Medical Apps’ original report (#106) - thank you again.
  • More self-auditing under the hood. Ongoing FHIR/MCP conformance hardening: the server’s CapabilityStatement is now checked to advertise exactly the operations it implements, error responses are verified to be well-formed FHIR OperationOutcomes, and every MCP data tool’s output is validated against its declared schema - so this whole class of bug is now caught automatically.

As always, everything runs locally - no terminology server and no network calls at runtime.

Install/upgrade: see the Installation guide.

sct v0.24.4

Released 2026-08-28. Release notes · compare v0.24.3…v0.24.4

Two bug fixes:

  • sct serve request body size limit (DoS fix). Seven FHIR endpoints read the POST body with no size limit, so a single request with a multi-gigabyte body could exhaust server memory. A 1 MiB DefaultBodyLimit is now enforced on the router - generous for a legitimate FHIR batch Bundle, and every other route only reads the body to refuse it. If you run sct serve on a network-accessible host, upgrade.
  • $validate-code no longer silently skips the display check. When a code is a member of a stored codelist but absent from the loaded database (e.g. the codelist came from a different edition), the server now adds a message saying the supplied display could not be verified, instead of returning an unqualified result=true with the check silently dropped.

As always, everything runs locally - no terminology server and no network calls at runtime.

Install/upgrade: see the Installation guide.

sct v0.25.0

Released 2026-09-03. Release notes · compare v0.24.4…v0.25.0

Highlights:

  • ECL history supplements: {{ + HISTORY }} and friends now work in sct ecl and sct codelist queries, letting you pull in a concept’s historical predecessors and moved members.
  • Empty search index is no longer silent: sct now fails loudly with a clear diagnostic if a lexical search runs against an empty FTS index, instead of quietly returning no results.
  • sct trud download now fsyncs files before persisting, so a crash mid-download can’t leave a truncated artefact that looks complete.
  • Windows coverage is stronger: the test suite now runs on a Windows CI runner in every build, so Windows-only behaviour is actually exercised rather than just compiled.

Install/upgrade: see the Installation guide.

sct v0.26.0

Released 2026-09-22. Release notes · compare v0.25.0…v0.26.0

Highlights:

  • sct serve now expands SNOMED CT’s implicit ?fhir_vs=refset ValueSet, listing the reference sets available in the loaded edition with filtering, pagination, and designations.
  • FHIR expansion routes now reject unsupported or ignored inputs instead of silently returning a different value set, and preserve empty codelist semantics correctly.
  • ECL handling is safer and more precise, including correct history-supplement binding, term-annotation checks, and stronger separation between identifiers, annotations, and executable query syntax.
  • RF2 processing now resolves layered component identities correctly and preserves literal quotation marks in TSV fields.
  • Configuration and generated-output boundaries are stricter, preventing unrecognised settings or display data from silently changing persisted membership, records, markup, or executable syntax.

Install/upgrade: see the Installation guide.

sct v0.26.1

Released 2026-09-23. Release notes · compare v0.26.0…v0.26.1

Highlights:

  • Local and source builds no longer emit deprecation warnings when Cargo resolves the current rmcp release.
  • The MCP server and protocol tests now use the stable underlying configuration types and are verified against rmcp 3.4.0.

Install/upgrade: see the Installation guide.

sct v0.27.0

Released 2026-09-26. Release notes · compare v0.26.1…v0.27.0

Highlights:

  • sct serve --public-url now lets reverse-proxied deployments advertise the correct external FHIR base URL in metadata, ValueSets, and search results.
  • FHIR R4 responses now include the required CapabilityStatement date, ValueSet expansion timestamp, and search Bundle fullUrl fields.
  • Docker Compose and Caddy deployments derive reachable public URLs for both HTTPS domains and the local no-domain setup.
  • sct serve --cors-origin adds explicit browser CORS controls without weakening the loopback-only default.
  • The documentation now separates repository regression checks, FHIR structural validation, official terminology tests, and ECL evidence so conformance claims stay precise.

Install/upgrade: see the Installation guide.

sct v0.28.0

Released 2026-10-14. Release notes · compare v0.27.0…v0.28.0

Highlights:

  • sct search lexical|semantic|fuzzy provides one front door for the three search modes.
  • The FHIR server supports the $expand property parameter and includes the requested properties in expansion results.
  • History and ICD-10/OPCS-4 mapping commands now require evidence that their companion data was loaded, avoiding misleading empty results.
  • Provenance companions now survive NDJSON-to-Arrow conversion and can be recovered from Arrow metadata.
  • Subsumption requests are faster because the server caches transitive-closure capability checks.
  • Grouped ECL attribute refinements are rejected clearly instead of being flattened into a different expression.

Install/upgrade: see the Installation guide.

sct v0.29.0

Released 2026-10-15. Release notes · compare v0.28.0…v0.29.0

Highlights:

  • New sct cite command generates plain-text, BibTeX, or CSL-JSON citations for sct and the exact local SNOMED CT artefact recorded in its provenance, without exposing local paths or inventing missing metadata.
  • FHIR terminology operations now accept typed POST Parameters inputs, with an independent HL7 FHIR Validator gate covering representative responses.
  • FHIR lookup and subsumption requests reuse cached metadata and prepared statements for lower per-request overhead.
  • RF2 and NDJSON ingestion now rejects malformed input cleanly instead of panicking.

Install/upgrade: see the Installation guide.