The AI-native operating system for a dental practice — asked work in chat, unprompted work in the inbox, every write on the same governed rails.

What it is
Canopy is the company. Vella is what staff actually use — a coordinator talks to her in chat, the inbox holds the work she started on her own, and the rest of the practice (schedule, eligibility, claims, remits) sits on the same desk.
Underneath is the OSCAR platform: an event-driven system on Azure where agents and humans write through the exact same door — same risk score, same policy, same hash-chained audit. Autonomy is first-class. A back door is not.
In action
Screens from a synthetic demo practice. No real patients.
Ask Vella
A coordinator types the way they talk — look up a patient, check coverage, draft a claim. Vella answers on a card, and irreversible steps stop on a confirm she will not skip.

Coverage before the chair
The eligibility board is the morning list: who is verified, who has no coverage on file, who needs a live check. A 270/271 is one action, and the result stays on the visit.

Claims, acks, money
Once a claim leaves, this is the desk: 999s, 277s, unpaid, rejected. Open a row for the EDI, the ack, and the remit — the same trail Vella reads when someone asks where a claim is.

Nothing she can do is hidden
What Vella can do is a live catalogue — playbooks she always follows, skills she looks up, and an honest badge for shipping versus still being built. Read from the system, so it cannot go stale.

More of the desk






