A sanitised reference implementation. Drop it into Claude Code, point it at your own customer messages, adapt the playbook. Generic on purpose, with no business specifics and no real customers.
The problem
Customer messages arrive all day. Most are the same dozen questions, and every one still needs a careful, polite answer. Typing them eats hours. Handing them to a bot that answers on its own is worse, because one wrong promise goes out under your name and you only find out when the customer quotes it back at you.
The idea
Every new customer message gets a drafted reply, written from your own playbook of how you handle each situation, in the voice you sign off with. The drafter can write and nothing else. Every draft waits on your phone for you to approve, edit or skip, and you are the one who sends it. When a draft goes wrong, the case goes into a learned cases file with what the customer said, what the draft got wrong, what you actually wanted and why. The drafter reads that file every time, so it learns your judgement, not just your wording.
new message ──> [draft from your playbook and learned cases] ──> waits for you
│
approve ─── edit ─── skip │
v
sent by you
wrong draft ──> [write it up as a learned case] ──> the next draft is better
Minimal reference implementation
# replies_drafted.py, reference only. Swap in your own inbox, playbook and model.
def draft_reply(message, playbook, learned_cases, model):
"""Text in, text out. The drafter gets no tools, so it has no way to send,
refund or promise anything by itself."""
prompt = (
"You draft replies for a small business owner to approve.\n"
f"Playbook:\n{playbook}\n\n"
f"Learned cases, learn the reasoning and never copy them word for word:\n"
f"{learned_cases}\n\n"
f"Customer message:\n{message['text']}\n\n"
"Write one reply in the owner's voice. If the playbook does not cover it, "
"say so plainly instead of guessing."
)
return model(prompt)
def on_new_message(message, playbook, learned_cases, model, save_for_approval):
draft = draft_reply(message, playbook, learned_cases, model)
save_for_approval(message["id"], draft) # a person approves, edits or skips
A LEARNED CASE, one per draft that went wrong
The message what the customer actually said
What the draft got wrong the exact mistake, in one or two lines
What I wanted the rule behind the right answer
The reply the reply that went out
Why it works
- The drafter cannot act. It writes text and nothing else. Sending is always a person pressing a button, so a bad draft costs a few seconds, never a customer.
- Your playbook, not the model's manners. The drafts follow how you actually handle a refund, a late parcel or a faulty unit, because that is what it reads first.
- It learns judgement from real mistakes. One learned case teaches the reasoning behind a whole family of messages, not one reply to copy.
- Approving is quick. Most drafts need one tap. The time goes on the few that need your thought, which is where it should go.
- It costs pennies. A draft is one short model call, and there is no platform to pay for.
Adapt it
- Start the playbook from your own last fifty replies. The patterns are already in there.
- Add a learned case the same day a draft goes wrong, while you still remember why.
- Keep anything with money, refunds or dates in the approve step for good, even once the drafts are nearly always right.
Built for my own online shop's buyer messages, and this is the generalised version. Take it, point it at your own inbox, tell me what it gets wrong first.