P PraxisNotes
Page 01 · Before · the honest audit

Before we build anything, we start from the truth.

We wrote today's PraxisNotes, so this is our own audit — not a competitor takedown. We read the codebase line by line, mined the live app, and mapped one clinic's documentation pipeline against the industry data and the federal audit record. The current product is genuinely good at the job it was built for: a solo RBT generating a note. A 100+ RBT clinic with a QA department needs something structurally different — and the honest way to earn that is to say exactly where the time goes today.

Our own code

64 database migrations, every prompt file, the credits engine and the auth schema — read directly.

The live app

The shipped bundle at app.praxisnotes.com — the exact form fields, enums, and generation flow users touch.

The industry record

Payer documentation rules, BACB staffing data, and the HHS-OIG state audits — every number is sourced.

This ports into the new product

What today's PraxisNotes gets right

None of this gets thrown away. The domain vocabulary, the seeded catalogs, and the human-in-the-loop editing are real value that RBTs already know. The new PraxisNotes keeps all of it — and builds the team layer on top.

The structured session form

It speaks the exact clinical language RBTs and payers expect. That structure is what makes a note QA-checkable — we port it verbatim as the schema the agent fills.

23 location options ABC cards · antecedent · function · behaviors · interventions function: attention / escape / sensory / tangible replacement cards · 22 prompt types teaching + prompting procedures client response: expected / exceeded / delayed progress % valuation: fair / good / poor reinforcers observations
The seeded clinical catalogs

A real, curated ABA corpus — global entries plus org-custom ones, with inline "create custom" from any picker. This is domain value that took years to assemble.

627antecedents
546reinforcers
273replacement programs
181behaviors
133interventions
22prompt types
Streamed generation, with a fidelity dial

The note streams into the editor token by token — good perceived speed. And the live app already ships a smart instinct: a "how closely should the AI stick to your session data?" control, anchored to the safest option by default. We keep the concept and make it clinic policy.

Verbatim from the shipped app:

How closely should the AI stick to your session data?
Strict · default
"Only what's in the data. Safest for insurance audits."
Balanced
"Reads as a clinical narrative. Numbers stay from input only."
Elaborate
"Fuller narrative. Always review before signing."
Edit with a preview

Ten one-tap edit actions plus free-form custom instructions — every transform lands as a preview you Accept or Cancel. That accept/cancel gate is exactly the draft-review primitive we build on.

Re-generate Improve it Shorten it Clean up notes Make it more descriptive Make it more detailed Simplify it Fix any mistakes Sound fluent Make it objective
A Spanish review tab

The editor translates the finished English note to Spanish for review, and translates back on save, so the stored record stays English. A real acknowledgment that the RBT workforce is heavily bilingual — a strength we build much further with capture in any language.

Pricing people understand

Per-note credits with a monthly allowance — 10 free, then 30 / 60 / 200 by plan — backed by a transaction ledger. A clean, legible unit of value. The clinic model changes who pays, not the idea that a note is a countable thing.

The six structural limits

These aren't bugs. They're what a single-user note generator is, by design — and each is exactly what a 100-RBT clinic runs into on day one. The roadmap over the years promised more than the single-user architecture could ever deliver; naming that honestly is the first step to fixing it.

a
One user, one world

Every account is a personal island. On signup the app quietly creates a one-person "organization"; the member, invitation, and role tables exist but nothing wires them up. There is no invite flow and no RBT / BCBA / QA role anywhere in the schema — the seeded role list is literally empty.

A clinic can't even represent itself. There is no shared caseload, no supervisor view, no QA queue — because there is no "us," only many separate "me"s.

b
A note is one text box

The generated note is a single notes text column that gets overwritten. No versions, no draft → submitted → approved status machine, no sign-off, no audit trail. "Draft vs completed" is computed one way only: is the column empty or not.

Regenerating destroys the prior text. There is no record of who wrote, edited, or approved what — the exact thing an insurance audit demands.

the client's core pain
c
The rules live inside the engine

Compliance requirements are hardcoded prompt text. The generation prompt is one template literal that names exactly one CPT code — 97153 — with the medical-necessity language baked in as string constants. There is no payer table, no per-clinic requirement record, no data-driven rule.

So when a payer changes a documentation rule — and they do, continually — the only way to comply is to edit a .ts file, rebuild, and deploy, for every user at once. This is confirmed in the code, and it is precisely the pain the clinic described: requirements move faster than the engine can be redeployed.

Today, a rule change is a code deploy
payer updates a note requirement
  ↓
edit generate-notes-prompt.ts
  ↓
rebuild → redeploy the whole app
  ↓
ships to every user, 97153 only
There is an early rules primitive — here's the honest nuance

The app does ship a "note generation rules" list where a user can add personal stylistic preferences, with the note that "payer-compliance rules always win on conflict." But it is hard-limited to CPT 97153 in the UI, the payer-compliance rules themselves stay platform-managed and invisible, and there is no clinic-level layer at all. It's the seed of the right idea — we out-build it into versioned, clinic-editable rule packs, not invent it.

d
The form asks less than the note needs

The generation prompt instructs the model to include trial counts and prompting levels — "3 out of 5 trials correct," "full physical, partial physical, model, verbal, gestural" — but the form never collects them. The ABC entry's function field is captured and then never even passed to the prompt.

