NightDesk: A complete MSP after-hours voice triage system, built overnight
Eight weeks ago NightDesk was a Twilio webhook that answered phone calls and created tickets in ConnectWise.
Today it's a complete MSP after-hours operations platform. This is how it got there.
What NightDesk does
NightDesk answers your MSP's after-hours phone. Callers describe their problem, the AI classifies urgency and category, and the system takes the right action: create a ticket, page the on-call engineer, schedule a callback, or leave a voicemail. No humans required between midnight and 6 AM.
That was version one. Here's what a complete version needs.
The full module list
Call handling core
- Call routing engine. Skill-based dispatch that scores each available tech by proficiency match, tier fit, and load. Escalates immediately for Security issues or Critical priority.
- Voicemail fallback. When AI fails or the caller requests voicemail, records a message, transcribes it, creates a ticket, and alerts the on-call engineer via SES + Slack.
- Language detection. Spanish-language detection from the first caller utterance — zero API calls, zero latency overhead. Spanish speech, English ticket body (so the on-call engineer's debrief is always readable).
Before the call
- Pre-call technician briefing. When a caller is transferred to a tech, the system sends a briefing: caller urgency, sentiment flag, open ticket count, days since last call, and a suggested greeting. Reduces the cognitive load of a 2 AM callout.
- Maintenance window support. Admin CRUD for scheduled maintenance windows. During a window, the triage agent knows about planned downtime and suppresses escalations when appropriate.
During the call
- Transcript sentiment analysis.
analyze_transcript()classifies callers as CALM / CONFUSED / URGENT / FRUSTRATED / HOSTILE with a 0-100 score, exact-phrase signal matching, and per-tier callback opening recommendations. - Ticket auto-classifier. 22 rule-based categories covering Server/UPS/Workstation/Crash/Patch/License/VPN/Connectivity/DNS/Firewall/Email/Phishing/Password/Locked/MFA/RDP/Backup/Malware/Breach/M365/Printer/New Device. Confidence HIGH/MEDIUM/LOW. Priority auto-assigned.
After the call
- Post-call action extractor. Extracts 8 action types from transcripts: callback, escalation, parts order, on-site dispatch, vendor case, ticket create/update, research, client email. Formats CW Internal Analysis notes and Slack messages.
- CSAT tracker. Parses "1/2/3" or "great/ok/poor" from SMS replies after calls. Builds per-tech and per-category rankings with an NPS-style score.
- Caller sentiment recorder. Logs sentiment per call to DDB so trends surface in the morning debrief.
Outbound
- Outbound call notifier. Initiates TwiML-driven outbound calls for critical alerts:
initiate_call → gather → handle_result (ack/escalate/no_answer). DDB-backed with 30-day TTL. - SMS opt-out tracker. TCPA-compliant STOP/UNSUBSCRIBE tracking.
is_opted_out()fails safe — returns True on DDB error, so infra failure never results in a spam call.
Scheduling and rotation
- On-call rotation engine. Pure-compute weekly rotation —
get_oncall_for(entries, anchor_date, dt)with calendar views and Slack Block Kit formatters. No database required for schedule lookup. - Callback scheduler. NL time normalization for "call me back at 9" → structured DDB row. Warm closing speech. Morning debrief shows scheduled callbacks by time.
Reporting
- Shift handoff report.
HandoffTicketRecord + CallSummaryRecord → ShiftHandoff. Aggregates: resolved/escalated/pending-callback counts, new tickets opened, call count + avg duration. Formats Slack Block Kit (tech A → tech B, stats, priority ticket list) and a one-line CW Internal Analysis note. - Call trends. Per-period call volume, category breakdown, resolution rate, avg duration.
- Resolution knowledge base. Keyword-based search over past resolutions, ranked by match score then helpful_rate. Triage agent can offer "last time we fixed this by doing X" before escalating.
- Per-call cost estimator.
PricingConfigcovers Twilio (inbound/outbound/SMS/number), AI (Haiku triage/Sonnet escalation/transcription), infra, and optional labor. Slack Block Kit + plain-text formatters.
Billing
- Trial lifecycle cron. Scans trialing tenants, sends 7-day warning, 1-day warning, and expiry "service paused" SES emails. Idempotent with timestamp guards.
The numbers
1,921 tests passing. Every module has a companion test file. Tests use injectable mocks throughout — no live Twilio or DDB calls in CI.
66 source files. The agent is organized as a flat Python package with one file per concern.
5 SAM-managed Lambda functions. The main triage handler, voicemail cron, trial lifecycle cron, outbound call notifier, and an admin API.
What's next
The codebase is ready for a production SAM deploy. Two things block it:
- A real phone number. The Twilio number needs to be purchased and configured with the webhook URL.
- A first MSP customer. NightDesk charges $299/mo. One paying customer covers hosting + Twilio costs. The second one is profit.
If you run an MSP and your after-hours phone coverage is you personally answering at 2 AM — NightDesk is worth 30 minutes of your time.