Handover
When the bot stops and asks for a person, what that person is sent, and how to set it up. The reasoning is in Architecture, under "The handover email goes over Resend's API, not SMTP".
When it fires
A handover is one of four exits from a question, and it always means a person really is coming: the team is emailed every time. It is reached two ways:
| Route | What happened | Emails the team |
|---|---|---|
| Sensitive | The safety gate judged the message to be about medication, symptoms or a diagnosis | Yes |
| Failed validation | The model produced something the design says it cannot produce | Yes |
Two more exits never reach a handover at all: crisis, which needs a faster channel than an inbox and says so in the reply, and scope, where the bot cannot help and says so plainly — the question is off-topic, or on-topic with no lesson that fits ("I don't have a resource that covers that, so I can't help with it here"). Nobody needs to follow up on either, and nobody is told they will.
What no longer emails. On 2026-09-18 the eating-disorder rule was narrowed to physical compensation and prolonged restriction, and the model gate was given the same line. Bingeing, eating in secret, hiding wrappers, feeling out of control or addicted, and getting back on plan after a slip are answered with the lesson written for them instead of becoming a handover. Purging, laxatives, chewing and spitting, days without food, and eating to the point of being sick most nights still reach a person. See the architecture notes under "The eating-disorder rule was narrowed to compensation".
Why "no fitting lesson" is not a handover. It is the common case rather than the alarming one — it fires for anything the courses do not cover. Measured on a sixteen-message probe, it produced nine of the eleven emails: greetings, "test", a keysmash and a spam link among them. An inbox that is mostly noise is one nobody reads, and the cost of that is the clinical handover sitting unread in it.
It first stopped emailing while still being called a handover, so the member was told "someone from the team will follow this up" and nobody was. On 2026-09-29 it became a scope reply instead: handovers are kept for crisis and clinical questions, and anything else the bot cannot answer gets an honest "I can't help with that", with the office number when one is configured. The same change stopped a decline with a blank model sentence from failing validation, which had been turning some of these into emailed handovers.
What the email holds
Enough to act without opening anything else:
Subject: [Deciple] handover — <the member's question, clipped>
Question the member's words, verbatim
What the member was told the reply they actually saw
What the model was shown the ranked candidates, with scores
Why it came to you reason, confidence, lesson, trace id, timestamp
The trace id opens the whole request in MLflow — every stage, in order, with what each one decided. The recurring question about a bad handover is whether the model chose badly or was shown nothing usable, and the candidate list answers it directly.
Setting it up
Three variables, all listed in Environment variables:
RESEND_API_KEY=...
DECIPLE_MAIL_FROM=Deciple <bot@yourdomain.com>
DECIPLE_HANDOVER_TO=whoever-reads-these@yourdomain.com
DECIPLE_HANDOVER_TO has no default. A wrong address here mails a member's
health question to a stranger, and a default is how that happens quietly.
An empty RESEND_API_KEY means no email is attempted. Everything else still
works: the member still gets the handover reply, and the trace is still
written.
The sandbox sender
Until a domain is verified with Resend, the only working sender is Resend's
sandbox address, onboarding@resend.dev. It delivers to the account owner and
silently drops everyone else. Resend still returns a message id, and the
log still says the email was sent.
So adding a teammate to DECIPLE_HANDOVER_TO before the DNS records exist
looks like it worked and does not. Verify the domain first, or keep the address
as the Resend account owner's.
The email cannot slow a member down
It is sent as a background task after the reply has gone out. A slow or dead mail server costs the member nothing — they have already been told a person will follow up.
That also means a failed send does not fail the request. It is logged, and the
Resend id in the log line is what you look up in the Resend dashboard when
someone says they never got it.
Checking it without a member
Ask the bot something clinical — anything about your own medication, symptoms or a diagnosis. That takes the sensitive route, which emails.
Asking something merely off-topic, or something no lesson covers, will not do it: both are scope replies, and neither sends anything.