Asked for numbers it was never given, the model fills the gap — inventing plausible clinical facts in a legal record. It's a fabrication risk QA catches immediately.

e
Typed-only, English-first

There is no voice capture, no dictation, no transcription anywhere — verified across the whole bundle — and no native mobile app; it's responsive web only. Spanish is handled as post-hoc translation of a finished English note, not as capture.

A bilingual RBT still types a long English form on a phone after the session. The highest-friction step is untouched.

f
The pipeline ends at a download

The product's last step is exporting the note — a Markdown (or PDF) file. Everything after that — QA review, entry into Office Puzzle, the claim itself — happens outside the product, by hand. There is no reviewer, no approval gate, and no integration out; the terminal action is copy-paste into whatever the clinic bills from.

The clinic's entire QA-and-billing operation lives in the gap the product leaves open. That gap is where the time — and the audit risk — accumulates.

The clinic's week, today

Zoom out from one note to the whole documentation pipeline at 100+ RBTs. The product does its job in the first two steps; the rest is a human relay against three clocks — and every handoff is a queue, and every queue is payroll.

Session ends
stacked 3–7pm, back-to-back
Evening typing
the long form, from memory
15–30 min / note
Self-review
RBT marks it "completed"
Human QA queue
2–6 QA FTEs / 100 RBTs
days of latency
Fails a payer rule
the common case, not the exception
80% fail ≥1
Rework round-trip
lands mid-session, 3–7pm
re-review → re-fix
Manual re-entry
retyped into Office Puzzle
no API · by hand

At 100 RBTs that's roughly 830–1,250 session notes a week (~3,600–5,400 a month) moving through this relay — and 7–15 hours of documentation a week per RBT, much of it after hours and unpaid. That unpaid-time pattern is real enough to have drawn an FLSA class-action investigation into ABA agencies.

And three clocks are running the whole time
Sign within 2 business days

Florida's recordkeeping rule (59G-1.054) requires each record signed and dated within two business days of service.

24–72h to complete

Industry and internal norms: notes finalized within 24 hours; anything past 72 hours draws audit scrutiny.

90–180 day timely filing

Once a payer's filing window closes, the money is gone — no appeal. Every day QA adds erodes the submission target.

The punchline: this relay has no economy of scale.

Every new cohort of RBTs adds notes at a constant rate, so it adds QA payroll at a constant rate — the marginal QA cost per RBT never drops. Worse, the people can't get more senior: 65–103% annual RBT turnover keeps the workforce perpetually junior, so error rates stay high while headcount climbs. And the one role that could absorb review — the BCBA — is the scarcest resource and already saturated.

2.8:1
218,757 RBTs to 77,415 BCBAs nationally — the supervisor is the bottleneck.
72%
of BCBAs report medium-to-high burnout — before any note QA is added to their plate.
5%
of an RBT's hours must be BCBA-supervised every month — that time is already spoken for.
How the 2–6 QA FTE figure is built

100 RBTs at ~25 billable hours each ≈ 2,500 session-hours a week ⇒ ~830–1,250 notes a week. At a conservative 5–10 minutes of first-pass human review per note against a ~15-element payer checklist, that's ~70–210 review-hours a week — roughly 2–6 full-time QA reviewers, before rework. With ~80% of notes failing at least one requirement on first pass, each failure adds an RBT correction plus a re-review touch, plausibly 30–50% more QA time. Non-certified QA reps run $45–60K; BCBA-level QA runs ~$72–90K — so the layer costs roughly $120K–$400K a year in salary alone, and it scales linearly.

Why sampling can't survive an audit

The exposure

This isn't a hypothetical risk — it's an active federal enforcement wave, and the documentation is the thing that fails. HHS-OIG has been auditing state Medicaid ABA programs one by one, and the sample error rates are near-total.

$77.8M
Colorado

improper payments (2026 report); 93 of 100 sampled months failed a documentation check.

$56M
Indiana

improper payments; in 95 of 100 sampled months the session notes did not meet documentation requirements.

$18.5M+
Wisconsin

confirmed improper (plus $94.3M potentially); notes often failed to support the CPT codes, units, or dates billed.

$45.6M
Maine

improper Medicaid autism-services payments — one more state in an expanding OIG series.

What the auditors keep finding
missing notes missing / invalid signatures — incl. pasted signature images notes signed before the session ended cloned / verbatim-duplicated notes units unsupported — nap time billed as therapy

And this isn't a lightning strike: 35–40% of ABA providers face a documentation or billing audit within their first five years. Against 100/100-style sample error rates, the industry's standard defense — sampling 10–20% of notes — is demonstrably not enough. If the auditor pulls the 85% you never reviewed, the sample tells you nothing.

10–20%
the sampling standard
vs. ~100% of notes that need to be defensible

And here is the structural point: nothing in a single-text-column note store can even answer an auditor.

No versions, no signature record, no "who reviewed this and when." The note lifecycle that survives an OIG audit is exactly what the current architecture can't hold — that's the whole of the compliance page →

None of this is a criticism of the people. It's the ceiling of the architecture.

The RBTs type carefully. The reviewers catch real errors. The billers work late. Everyone is doing the job well — inside a system built for one person to write one note. Raise the ceiling, and the same people get their evenings back and the claims go clean. That's what the next page is.

See what replaces it