The short answer
Place Deedglass between your AI agents or Medplum Bots and your Medplum project. Deedglass serves as a governed FHIR proxy and Model Context Protocol gateway.
Before an action runs, Deedglass checks tool arguments against your security policy. Safe reads proceed immediately, sensitive patient mutations pause for human authorization in the Console or Slack3, and every executed write is verified against the version Medplum committed in PostgreSQL rather than trusting HTTP response codes3.
Deedglass
The server said “saved”. Deedglass looked.
Deedglass reads it back
Why FHIR APIs need post-write checks
Autonomous clinical agents, ambient scribes, and intake bots interact with electronic health record backends by sending HTTP POST, PUT, and PATCH requests to FHIR endpoints. Standard gateway architectures assume that receiving a 201 Created or 200 OK status means the record stored matches what the agent transmitted.
In practice, healthcare APIs frequently transform or truncate payloads during ingestion:
- AccessPolicy field redaction: In Medplum, an AccessPolicy configured with
readonlyFieldspermits the write to succeed but discards restricted fields without raising an error code. An AI scribe sending clinical notes will receive a201 Createdwhile the actual patient note was silently dropped. - Version drift: Medplum generates a server-controlled
versionIdandmeta.authorfor each resource version1. Agents cannot predict or verify the version identifier before the database commits. - Partial batch application: If an agent dispatches a bundle without atomic transaction support, certain entries succeed while others fail, leaving clinical charts in a partial state.
- Lack of verifiable audit trails: Traditional API gateways log request URLs and response codes, but provide no cryptographic linkage between an agent’s reasoning session and the row committed in PostgreSQL.
Deedglass solves this by intercepting requests before execution and reading back the exact stored version after execution.
Connecting Medplum through the FHIR connector
To connect an agent to Medplum through Deedglass, create a ClientApplication in your Medplum project with an AccessPolicy scoped to the resources the agent requires.
Configure Deedglass’s FHIR connector in your connector settings (connectors.yaml):
Code A settings file: the rules a tool reads before it acts.
version: "connector/v1"
connectors:
- id: "medplum-ehr"
type: "fhir"
base_url: "https://api.medplum.com/fhir/R4"
auth:
kind: "bearer"
token: "${MEDPLUM_ACCESS_TOKEN}"
allowed_resource_types:
- "Patient"
- "Observation"
- "Condition"
- "Encounter"
interactions:
- "read"
- "search"
- "create"
- "update"
witness:
enabled: true
server: "medplum"
author: "ClientApplication/c8a4128f-9e20-4d51-b01a-7b3c20261030"
When running Medplum on your own PostgreSQL infrastructure, enabling witness allows Deedglass to read the underlying write-ahead log and verify row changes directly3. On managed Medplum cloud instances, Deedglass operates at the Checked level via HTTP read-back.
Configuring approval policies for clinical resources
Policy rules dictate which FHIR interactions proceed automatically and which require clinical human-in-the-loop oversight.
Here is an example policy configuration (policy.yaml):
Code A settings file: the rules a tool reads before it acts.
version: "policy/v1"
name: "clinical-agent-policy"
defaults:
decision: "deny"
reason: "No rule permits this clinical write."
rules:
# Analytical reads proceed immediately
- id: "allow-patient-reads"
match:
connector: "medplum-ehr"
interaction: "read"
action: "allow"
# Routine vitals observation creates proceed with automated verification
- id: "allow-vitals-observation"
match:
connector: "medplum-ehr"
interaction: "create"
resource_type: "Observation"
action: "allow"
# Diagnostic condition mutations require physician approval
- id: "require-approval-for-diagnoses"
match:
connector: "medplum-ehr"
interaction: "create"
resource_type: "Condition"
action: "require_approval"
approval:
channel: "slack-clinical-review"
timeout: "45m"
required: 1
# Deletions are strictly prohibited for autonomous agents
- id: "block-deletions"
match:
connector: "medplum-ehr"
interaction: "delete"
action: "deny"
reason: "Clinical records cannot be deleted by autonomous agents."
When an agent issues a POST /Condition, Deedglass halts the call, generates a structured approval card with the clinical context and proposed coding, and sends it to the configured review channel3. The reviewing clinician can inspect the diagnostic code, status flag, and encounter reference before deciding whether to permit the write.
If the reviewer denies the request or the approval window expires, Deedglass halts the transaction and returns a structured rejection payload to the agent runtime. The autonomous agent can then acknowledge the decision or seek guidance without corrupting patient records.
How read-back verification catches dropped fields
Once a write executes, Deedglass performs an immediate read-back check (the Checked level)3:
- Deedglass reads the
ETagheader from Medplum’s HTTP response to retrieve the assigned version identifier. - It fetches the resource at that exact version URL (
/fhir/R4/<Type>/<id>/_history/<versionId>). - It performs a field-by-field diff between what the agent sent and what Medplum stored.
- Server-assigned metadata fields (
meta.versionId,meta.lastUpdated, and system tags) are normalized. - If any field the agent set is missing or altered, the action is marked as Doesn’t match3.
In automated testing against Medplum, an agent attempted to write a patient observation with a private clinical note while under an AccessPolicy that marked notes as read-only. Medplum returned HTTP 201 Created, but Deedglass flagged a Doesn’t match result because the stored version held note: null3. The agent’s logs claimed success, but Deedglass surfaced the discrepancy immediately.
Change-log verification with PostgreSQL history tables
For self-hosted Medplum instances, Deedglass verifies the database commit directly by inspecting PostgreSQL’s logical replication stream3.
Medplum stores each historical resource version as full JSON text inside dedicated per-type history tables in PostgreSQL, such as "Observation_History" and "Condition_History"1.
When an action commits:
- The replication reader inspects the write-ahead log for the transaction.
- It extracts the JSON payload from the
contentcolumn of the history table1. - It compares the database delta against the agent’s intent.
- It verifies that the row author matches the expected
ClientApplicationidentity1.
If a background database trigger or manual intervention altered additional patient tables during the transaction, Deedglass detects the divergence and flags the action record.
Offline verification with Ed25519 audit chains
Every governed clinical action produces a signed action record. Each record is sealed using Ed25519 cryptographic signatures over RFC 8785 canonical JSON, and hash-linked to prior records to form a hash-linked audit trail3.
Hospital security teams and clinical safety officers can inspect these records offline without requiring network access or database credentials:
Code Commands typed in a terminal. The text around it says what happens.
deedglass verify ./medplum-audit.json --public-keys ./hospital-keys.json
The verification command checks cryptographic signatures, sequence counters, and row deltas offline3. This means clinical chart changes can be audited years later, regardless of vendor infrastructure changes.
For related patterns in healthcare systems and agent safety, see AI scribes and EHR write approvals, AI agents writing to patient records, and FHIR terminology in our glossary; the human-in-the-loop approval guide details multi-reviewer workflows. To see what the agents configured on your machine can change, paste the config into the check page or run npx deedglass scan (how the grade works); to try approval rules in your browser, open the playground.
Written with AI assistance and checked against our claims register.