Abridge Local Dev Loop
Overview
Local development workflow for Abridge clinical AI integrations. Uses a local HAPI FHIR server for EHR simulation, synthetic patient data from Synthea, and Abridge sandbox APIs. Never use real PHI in development.
Prerequisites
- Completed
abridge-install-auth setup
- Docker installed (for local FHIR server)
- Node.js 18+ with TypeScript
- Abridge sandbox credentials
Instructions
Step 1: Start Local FHIR Server
docker run -d --name hapi-fhir \
-p 8080:8080 \
-e hapi.fhir.default_encoding=json \
hapiproject/hapi:latest
curl -s http://localhost:8080/fhir/metadata | jq '.fhirVersion'
curl -X POST http://localhost:8080/fhir/Patient \
-H "Content-Type: application/fhir+json" \
-d '{"resourceType":"Patient","name":[{"given":["Jane"],"family":"Doe"}],"birthDate":"1985-03-15","gender":"female"}'
Step 2: Create Dev Environment Configuration
interface DevConfig {
abridge: { baseUrl: string; clientSecret: string; orgId: string };
fhir: { baseUrl: string };
fixtures: { transcriptsDir: string };
}
const devConfig: DevConfig = {
abridge: {
baseUrl: process.env.ABRIDGE_SANDBOX_URL || 'https://sandbox.api.abridge.com/v1',
clientSecret: process.env.ABRIDGE_CLIENT_SECRET!,
orgId: process.env.ABRIDGE_ORG_ID!,
},
fhir: { baseUrl: 'http://localhost:8080/fhir' },
fixtures: { transcriptsDir: './fixtures/transcripts' },
};
export default devConfig;
Step 3: Build Transcript Fixtures
export const CARDIOLOGY_VISIT = {
specialty: 'cardiology',
segments: [
{ speaker: 'provider', text: 'I see you are here for a blood pressure follow-up.', timestamp_ms: 0 },
{ speaker: 'patient', text: 'Yes, I have been taking the lisinopril like you prescribed.', timestamp_ms: 3500 },
{ speaker: 'provider', text: 'Your BP today is 138 over 85. Better, but still elevated. Let us increase lisinopril from 10 to 20mg.', timestamp_ms: 7200 },
{ speaker: 'patient', text: 'Okay. Should I be worried?', timestamp_ms: 15000 },
{ speaker: 'provider', text: 'Not at all. Come back in four weeks.', timestamp_ms: 18000 },
],
};
export const DERMATOLOGY_VISIT = {
specialty: 'dermatology',
segments: [
{ speaker: 'provider', text: 'What brings you in today?', timestamp_ms: 0 },
{ speaker: , : , : },
{ : , : , : },
{ : , : , : },
{ : , : , : },
],
};
Step 4: Dev Test Runner with Watch Mode
import devConfig from '../config/dev';
import { CARDIOLOGY_VISIT } from '../../fixtures/transcripts';
import axios from 'axios';
async function runDevEncounter() {
const api = axios.create({
baseURL: devConfig.abridge.baseUrl,
headers: {
'Authorization': `Bearer ${devConfig.abridge.clientSecret}`,
'X-Org-Id': devConfig.abridge.orgId,
},
});
const { data: session } = await api.post('/encounters/sessions', {
patient_id: 'demo-patient-001',
provider_id: 'demo-provider-001',
encounter_type: 'outpatient',
specialty: CARDIOLOGY_VISIT.specialty,
sandbox: true,
});
for (const seg of CARDIOLOGY_VISIT.segments) {
await api.post(`/encounters/sessions//transcript`, seg);
}
api.();
( i = ; i < ; i++) {
{ data } = api.();
(data. === ) {
.(.(data.., , ));
axios.(, {
: ,
: ,
: [{ : { : , : .(.(data..)).() } }],
});
.();
;
}
( (r, ));
}
}
().(.);
Step 5: Package Scripts
{
"scripts": {
"dev:fhir": "docker start hapi-fhir 2>/dev/null || docker run -d --name hapi-fhir -p 8080:8080 hapiproject/hapi:latest",
"dev:encounter": "tsx watch src/dev/test-encounter.ts",
"dev:all": "npm run dev:fhir && npm run dev:encounter",
"test:fixtures": "vitest run --grep 'fixture'"
}
}
Output
- Local HAPI FHIR R4 server on port 8080
- Synthetic patient data seeded
- Specialty-specific transcript fixtures
- Watch-mode dev loop with live note generation
Error Handling
| Error | Cause | Solution |
|---|
| Docker port conflict | Port 8080 in use | docker stop hapi-fhir && docker rm hapi-fhir |
| Sandbox rate limit | Too many test sessions | Wait 60s between test runs |
| FHIR validation error | Malformed resource | Validate against FHIR R4 schema |
Resources
Next Steps
For reusable SDK patterns, see abridge-sdk-patterns.