EHR-Embedded AI Inference via CDS Hooks in Epic and Cerner
CDS Hooks lets AI recommendations surface directly in clinicians' existing workflows.

CDS Hooks is the plumbing that lets an AI service whisper a recommendation into a doctor's ear without the doctor ever leaving the chart they're already in. That's the whole idea: it lets an outside AI service surface a recommendation directly inside the doctor's existing workflow, without requiring a separate build inside the EHR vendor's proprietary rules engine. Before this specification existed, adding a new piece of decision support meant building inside the EHR vendor's own proprietary rules engine, which left no path for an outside AI service to surface a prediction at the point of care. CDS Hooks, an HL7 specification managed by the HL7 CDS Work Group, changed that by giving any external service a standardized API contract for delivering recommendations straight into the clinician's workflow.
The decoupling this produces is the whole point. A payer's coverage engine, a pharmacogenomics advisory tool, a clinical guideline service, and an AI inference pipeline all speak through the same hook-and-card contract, and none of them needs the EHR vendor's involvement to ship. A pharmacogenomics advisory tool, a clinical guideline service, and an AI inference pipeline all speak through the same hook-and-card contract because that portability is built into the architecture itself. It's backed by law: the ONC's 21st Century Cures Act requires certified EHRs to support FHIR and SMART on FHIR, which sets the compliance floor that makes this architecture work the same way across Epic, Oracle Health's Cerner platform, MEDITECH, and any other ONC-certified system. Vendors don't need a different integration philosophy for each EHR. They need to understand how each one interprets the same standard, which turns out to be a considerably harder problem than it sounds.
The request-response loop that carries AI inference into the clinician's view
Three protocols carry the weight here, and each does a different job. FHIR supplies the data, CDS Hooks supplies the timing, and SMART on FHIR supplies the trust layer. An AI agent that understands only one of these three cannot participate in patient care, no matter how good its underlying model is.
The loop itself runs in a fairly fixed sequence. A clinician action, opening a chart, drafting an order, signing an order, triggers the EHR to fire a hook to whatever CDS service endpoint is registered for that event. That hook request arrives as JSON over HTTPS, carrying a hook identifier, the patient context, and a set of prefetched FHIR resources the EHR already holds in memory. The receiving service authenticates through the SMART on FHIR backend-services flow to get an access token, which it needs for any FHIR queries beyond what was prefetched. From there it reads FHIR R4 resources (Patient, Condition, MedicationRequest, Observation for labs, and other clinical resource types) to build out the clinical picture the model needs. The model, an LLM or a narrower predictive model, reasons over that context, checking for care gaps, cross-referencing guidelines, and generating a recommendation. The service then returns one or more CDS Cards as JSON, and the EHR renders them inline in the clinician's workspace, with no page reload and no separate window. If the clinician approves something the service generated, a write-back tool can submit a DocumentReference back to the FHIR server, closing the loop.
Cards themselves follow a simple anatomy: three severity levels (info, warning, critical), and the option to link out to a clinical reference like UpToDate or OpenEvidence, suggest a change to an order, or launch a full SMART on FHIR app inside the EHR for deeper interaction. None of this is exotic engineering. What makes it hard is the clock. The HL7 specification targets a response time on the order of 500 milliseconds, and practical usability requires responses well within that range. Clinicians don't wait around if that window is missed. They click past the card, or ignore it entirely, and an inference pipeline that's technically correct but consistently slow is functionally the same as one that doesn't exist.
The hook library and which workflow triggers are production-ready
The specification defines several named hooks, but they are not equally mature, and treating them as interchangeable is a mistake engineers make early and pay for later.
patient-view fires the moment a clinician opens a patient's chart. It's the natural place to surface care gaps, pending alerts, or population-health recommendations, and it's among the most commonly implemented hooks across EHR platforms. order-sign fires just before a clinician submits an order, which makes it the natural home for final safety checks, prior-authorization alerts, or last-second documentation reminders. It's also broadly implemented, and arguably the more consequential hook, since it is at an actual decision point rather than an orientation moment. order-select fires earlier, when an order is chosen but not yet signed, and works well for formulary checks, coverage verification, or interaction flags. Epic's implementation supports it specifically for coverage-requirements discovery. The medication-prescribe hook is a legacy hook that has been superseded by order-select and order-sign for current implementations. Building anything new against it is wasted effort.
For a team shipping a first production service, the practical path is narrow: build and certify against patient-view and order-sign, since those are the two hooks most EHRs support reliably today, and treat order-select as a bonus wherever the target EHR confirms it. Hook choice also sets the latency budget. A patient-view hook fires while the clinician is still getting oriented, so there's a little more slack. An order-sign hook fires at the actual moment of commitment, so a card that meets the 500-millisecond target gets read, while one that doesn't gets ignored.
For teams building on agent frameworks like LangChain or CrewAI, or on custom tool-calling architectures, CDS Hooks effectively becomes the "when should the agent run" signal. It replaces a cron job or a polling loop with an event that's native to the clinical workflow itself, which is a meaningfully different design pattern than most agent frameworks are built around by default.
Epic's CDS Hooks implementation, its constraints, and its audit surface
Epic holds 42.3% of the acute care EHR market and 54.9% of hospital beds, with roughly 305 million patient records sitting inside its systems. That scale is why Epic certification functions as gate-one for most AI vendors building in this space: skip it, and a huge share of the addressable hospital market simply isn't reachable.
Epic's CDS Hooks implementation covers hooks relevant to coverage-requirements discovery, order-sign, and order-select. Cards render directly inside the order-entry workflow, right where a clinician is already looking, which is the entire point of the architecture working as intended.
The UI layer adds its own wrinkle. Cards show up inline inside the clinician's Epic workspace with no page transition and no separate window, and where an app embeds via SMART on FHIR launch changes how it behaves. Apps that launch inside Hyperdrive, Epic's modern web client, behave differently than those interacting with Hyperspace, the legacy desktop client, and the embedding constraints are not identical between the two. The embedding constraints are not identical between the two, and those differences affect how the service behaves in practice.
Prefetch design is where a lot of the real performance work happens. The hook request can carry FHIR resources the EHR already has in memory, and using that prefetch well cuts down on round-trips and keeps latency inside budget. A poorly designed prefetch does the opposite: it forces the service to go back for additional FHIR reads, and those extra reads eat directly into the 500-millisecond window that was already tight to begin with.
Oracle Health (Cerner) CDS Hooks implementation: availability status, certification path, and the CCL fallback
Oracle Health holds 22.9% of acute care hospitals and serves healthcare facilities worldwide. That's not a market any vendor can treat as secondary, but the integration path here comes with a caveat that Epic's doesn't.
As of early 2025, Oracle Health's CDS Hooks implementation was not generally available, and its availability appeared to be in transition, possibly varying site to site or instance to instance. That means engineers cannot assume CDS Hooks is simply "on" for a given customer. It has to be confirmed against the specific Millennium instance in question before anyone commits engineering time to building around it.
Where it is available, the registration of a CDS service endpoint happens at the Millennium instance level, with each customer site configuring which hooks are active and which services get called. Certification for third-party CDS services runs through Code Console, Oracle Health's developer certification program. Where the implementation is live, card rendering and context are well-formed. Certification timelines through Code Console run 8 to 16 weeks for a first-time submission, and vendors with an existing Code Console relationship can compress that considerably, a notably shorter range than the three-to-six-month path Epic typically requires. The tradeoff, then, is a faster certification process sitting on top of a less universally available implementation, which is exactly the kind of tradeoff engineers need to weigh before picking a platform to build against first.
Platform differences that change how engineers design the inference service itself
None of this is a detail to sort out after the model is built. Latency architecture has to be designed before model selection, not after, because the 500-millisecond specification target and the 500-millisecond specification target applies to the entire pipeline, not just the network hop. Model inference, FHIR reads, and response serialization all have to fit inside that same window, together.
Prefetch behavior diverges meaningfully between the two platforms. Epic's prefetch mechanism cuts down on additional FHIR round-trips when it's designed well, while on Oracle Health's Cerner platform, prefetch is governed by instance-level configuration that controls exactly which resources arrive in the hook payload. The contract is identical on paper. Platform-specific behavior causes a direct engineering consequence: a large LLM with multi-second inference times is not viable as a synchronous CDS Hooks responder on either platform, unless it's paired with caching, pre-computation, or a lightweight routing layer sitting in front of it to absorb the latency the model itself can't avoid.
The FHIR resource layer carries its own version of this problem. Common resource types, Patient, Encounter, Condition, MedicationRequest, Observation for labs, read consistently on both Epic and Oracle Health. But both platforms carry their own vendor-specific resource extensions, and a feature built against an Epic-specific extension will not simply degrade gracefully on Cerner. It will fail silently or throw an error, depending on how defensively the service was written. Any team building an inference service meant to run across both platforms needs an abstraction layer that treats the common resource set as the reliable core, and treats every vendor extension as something to detect and handle explicitly, rather than something to assume is there.