What she can do
Patient lookup
Name in, the chart and coverage on a card — no tab-hopping through the roster.
Eligibility & coverage
What is on file, then a live 270/271 when the coordinator needs the payer's word.
Draft and send claims
A clean 837D from the visit, CDT rules before it leaves, confirm-gated transmit.
Rejections & remits
999/277 diagnosis and 835 reconciliation land as cards in the inbox, not email.
Schedule lifecycle
Book, confirm, check in, reschedule, no-show, cancel — every verb is a governed write.
Same rails as a human
Agents never get a back door. Risk score, policy, audit hash-chain — identical path.
Impact
Beyond the engineering, I independently negotiated $144,000 off the company's data contract.
System architecture
Eight bounded services communicate through an event backbone. State never changes by side effect: writes go through a single governed entry point that commits the change, an audit record, and an outbox event in one atomic transaction. A relay publishes those events to Service Bus, and downstream services react.
- Governed-write entry point
Every state change flows through one door. Each write is an atomic triple-write inside a single transaction — the state mutation, an immutable audit record, and an outbox event — and is scored by a risk engine + policy sidecar before it commits.
- Agentic reasoning
Assembles context, reasons with an LLM, and executes tool calls under the same governance rules as humans. Authenticates to Azure OpenAI via managed identity.
- Real-time risk scoring
Consumes the operational event stream and computes a live Practice Risk Score across six weighted dimensions. The gateway reads it live to elevate verdicts on risky actions.
- Practice snapshot
Maintains a capability-filtered, token-budgeted live view of each practice in Redis, kept fresh by watchers on the event stream — the context layer agents read from.
- Transactional outbox
Polls the outbox table and publishes events to Service Bus with exactly-once intent. Dialect-aware row locking lets workers scale concurrently without double-publishing.
- Real-time fan-out
Streams events to live clients over WebSockets (Azure Web PubSub) with per-session ordered replay after reconnect.
- Revenue cycle
The dental claims pipeline — eligibility, 837D assembly, clearinghouse submission, and remittance ingestion (detailed below).
- DICOM pipeline
A DICOMweb store (Orthanc) and a web-based radiograph viewer (OHIF) for dental imaging, wired into the same platform.
Data flow
One write, one rulebook. Every governed change — whether a clinician posts a procedure, an agent submits a claim, or an ERA arrives from a payer — moves through the same path. Nothing bypasses it.
- 01
A human action or an agent tool call arrives at one of the bounded services. Both paths converge on the same governed entry point — same writes, same scoring, same audit. There is no back door.
- 02
A policy sidecar evaluates the action against versioned policy that defaults to deny, then a deterministic risk engine bands it. The live Practice Risk Score is read here too — and it can only escalate a verdict, never relax one.
- 03
The state row, a hash-chained audit row, and an outbox row all commit inside one transaction. If any of the three fails, none of them lands — so the event backbone can never announce a change that didn't actually happen.
- 04
A background worker polls the outbox with dialect-aware row locking and publishes the canonical event, keyed so the broker dedupes it. Workers scale concurrently without ever double-publishing.
- 05
Subscribers receive the event through topic filters generated from each service's manifest — routing is declared, never hand-wired. In parallel the delivery service streams it to live clients with per-session ordered replay after a reconnect.
- 06
The revenue-cycle engine assembles a claim, the practice snapshot refreshes, the risk score re-scores, the UI re-renders. Every subscription is idempotent, so a redelivery changes nothing.
- 07
When a reaction leaves the building — a claim to a clearinghouse, a benefit check to a payer — the responses come back in as new governed events through this same path, never as ad-hoc side effects.
Revenue cycle engine
The RCM engine turns clinical work into clean, payer-ready claims and tracks them end to end. The pipeline is deliberately pure — claim assembly does no I/O — so the same logic runs identically from a CLI, an API call, or a batch job, and every output is deterministic and testable against fixtures spanning the full dental code set.
- 01
Real-time benefit checks via X12 270/271 before work begins, so coverage is known up front.
- 02
A clean domain model compiles into a deterministic 837D EDI file through a pure builder — no I/O — so the same pipeline runs from CLI, API, or batch.
- 03
Per-procedure validation across the full CDT taxonomy (D0100–D9999): allowed teeth, required surfaces, and age gates are enforced before submission.
- 04
A canonical receiver/payer table routes each claim to the right clearinghouse and carrier, with hard guards against ID collisions.
- 05
Claims are delivered to the Vyne clearinghouse over pinned-key SFTP, with deterministic, collision-proof filenames safe for parallel retries.
- 06
Functional acks (999) and claim-status responses (277CA) are ingested, de-duplicated, and traced back to the originating claim.
- 07
Electronic remittance advice (835 ERA) is parsed and reconciled — paid amounts, patient responsibility, and per-claim detail preserved for posting.
The risk loop
Every other path on this page has two ends. This one closes. The events a practice generates move its risk score, the score raises the floor on what the gateway will approve without a human, and that floor constrains the very activity that produced the events — so the system gets more cautious exactly where it has been going wrong.
- 25%
Moves when a claim comes back denied. The heaviest dimension, because a denial is the earliest honest signal that something upstream — coding, coverage, eligibility — was wrong before the claim ever left.
- 20%
Moves when a payment fails to reconcile. Money that arrived but can't be matched to what it was paying for. Weighted hard and escalated fast: an unreconciled payment is the one error that compounds silently.
- 20%
Moves when an adjustment is posted. Write-offs and adjustments are legitimate, but they're also where revenue quietly leaves. Volume and pattern matter more than any single entry.
- 20%
Moves when a patient doesn't show. No-shows and cancellations, which drive both the schedule and the forecast. The one dimension driven by patients rather than by the practice.
- 10%
Moves when a compliance gap is detected. Credentialing and compliance gaps that would invalidate work already performed.
- 5%
Moves when an order is approved. Supply and vendor commitments. The lightest weight — it moves slowly and rarely surprises anyone.
Infrastructure
The whole estate is Azure-native and declared as code in Bicep — reproducible per environment, with no click-ops. CI/CD runs three sequential gates on every change: lint & tests, manifest and event-filter validation, then idempotent SQL migrations, container build, deploy, and smoke tests.
Every service runs as an independently-scaled container app
The entire estate is declared as code, modular and parameterized per environment
Entra-only authentication — no SQL passwords anywhere
The event backbone; topic filters generated from service manifests
Live practice snapshots, risk scores, and session state
Real-time WebSocket delivery to clients
LLM reasoning for the agent orchestrator, via managed identity
Secrets isolated from code and never logged
Immutable archive for the audit ledger
VNet + private endpoints in front of data services