Build an AI scribe in a weekend (without a HIPAA lawyer)

A step-by-step build: audio → transcript → AI draft → clinician signs → FHIR DocumentReference → export → audit. You write the workflow; the clinical data layer handles the regulated parts.

An AI medical scribe is the perfect first build in healthcare: clinicians feel the pain daily, the demo lands in thirty seconds, and the workflow is genuinely vibe-codeable. What stops most weekend builds isn't the AI — it's the question that arrives on Monday: "where does the note live, and is it compliant?" This walks the whole build with that question already answered.

Can you build an AI medical scribe in a weekend?

Yes. The workflow — record a visit, transcribe it, draft a SOAP note, let the clinician edit and sign — is a weekend project for one developer. The hard part is never the AI; it is storing the note as durable clinical data with provenance, audit, encryption, and a BAA. Put that on a clinical backend and the weekend is real.

What the build actually is

An AI scribe is a pipeline, not a model. Five steps, each small:

  • Capture the visit audio in the browser.
  • Transcribe it to text with a speech-to-text model.
  • Draft a structured note (SOAP/DAP) with an LLM.
  • Sign — the clinician edits the draft and attests, which records who authored what and when (provenance).
  • Store the signed note as a FHIR DocumentReference, exportable and audited.

Steps 1–3 are where you vibe-code freely. Steps 4–5 are the regulated data layer — the part you should not hand-roll. That split is the whole point of bonfireDB: the open-source clinical backend that owns the data layer so your weekend stays a weekend.

The honest line: the demo is a weekend. The compliant demo is also a weekend — but only if the storage, provenance, audit, and BAA come from infrastructure built for PHI, not from code an AI scaffolded that looks done.

Step 1 — Capture the audio

This is plain web. Record with MediaRecorder in the browser, hand the resulting blob to your scribe pipeline. No PHI touches anything regulated yet — it's an audio file in memory.

const recorder = new MediaRecorder(stream);
const chunks: Blob[] = [];
recorder.ondataavailable = (e) => chunks.push(e.data);
recorder.onstop = async () => {
  const audio = new Blob(chunks, { type: "audio/webm" });
  await draftNoteFromAudio(audio, patientId);
};
recorder.start();

Vibe-code this entire step. It's UI and browser APIs — exactly what AI tools are great at.

Step 2 — Transcribe

Send the audio to a speech-to-text model. One thing matters here and it's not the code: the transcription vendor is now processing PHI, so it must be under a Business Associate Agreement. A BAA on your coding tool does not cover the model your running app calls — each data-layer vendor needs its own. Route the call through your backend so the model endpoint and key live server-side, never in the browser.

// server-side — the transcript is PHI from here on
const transcript = await clinical.transcribe(audio);

Step 3 — Draft the note with AI

Feed the transcript to an LLM with a SOAP/DAP template and get a structured draft back. This is a draft, not a decision — it never becomes part of the record until a clinician signs it. Keep the prompt and the model call server-side, and use a model vendor that has signed a BAA.

const draft = await clinical.notes.create({
  patientId,
  type: "progress-note",
  status: "draft",
  text: await clinical.agent.draftSOAP(transcript),
});

The note exists now, but as a draft: not signed, not part of the legal record, fully editable. That distinction is enforced by the data layer, not by a boolean you remembered to check. When you want the draft grounded in the patient's history, pull that context through bonfire's agent layer (MCP + clean projections) rather than dumping the whole chart into the prompt — agents working over raw FHIR cap out around 50% on real tasks (FHIR-AgentBench), so a curated projection is the part designed to do better than the raw resource graph.

Step 4 — Clinician edits and signs (provenance)

Render the draft, let the clinician fix what the AI got wrong, then capture the signature. Signing is the moment that matters: it freezes the text, stamps the author and timestamp, and writes a FHIR Provenance resource so the record can always answer "who wrote this, who signed it, and was AI involved?"

await clinical.notes.sign(draft.id, {
  signedBy: clinician.id,
  // provenance is recorded automatically:
  // author, timestamp, and that an AI draft was used
});

You did not build an audit table, a signature schema, or an amendment workflow. Provenance is a first-class primitive — because in a clinical record, who said what when is not metadata, it's the point.

Step 5 — Store as a FHIR DocumentReference, then export

Store a SOAP note as a FHIR DocumentReference. That's the R4-correct home for a clinical document: it carries the text, the type, the author, the status, and links to the encounter and patient. Because it's FHIR underneath, the note is portable from the first day — you can export a patient's whole chart as a standards-compliant bundle without a migration project.

// the signed note is already a DocumentReference under the hood
const bundle = await clinical.fhir.export(patientId);
// → a FHIR R4 Bundle: Patient, Encounter,
//   DocumentReference (the note), Provenance, Observation…

For coded data alongside the note — vitals, a screener result — use the matching primitives so they land as proper FHIR resources, not free text:

