Fitting a daily CRM briefing into one WhatsApp message
The dashboard report ran to three sections, but the phone version had to fit Twilio’s 1,600-character limit and read at a glance. Five prompt versions in three days ended in a fixed template and a hard cap in code.
The problem
The full report was too long and too heavily formatted for a phone.
The fix
A fixed template in the prompt, and a 1,500-character cap enforced in code.
- ≤ 1,500
- characters, cut at a line break
- 5
- versions of the WhatsApp prompt in 3 days
- 3 · 2 · 2
- figures, signals and actions per message
The briefing has two readers. The dashboard has room for three sections of analysis. A phone gets one screen, WhatsApp’s own formatting and, through Twilio, a limit of 1,600 characters a message. The same text couldn’t serve both.
One prompt, two outputs
The local model writes both versions in one go, each inside its own tag, and Python splits them: the long report is saved for the dashboard and the short one goes to WhatsApp. How the job keeps a small model to that format is its own story.
Five versions in three days
The git history holds five versions of the WhatsApp half of the prompt, all between 23 and 25 February:
- Free-form. A concise summary for a phone screen: five to seven lines, one action, no emojis.
- Counted bullets. Two or three on volume and pipeline, one or two on channels, exactly two actions, under 1,400 characters. The hard cap in code arrived in the same commit.
- Anomalies in. Once the overloaded-salesperson and junk-channel rules existed, one or two bullets had to cover the most critical flag.
- Sections and slots. Markdown headers don’t render well in WhatsApp, so section titles moved to WhatsApp’s own bold, and every figure got a slot to fill.
- A fixed template. No headers and no bold: three figures, two signals and two focus lines, with three emoji as markers.
The final template, lightly simplified:
📊 Daily CRM Summary - [Month Day]
• New Leads: [X] ([+/-X%] vs avg)
• Pipeline Generated: [amount]
• Deals Closed: [amount]
⚠️ Signals:
- [overloaded salesperson or junk channel, with exact numbers]
- [any other anomaly or pacing drop]
👉 Focus:
- [one action based on the data]
- [one action based on the data]
Each version moved more of the shape out of the model’s judgement and into the prompt. By the last, the model fills the slots and writes four short lines of its own. The final prompt doesn’t even mention a character count: the template is short, and the code enforces the rest.
Ask in the prompt, enforce in code
The code doesn’t trust the prompt. If the WhatsApp text runs over 1,500 characters, Python cuts it at the last line break before the limit and adds a short note that it was trimmed. That leaves 100 characters of headroom under Twilio’s 1,600, and cutting at a line break means a figure is never chopped in half.
Getting it delivered
Messages go through Twilio’s WhatsApp sandbox, with both numbers prefixed whatsapp:. The first real test connected and was still refused, with error 20003. Two fixes got it through. The phone numbers went into strict E.164 format (a plus sign, the country code, then digits, no spaces), and the account ID and auth token, which had been swapped in the config, went back in their right places.
What I’d change
The template lives in the prompt, so the model still copies the three headline figures from its input into the slots. The next step is to fill those three in Python and let the model write only the signals and focus lines. Then the figures people forward can’t be mistyped.
Rules I’d keep
- Design for the screen it lands on. WhatsApp isn’t a small dashboard.
- Ask in the prompt, enforce in code.
- Cut at a line break, never mid-figure.
- Put figures in fixed slots, ideally filled by code.