Add visit-confirmed to extensions - #425
Conversation
Visit Confirmed is an AI scheduling agent that confirms appointments and recovers no-shows over two-way SMS and voice. This plugin forwards Canvas appointment lifecycle events (created, rescheduled, cancelled, no-show) to Visit Confirmed, which then contacts the patient in the practice's name. The connector sends only resource IDs and scheduling metadata. It transmits no patient names, phone numbers, emails, or clinical data, and logs none either. Visit Confirmed resolves contactable details through the practice's own Canvas FHIR connection under its BAA. Verified before submission: mypy clean under the same mypy.ini used by extensions/missed-appointment-notifications, 6 tests passing against canvas[test-utils] with 100 percent branch coverage, and canvas validate loading the handler cleanly in the sandbox. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…t_time guard
Self-review against this repo's CLAUDE.md plugin checklist found two issues in
the original submission.
The Appointment query did not filter entered_in_error, so a retracted
appointment could have triggered patient outreach. Now filtered, per the
clinical-data rule in CLAUDE.md.
The payload reads patient.id and provider.id, so the query now uses
select_related('patient', 'provider') instead of paying a query apiece.
Adds a defensive guard for a missing start_time, since arrow.get(None) raises.
start_time is declared non-null on the SDK model, so this is precautionary,
matching the guard in extensions/missed-appointment-notifications.
Tests updated to patch the select_related().get() chain, with new cases for the
retraction filter and the missing start time. 8 tests, 100 percent branch
coverage, mypy clean, canvas validate clean.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
Self-reviewed against this repo's Retracted appointments were not excluded. The query was a bare Related objects cost a query apiece. The payload reads Also added a defensive guard for a missing Tests now patch the One note in case it looks off against the checklist: the manifest uses |
VISIT_CONFIRMED_API_URL feeds an Http.post carrying the key in an Authorization
header, and nothing validated the scheme. canvas_sdk's Http does not either:
with no base_url its join_url containment check is joined.startswith(''), which
is always true, so an http:// value would send the key in cleartext.
Implemented as a lowercased prefix test rather than urllib.parse.urlparse,
which the plugin sandbox rejects as a disallowed import. Secrets are stripped on
read, matching extensions/missed-appointment-notifications.
Two new tests cover an http:// endpoint and a scheme-less one. 10 tests, 100
percent branch coverage, mypy clean, canvas validate clean.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
What it does
VisitConfirmed is an AI scheduling agent that confirms patient appointments over two-way SMS and voice. This plugin forwards Canvas appointment lifecycle events (created, rescheduled, cancelled, no-show) to VisitConfirmed, which then contacts the patient in the practice's name, answers what they ask, and passes only the exceptions back to staff.
One handler,
visit_confirmed.handlers.appointment_events:AppointmentEvents, responding toAPPOINTMENT_CREATED,APPOINTMENT_CANCELED, andAPPOINTMENT_NO_SHOWED. A create linked viaappointment_rescheduled_fromis reported as a reschedule.On PHI
The plugin's payload carries resource IDs and scheduling metadata only, no names or contact details, and it logs none either. To be straightforward about the whole picture rather than just the plugin: VisitConfirmed does read patient demographics, over a separate scoped FHIR connection the practice authorizes under a BAA. The README's Privacy section states both channels explicitly rather than leaving the impression that no patient data leaves Canvas.
It is inbound only and never writes appointments back into Canvas.
Configuration
Two sensitive variables,
VISIT_CONFIRMED_API_URLandVISIT_CONFIRMED_API_KEY. The handler fails closed if either is unset: it logs an error and makes no outbound call.Verification
mypy.iniis copied fromextensions/missed-appointment-notificationsso local results match review. Structure follows that plugin as well, includingdocs/inside the package.The README screenshot is generated from
docs/canvas-appointment-confirmation.source.html, committed beside it so it can be re-rendered rather than being an opaque binary. It is an illustration of the conversation, not a capture of real patient data.Source repo
https://github.com/VisitConfirmed/canvas-medical-plugin (public, MIT)
One question for reviewers
Happy to move this if a vendor-branded connector belongs somewhere other than the reference-plugin repo.
extensions/nablasuggested here is right, but say the word and I will relocate it.🤖 Generated with Claude Code