await clinical.observations.record({
  patientId, code: "8867-4", value: 72, unit: "/min", // heart rate
});
await clinical.assessments.record("PHQ-9", { patientId, score: 11 });

SNOMED CT is free for US use through the NLM, so coding your observations and problems doesn't add a licensing bill. On the read side, your UI queries the same store reactively:

const { data: notes } = useClinicalQuery(
  clinical.notes.list, { patientId }
);

Step 6 — Audit comes free

Every read and write above is logged automatically — who accessed which patient's data, when, from where. You don't write the audit log; you query it when a compliance review asks. Same for access control: "only this patient's clinician can read this note" is enforced server-side by the data layer, not by CRUD you scaffolded and hoped covered every route.

Where this gets you — and what's honest about it

By Sunday night you have a working AI scribe whose notes are real FHIR documents, signed with provenance, encrypted, audited, and exportable. The parts you vibe-coded (capture, draft UI, edit screen) are yours to own; the parts you didn't (storage, signing, audit, FHIR, BAA) are the parts you'd least want to hand-roll under a deadline.

Two honest caveats. First, bonfireDB is pre-launch — early access, presented as product vision, not a track record. Second, you are not the only option: AWS HealthLake is a real FHIR store, and Medblocks already pioneered the code-first, AI-buildable FHIR reframe. bonfire's bet is narrower and opinionated — agent-native primitives, a BAA from day one, and an OSS core sized for a pre-seed indie team building exactly this scribe. Pick the tool that fits; just don't let the data layer be the thing you improvise.

Want the deeper version? See the Scribe Fire Starter for the full starter template, how bonfire works end to end, and the AI scribe backend pillar for the architecture behind every step above.

Keep reading

TL;DR

  • An AI scribe is a 5-step pipeline: capture → transcribe → AI draft → clinician signs → store as FHIR DocumentReference. Steps 1–3 are vibe-codeable; 4–5 are the regulated data layer.
  • Signing records provenance (author, timestamp, AI-assisted) — first-class, not a table you build.
  • Notes stored as FHIR R4 are portable and exportable from day one via clinical.fhir.export(patientId).
  • Audit and per-patient access control are enforced by the data layer, not scaffolded CRUD.
  • Every PHI vendor (transcription, the LLM, storage) needs its own BAA — your coding tool's BAA doesn't cover them.
  • Honest framing: bonfireDB is early access; HealthLake and Medblocks are real alternatives. Compete on fit, not on a vacuum.
FAQ

Frequently asked questions

Can you really build an AI medical scribe in a weekend?

Yes. The workflow — record a visit, transcribe it, draft a SOAP note, let the clinician edit and sign — is a weekend project for one developer. The hard part is never the AI; it is storing the note as durable clinical data with provenance, audit, encryption, and a BAA. Put that on a clinical backend and the weekend stays a weekend.

What are the steps to build an AI scribe?

Five steps: capture the visit audio in the browser, transcribe it with a speech-to-text model, draft a structured SOAP/DAP note with an LLM, have the clinician edit and sign it (which records provenance), and store the signed note as a FHIR DocumentReference that is exportable and audited. Steps one through three you vibe-code; four and five are the regulated data layer.

Which parts of an AI scribe are safe to vibe-code and which are not?

Capture, transcription wiring, and the draft and edit UI are safe to vibe-code — they are browser and prompt code AI tools are great at. Storage, signing, provenance, the audit trail, per-patient access control, and FHIR export are the regulated data layer; put those on infrastructure built for PHI rather than code an AI scaffolded that only looks done.

Where is an AI scribe note stored, and can I export it?

The signed SOAP note is stored as a FHIR R4 DocumentReference — the correct home for a clinical document, carrying the text, type, author, status, and links to the encounter and patient. Because it is FHIR underneath, the note is portable from day one: you can export a patient's whole chart as a standards-compliant Bundle without a migration project.

Do I need a HIPAA lawyer to build a scribe, and which vendors need a BAA?

You can build the workflow without one if the data layer handles the regulated parts. Every vendor that processes PHI needs its own signed BAA: the transcription API, the LLM, the database, and the storage. Default coding-tool tiers do not cover PHI, though some enterprise tiers do sign a BAA — and that BAA still covers the tool, not the model your running app calls.

Is bonfireDB the only option for a scribe backend?

No, and it should not be pitched that way. AWS HealthLake is a real FHIR store, and Medblocks pioneered the code-first, AI-buildable FHIR reframe. bonfireDB's bet is narrower: agent-native primitives, a BAA from day one via the managed tier, and an open-source core sized for a pre-seed indie team. It is pre-launch and early access. Pick the tool that fits.

You build the app. Bonfire is the clinical data layer underneath.

bonfireDB is the open-source clinical backend for the AI scribe you're building — FHIR underneath, provenance and audit built in, BAA available via the managed tier. In early access.