August 2026 Feature Updates
August opened with a run of PostgreSQL storage internals and search-correctness fixes — batched transactional writes, Elasticsearch index migrations, and stricter _count/_offset parsing — running alongside the tail end of Luni-4's clippy remediation effort from July, then pivoted midmonth to a rebuilt MCP and OpenAPI surface and a hardened custom-operation runtime, before closing the month with tenant white-labeling, a from-scratch CLI OAuth flow, and ViewDefinition patient/group scoping.
Backend Changes
ViewDefinition patient/group scoping
- A new
compartment.rsmodule insql-on-fhirresolvespatient/groupinput parameters on aViewDefinitionRuninto a flat, deduplicated list ofPatient/{id}references, expanding Group membership to its Patient members and fetching only resources within that compartment via the PatientCompartmentDefinition's declared search-parameter mapping. - Unscoped, history-based runs now page through
_since/_count/_offsetin 1000-row pages up to a hard 50,000-row cap, instead of a single unpaged fetch, and the frontend runner gained a "Scope & output options" panel for patient/group references, row limit, and CSV header toggle. - PRs: #954.
AccessPolicyV2Assignment
- A new first-class resource,
AccessPolicyV2Assignment, decouples access-policy grants from the assignee: it holds just anaccessPolicyreference and alinkreference (to aClientApplication,Membership, orOperationDefinition), turning what was previously an embedded lookup into a separate, queryable join resource, generated in both the Rust and TypeScript model layers. - PRs: #946.
Tenant customization and white-labeling
- A new
HasteHealthTenantCustomizationoperation, gated to tenant owners, lets a tenant set a display name and a square logo (validated and resized to 150x150 via Lanczos3); a companionHasteHealthTenantBrandingread op and a/w/{tenant}/branding/logoroute serve it back. - Server-rendered chrome — login, signup, MFA, OIDC interaction, and error pages — now runs through a
TenantContextand atenant_banner()renderer showing the custom logo and tenant name, and the admin app picked up a matchinguseTenantBrandinghook andAppLogocomponent wired into a reworked sidebar. - PRs: #940, #941.
FHIRUser SMART claim
- When a token request's approved scopes include the SMART
fhirUserscope, the token route now resolves the authenticated Membership'slinkreference and embeds it as afhir_userclaim on the issued JWT; client-credentials tokens, which have no human membership, always getfhir_user: None. - PRs: #916.
CLI: browser-based OAuth login
- The CLI's prior login flow — a downloadable bundle shipping a fixed
client_secret— was replaced with a real Authorization Code + PKCE flow:login.rsgenerates a code verifier/S256 challenge, opens the system browser to the authorize URL, and binds a one-shot local listener on the profile's configured redirect URI to catch the callback and exchange it for tokens. - Secret material was split out of the non-secret
config.tomlinto its own.secrets.tomlso client secrets and cached tokens never surface viaconfig show-profile, CLI internals were reorganized under a dedicatedcli/module, andset-active-profile/delete-profilemoved from free-text prompts to aSelectdialog. Docs were updated to match, describing the new public-client, browser-login model. - PRs: #935, #947, #948, #949, #936.
Product and UX
Admin app search modal rewrite
SearchModal.tsxdropped its virtualized-list implementation for a categorized flat list combining a new set of static pages (Dashboard, Settings, All Resources, Event History, Indexing Errors, Bundle Import) with FHIR resource types, grouping resource types that already have a dedicated sidebar shortcut under that same category instead of a generic "Resources" bucket.- PRs: #912.
Indexing errors view
- A new admin-app
IndexingErrorsview and sidebar entry expose resources that failed search indexing and were "parked" rather than silently dropped, backed by a newindexing_errorsoperation and repository layer. - PRs: #911.
Doc link from the resource editor
- The
ResourceEditorheader gained a "Docs" button that opens the generated FHIR reference documentation for the resource type currently being edited in a new tab. - PRs: #951.
Platform and Runtime
Elasticsearch index migrations
- Search-parameter canonical URLs are now flattened (
.replaced with_) before being used as ES field names, since a literal.in a mapped field name creates a nested object path instead of a flat field — a gap that had been silently producing the wrong mapping shape. create_mappingnow diffs expected mapping properties against the live index: additive changes apply in place viaput_mapping, while removed search parameters — which mappings can't drop in place — go through a staging-index reindex, swap, and reindex-back cycle when aprune_removed_search_parametersflag is enabled. The index itself moved fromr4_search_indextor4_search_index_v2.- PRs: #950.
Custom-operation runtime hardening
DenoPoolmoved from round-robin worker assignment to a shared work queue so an idle worker always grabs the next job, with a queue-depth cap that rejects new work once the pool is saturated. Each worker now keeps one warm, unused V8 isolate ready to hide isolate-construction latency from the request path, and a dedicated watchdog thread terminates any script that runs past a 10-second timeout, since a blockingtokio::time::timeoutcan't interrupt a synchronous runaway script.- Module imports in custom-operation scripts are now categorically rejected rather than read from disk, transpiled JS is cached to skip redundant TypeScript parsing on repeat invocations, and the scripting FHIR client surface was filled out to cover the full REST API —
read,vread,patch,history,transaction,batch, and the remaininginvoke/deletevariants. - PRs: #945, #944, #943, #942.
MCP and OpenAPI schema rework
- MCP's tool list grew from search-only to the full REST surface — read, create, update, patch, delete, history, capabilities, transaction, and batch — with tool schemas referencing an external
/schemas/fhir/{ResourceType}endpoint instead of inlining definitions. - A vendored, generated MCP types file (nearly 28,000 lines) was replaced with a hand-written ~840-line module covering the MCP spec's JSON-RPC types, and a new
RESOURCE_SCHEMAScache gives each resource and complex type its own isolated JSON Schema with cross-type references resolved as external$refs. - PRs: #915, #913, #914.
Search result shaping and parameter validation
- A new
element_filteringmiddleware implements FHIR's_elementsand_summarysearch result subsetting, with_elementstaking precedence when both are present. _count/_offsetparsing was tightened twice this month: first fixing ES and PG history reads to reject negative values instead of silently clamping to zero, then requiring the parameters parse directly asu64rather than falling back to a default on malformed input.- PRs: #920, #902, #875.
PostgreSQL storage: model separation and batched writes
- Repository model files moved under a dedicated
pg/models/directory, andcreate/update/deleteonFHIRRepositorywere changed to take resources by value rather than by mutable reference, simplifying transaction-wrapping call sites. - A new buffered multi-row insert path lets transactional writes queue as owned rows and flush as a single batched
INSERT, which is what lets FHIRtransaction/batchbundle processing commit its member writes together instead of one row at a time — the same batching approach was then applied to startup artifact loading, cutting it from one request per resource to a singleBundle::batchcall. - PRs: #887, #886, #888, #889, #896.
Testscript runner coverage
- The testscript runner picked up
Batch, conditionalUpdateCreate,Patch(sourced from aBinaryfixture per the standard TestScript convention), and merged conditional-delete handling, plus improved logging detail in both the runner and the CLI'stestscriptcommand. - PRs: #937, #900.
Reliability, performance, and workspace hygiene
- The binary switched its global allocator to mimalloc and the release profile picked up thin LTO and single-codegen-unit builds; a hot path in FHIR structure-definition traversal that was compiling a regex per call was replaced with a plain string comparison, meaningfully speeding up FHIR profiling.
- Failed search-indexing resources are now tracked and "parked" rather than silently dropped or retried forever, with a gap detector that warns when indexed counts don't match the expected sequence delta, and the
operation_executor/wal_workercrate directories were renamed to match the workspace's hyphenated naming convention. - PRs: #927, #931, #919, #909, #908, #910, #923.
Artifacts, Tooling, and Maintenance
Website: Headless EHR re-centering and a live MCP showcase
- Homepage messaging was repositioned around "Headless EHR," dropping the prior EHR-integration-logo framing in favor of a new data-flow diagram and a live-rendered MCP tool catalog, auto-categorized into read/create/update/delete/bulk badges from the generated tool list.
- The homepage hero picked up a typing animation for its sample CLI command and JSON response (respecting
prefers-reduced-motion), and a new/contactpage lists business, developer, and security contact channels alongside GitHub Issues and Discussions links. - PRs: #925, #934, #891.
Generated docs and SEO
- The docs generator now produces a truncated meta description for every generated FHIR resource/data-type page, and category index pages across the API, auth, and reference sections picked up generated-index descriptions for better landing-page SEO; the full FHIR reference doc set was also regenerated to pick up the month's model and terminology changes.
- PRs: #952, #926.
CI and dependency hygiene
- The Sonar scan workflow was split into a main-branch workflow and a build/analyze pair so PRs from forks can be analyzed without exposing repo secrets to untrusted fork code, and the frontend package pinned several transitive dependencies and expanded audit-ignore entries to keep the dependency audit gate green against upstream advisories.
- PRs: #903, #890.
Standalone Commits (No PR Link)
- Frontend fixes: the SQL-on-FHIR raw-output panel no longer collapses to zero height in flex layouts, plus small follow-up styling fixes to the new contact page and homepage syntax highlighting.
- Sonar/CI config: generated Rust and TypeScript model code was excluded from SonarQube analysis, an "expensive" test flag was toggled off in CI, and a one-line test workflow fix followed the new clippy-action PR.
- Small backend follow-ups: a
usize→u64recast in the FHIR client storage middleware, and a stray.clone()removed from the search-indexing worker. - Docs and repo hygiene: README overview simplification, removal of a stale Postgres 16 benchmark section, an admin app URL fix, and a revised
SECURITY.mdwith updated supported versions and reporting instructions. - Build/deploy: a Dockerfile build stage trim.
- Version bumps:
ade25825b,759944b85.
Contributors
Thanks to Luni-4 for carrying the crate-by-crate clippy remediation effort straight through August. The month opened with the repository crate (#874), then a four-PR day covering hl7v2 (#882), a batch of miscellaneous lints (#879), fhir-converter (#880), and encryption (#881). Mid-month brought fhirpath (#892) and sd-to-json-schema (#893), followed by a three-crate day covering worker (#897), wal_worker (#898), and macro-loads (#895), then fhir-search (#894) alongside a README development-section improvement (#901). fhir-subscription-processor (#906) and a second missing-lints sweep (#907) followed, then fhir-profiling (#905), and the effort wrapped with a three-PR day covering the first missing-lints sweep (#904), openapi-schema-generator (#921), and operation-executor (#922), before a final pass on sql-on-fhir (#924) closed out the workspace-wide effort begun back in July.
