Engineering
Voice perio charting that lands in the chart
October 8, 2026
Periodontal charting is the one part of a dental visit where the clinician's hands are fully committed, the eyes are on a probe tip, and the data has to be recorded one millimetre at a time. This is how CareNotes turns a spoken "three two three" into six-site measurements in the practice's chart, from the acoustic front end to the exact bytes the practice management system accepts.
A full-mouth periodontal exam records up to 192 probing depths (32 teeth × 6 sites), plus bleeding on probing at each site, gingival margin, furcation involvement, and mobility. Those numbers drive staging and grading under the 2017 World Workshop classification [1], so they have to be complete and they have to be right. The conventional workflow needs a second person: one probes and calls out, the other types. Without an assistant, the hygienist probes a tooth, sets the probe down, de-gloves or hovers over a keyboard, types three numbers, and picks the probe back up. Probing itself is only reproducible to about a millimetre under the best conditions [2]; every interruption adds a chance to lose the site.
Voice charting removes the second person. In March we shipped it on iPhone with direct upload to Open Dental and Dentrix Ascend. In October it arrived in the browser, inside Visits, and gained writeback to practices connected through the CareNotes Agent (Dentrix, Eaglesoft, PracticeWorks, SoftDent, and EXACT). The clinician speaks, hears a short confirmation tone, and the chart advances to the next tooth. Nothing is typed. This post is about what happens between the beep and the chart.
The interaction loop
The design goal was that a hygienist should be able to chart with eyes on the probe and never look at a screen. That rules out anything that needs a visual confirmation, and it forces the audio feedback to carry the state.
- Listen. The microphone is live for the whole exam. Speech is transcribed continuously.
- Parse. Each utterance is cleaned, then matched against a grammar of charting commands. "Three two three" is a probing depth. "Bleeding fourteen" is a flag. "Jump nineteen lingual" moves the cursor.
- Apply. The command mutates the chart state. A probing depth fills the three sites of the current tooth and surface.
- Confirm. A short tone plays, and the tone carries the state. A probing depth gets a quick two-note chime; a recession, furcation, or mobility finding gets a rising glide; a command that was not understood gets a flat buzz. The tones are synthesized in code rather than shipped as audio files, so the Chrome extension and Visits sound identical.
- Advance. The cursor moves to the next tooth along the charting path, skipping any tooth marked missing.
Step 5 encodes a convention most hygienists already follow. The charting sequence is a single ordered list of 64 (tooth, surface) stops: upper facial from 1 to 16, back along the upper lingual from 16 to 1, lower facial from 32 to 17, and back along the lower lingual from 17 to 32.
There is one subtlety that is invisible in a keyboard workflow and essential in a voice one. The clinician reads sites in the order the probe meets them, which is left-to-right from the operator's view. On the upper facial pass that is distal, mid, mesial for the right side and the reverse on the left. On the return pass along the lingual the direction flips. The chart model knows which passes run right-to-left and reverses the three digits on those, so "four two two" spoken on the lingual of tooth 14 stores as 2, 2, 4 in anatomical order.
Without this the chart is internally consistent and anatomically wrong, which is worse than a missing value because nothing flags it.
Making speech-to-text safe for numbers
General-purpose speech recognizers are trained on conversational text. They are poor at a stream of isolated digits and dental jargon, and they are confidently wrong in characteristic ways. "Bleeding" becomes "leading", "cleaning", or "pleading". "Jump" becomes "John". "Lingual" becomes "lingo". A digit string arrives as "three to three" or "332." with a trailing period added by the recognizer's punctuation model. If any of that reaches the command grammar unrepaired, the command fails and the hygienist has to repeat it, which breaks the rhythm the whole feature depends on.
So the raw transcript goes through a four-stage deterministic pipeline before any parsing. Deterministic matters here: the repairs have to be fast enough to run on every utterance and predictable enough that a clinician can learn them.
text = strip_punctuation(raw) // "332." → "332"
text = words_to_digits(text) // 1. "twenty one" → "21", "two to three" → "223"
text = fix_known_confusions(text) // 2. observed recognizer slips → command words
text = phonetic_repair(text) // 3. unknown words → nearest dental term
text = normalize_sites(text) // 4. mesial/distal/central → front/back/middle
Stage 1 is a lookup table, compound numbers first ("twenty-one" before "one") so that partial matches cannot corrupt a value. Stage 2 is a list of observed confusions collected from real sessions, "leading" for bleeding, a first name for "jump", and a few dozen more. It is unglamorous and it is the single highest-yield component in the pipeline, because the same recognizer makes the same mistakes on the same phonemes.
Stage 3 handles the words Stage 2 has not seen. Each dental term has a phonetic key built the way Soundex and Metaphone build theirs [3]: strip vowels, collapse doubled consonants, keep a short consonant skeleton. An unknown word is matched to a term if its key is within a small Levenshtein distance [4] of one of the term's known "sounds like" keys (the standard dynamic-programming edit distance [6]), or if it begins with a known prefix and is not much longer than it. The dictionary covers the handful of terms that matter in a perio exam: mesial, distal, lingual, facial, buccal, bleeding.
The repair is context-aware. It only fires when the utterance already looks like a charting command, so "cleaning" in free speech is left alone and "cleaning fourteen" becomes "bleeding fourteen". Stage 4 maps the anatomical site names a clinician might use (mesial, distal, central) onto the positional names the grammar uses (front, back, middle).
Two-tier parsing
After cleanup the text hits a local parser: a small grammar, one rule per command type, that runs in microseconds and never leaves the browser or the phone. The rules cover probing depths, jump and go-to, bleeding and its reset, missing and un-missing teeth, repeat, recession, furcation, mobility, and the control words (undo, redo, save). Each rule accepts the natural variants a clinician actually says, "recession 2 on 14", "recession 2mm tooth 14", "gr 3 on number 12", without a model in the loop.
The numeric rule is stricter than it looks. A probing depth is a run of digits 1–9, grouped in threes; "44455522" yields two measurements and drops the trailing "22". A one- or two-digit string is explicitly rejected as incomplete rather than passed on, because the most expensive misparse we found was "two two" being interpreted as "tooth 22" and jumping the cursor across the arch.
Only when the local grammar fails does the parser fall back to a language model. The model is given the current tooth as context and asked for structured JSON in a fixed schema, with rules such as "if the input is only digits, it is a probing depth" and "return one command per tooth". A circuit breaker caps model calls per minute and times each one out; if the breaker trips, the command is rejected with the error tone and the hygienist repeats it. Most of an exam is digit strings, and digit strings never reach the model.
What the PMS actually receives
This is where the three integration paths diverge, and it is the part that took the most careful reading of vendor documentation.
Open Dental
Open Dental models an exam as a perio exam record plus a set of perio measurement rows, one per tooth per measurement type [5]. The types are probing depth, gingival margin, furcation, mobility, and bleeding, and each row carries six site values in Open Dental's own site order. CareNotes creates the exam for the day and posts measurement rows for each tooth and type that has data, updating rows in place when a site is re-probed. Before it does, it checks whether an exam already exists for that patient on that date, because a second exam on the same day is a common source of confusion in the Open Dental UI.
Dentrix Ascend
Ascend is visit-centric. The app opens an exam, then streams the probe measurements into it, omitting positions that were never probed rather than sending zeros. The progress of that stream is what drives the upload bar in the app.
The Agent path
For on-premise systems the bridge accepts one whole-mouth exam at a time, with each measurement type packed as a flat list in a fixed per-tooth site order. The builder walks every tooth, skips the ones marked missing, includes any tooth with a measured site or a recession, furcation, or mobility finding, fills unmeasured sites on an included tooth with zeros, and clamps every value to the range the contract allows. Getting the facial and lingual passes into the bridge's single site order is where the charting-path reversal from earlier pays for itself: the chart already holds anatomical order, so the packer is a straight read.
Recession is expressed as a signed gingival margin in this contract, so "recession 2 on 14" becomes a negative margin at each site, and a three-point "3,2,3" lands on the same mesial, mid, and distal sites the Open Dental upload uses so the two paths agree. The request is then queued and the phone polls the job ticket until the Agent reports success, exactly as it does for clinical notes.
Two vendor differences had to be handled explicitly. Dentrix (classic) derives clinical attachment level from pocket depth plus gingival margin using its own default script, so the exam is tagged for that behaviour only when the target is Dentrix. And a negative margin is valid on Dentrix but rejected by Eaglesoft, so for the other Agent systems the gingival margin is sent as a non-negative value and the PMS derives attachment loss its own way. When the bridge reports that an exam already exists for the patient today, the app says so in plain words instead of surfacing the raw error.
From the browser to the chart
The October release moved the charting surface into Visits, the browser workspace, so a hygienist can chart from the operatory computer with a room microphone instead of a phone. The parsing pipeline above runs in JavaScript in the browser; it is the same grammar and the same phonetic tables.
The handoff to the practice management system is where the architecture is deliberately conservative. The browser does not hold PMS credentials. When the exam is done, it writes the completed chart to the practice's in-region database, tagged with the PMS it belongs to and the practice identifiers. The clinician's phone, which already owns the Open Dental key, the Ascend organization, or the Agent location, picks the document up and performs the upload through the same code path as a chart taken on the phone. The browser shows the writeback status as it lands. One set of credentials, one upload implementation, two front ends.
Where this is going
The measurements are only as good as the recognizer's handling of digits, and that is improving fastest of all. The voice profile work means the phone can tell the hygienist's voice from the patient's, which matters when a patient answers "three?" mid-exam. Curve Dental perio upload is not available yet; Curve practices get notes and schedule today. The browser chart is part of Visits, which is in beta.
The clinical background, including how to structure a perio note from the chart, is in the perio documentation playbook. The feature page is here.
References
- Tonetti MS, Greenwell H, Kornman KS. Staging and grading of periodontitis: Framework and proposal of a new classification and case definition. Journal of Periodontology. 2018;89(S1):S159-S172. doi:10.1002/JPER.18-0006
- Listgarten MA. Periodontal probing: what does it mean? Journal of Clinical Periodontology. 1980;7(3):165-176. doi:10.1111/j.1600-051X.1980.tb01960.x
- Philips L. Hanging on the Metaphone. Computer Language. 1990;7(12):39-44.
- Levenshtein VI. Binary codes capable of correcting deletions, insertions, and reversals. Soviet Physics Doklady. 1966;10(8):707-710.
- Open Dental Software. Open Dental API Specification: PerioExams and PerioMeasures. opendental.com/site/apispecification.html
- Jurafsky D, Martin JH. Speech and Language Processing, 3rd ed. draft, ch. 2 (edit distance) and ch. 16 (automatic speech recognition). web.stanford.edu/~jurafsky/slp3