The €700/mo Virtual Assistant I Almost Hired — Replaced By

▶ Watch the video version of this article
Three days before I signed a part-time VA contract, I re-read the job description I'd written. Four tasks. All rule-based. All touching Gmail and Telegram, two systems I already had API access to. I killed the hire that night and spent the weekend building the agent instead. Six months of logs later, here's exactly what I built, what it costs, and where a human VA is still worth every dollar.
The VA job description is your automation spec sheet
Skip the "rank your tasks" step. If you're a solo operator and can't name the four things eating 30+ minutes of your day, you don't have an automation problem — you have an awareness problem, and no scoring matrix fixes that. The prioritized list already exists: it's the VA job description you wrote (or almost wrote). Every bullet is an agent spec, pre-ranked by the fact that you were willing to pay a human to do it.
Mine was 20 hours a week, quoted between $650 and $970/month depending on region. I picked one at $760. The full job:
- Triage inbound email and flag real buyers
- Push buyer details to a channel I check from my phone
- Draft polite replies to repeat questions for approval
- Handle scheduling back-and-forth for calls
That's four deterministic pipelines with clear inputs, clear outputs, and a human-in-the-loop on anything that actually gets sent. Not "AI strategy." Just plumbing.
The tell for whether a VA task is a good agent candidate: can you describe the decision rule in one sentence without saying "it depends"? "If the email mentions pricing or a demo, tag it buyer." Yes. "Draft a reply using our standard onboarding template." Yes. "Handle unexpected client escalations." No — keep the human.
The stack: Gmail API + a classifier + Telegram, running on a home server
The architecture is boring on purpose. Gmail API polls for new mail every two minutes. A classifier agent (Claude Haiku for cost, GPT-4o-mini works too) reads each email and drops it into one of four buckets:
- Buyer intent — summarized and pushed to a private Telegram channel with sender, ask, deal size signal, suggested reply
- Existing client — draft reply written directly to Gmail drafts, waiting for approval
- Admin / noise — labeled and left alone
- Template reply — draft written from an approved response library, one click to send
The core classifier prompt looks like this:
CLASSIFIER_PROMPT = """You are triaging inbound email for a solo operator.
Classify each email into exactly one bucket:
- BUYER_INTENT: prospect asking about pricing, demo, scope, or timeline
- EXISTING_CLIENT: current client, project-related
- TEMPLATE_REPLY: FAQ-style question answerable from a canned response
- NOISE: newsletters, receipts, admin, cold spam
Return JSON:
{
"bucket": "BUYER_INTENT|EXISTING_CLIENT|TEMPLATE_REPLY|NOISE",
"confidence": 0.0-1.0,
"reason": "one sentence",
"extracted": {
"sender_name": "...",
"ask": "one-line summary of what they want",
"deal_size_signal": "small|mid|large|unknown",
"suggested_reply": "2-3 sentence draft"
}
}
If confidence < 0.7, default to EXISTING_CLIENT (safer — I'll see the draft).
"""
Calendar coordination is a sub-flow triggered when the classifier flags scheduling intent. The agent hits the Google Calendar API, finds three open 30-minute slots in the next five business days that respect my working hours, and drafts the reply. Draft — not send.
def draft_scheduling_reply(email_thread, calendar_service):
busy = calendar_service.freebusy().query(body={
"timeMin": now_iso(),
"timeMax": plus_days_iso(5),
"items": [{"id": "primary"}]
}).execute()
slots = find_open_slots(
busy=busy["calendars"]["primary"]["busy"],
duration_min=30,
working_hours=(9, 17),
tz="America/New_York",
count=3
)
return render_scheduling_template(email_thread, slots)
The whole thing runs on my home server — WSL Ubuntu, a systemd timer, and API keys in a .env file. Marginal cost is a few dollars a month in model calls. No SaaS subscription. No Zapier task ceiling.
What's actually in the repo
poller.py— Gmail history API watcher, dedupe on message IDclassifier.py— the LLM call plus retry/backoffhandlers/— one file per bucket (buyer, client, template, noise)calendar_sub.py— availability lookup and slot renderingnotify.py— Telegram Bot API wrappertemplates/— 14 approved response templates as Markdown files
Under 900 lines of Python total. It's not clever. It's just wired up correctly.
The one design choice that keeps it from being embarrassing
The agent is not autonomous on sending. It's autonomous on reading, classifying, extracting, and drafting. I am the send button. Every outbound message — every reply, every scheduling confirmation — sits in Gmail as a draft until I open it and hit send.
That single rule is what makes the system reliable in production instead of a horror story. When the classifier misfires (and it does, about 4% of the time by my count), the failure mode is a draft I delete, not an email a client received. When Anthropic ships a model update that shifts tone, I catch it on the next reply I edit, not three weeks later when a customer forwards a screenshot.
The autonomy split I use for every solo-operator agent I build for clients:
| Action | Agent decides | Human decides |
|---|---|---|
| Read incoming data | ✅ | |
| Classify / route | ✅ | |
| Extract structured fields | ✅ | |
| Draft outbound content | ✅ | |
| Send outbound content | ✅ | |
| Charge money / commit spend | ✅ | |
| Schedule meetings on calendar | ✅ (I confirm the slot) |
You can loosen this later once you've watched the drafts for a month and know where the model breaks. Don't loosen it on day one.
30 days of logs: what the agent actually did
Pulled from the SQLite log the poller writes to. No estimates, straight counts:
| Metric | Daily avg | Monthly total |
|---|---|---|
| Inbound emails processed | 40 | 1,203 |
| Buyer-intent leads routed to Telegram | 8 | 241 |
| Draft replies written | 12 | 361 |
| Drafts sent with zero edits | 10 | ~300 |
| Drafts I lightly edited | 2 | ~60 |
| Misclassifications caught | ~1.6 | 48 |
| Scheduling threads handled end-to-end | — | 17 |
Time back, measured by tracking my inbox time before (RescueTime, four-week baseline) and after: 72–91 minutes per day. Call it 35 hours a month.
Cost side, same 30-day window:
- Claude Haiku classification: $4.10
- GPT-4o-mini for draft generation: $7.80
- Telegram Bot API: $0
- Google APIs (Gmail, Calendar): $0 (well under free tier)
- Server: already running for other projects, marginal cost ~$0
Total: $11.90/month.
The honest comparison: agent vs. VA at $760/mo
The agent doesn't do everything a good VA does. A VA also handles light research, formatting, occasional judgment calls, and the odd "can you call this vendor and figure out why the invoice is wrong" task. Those are not agent tasks in 2026 — not reliably, not without a human on the send button for higher-stakes work.
So the honest split of that 20-hour/week role:
- ~10 hours/week was the repetitive core: triage, draft, route, schedule. The agent covers this.
- ~10 hours/week was judgment, research, formatting, and one-off tasks. The agent doesn't cover this, and I don't want it to.
At $760/month for 80 hours, the agent replaces roughly half the role — call it $380/month of VA work at $11.90/month of API spend. Six months in, that's about $2,200 saved, minus the weekend I spent building it. It never has a bad day, never quits in month three, never needs onboarding when I take on a new client, and doesn't sleep through timezones.
What I still don't automate:
- First reply to any new enterprise-tier lead (I want my fingerprints on it)
- Anything involving contracts, invoices, or refunds
- Client escalations
- Anything where getting it wrong costs more than a customer's afternoon
If your VA role is mostly the judgment stuff, don't build this. Hire the VA. If it's mostly the four tasks I listed, you're looking at a weekend of work and $12/month.
The build order that actually ships
Most people who try this get stuck at week two because they try to build all four handlers at once. Do it in this order — each step delivers value before the next one exists:
- Classifier + labels only (day 1). Just tag every email with a bucket. Read them yourself. You'll immediately know how accurate it is and where it breaks.
- Telegram notifier for buyers (day 2). Only the BUYER_INTENT bucket. You'll stop missing leads within 24 hours.
- Template replies for FAQs (day 3–4). Start with your top 5 canned responses. Grow the library as you notice repeats.
- Existing-client drafts (day 5–7). Highest risk of tone drift, so it goes last, when you already trust the classifier.
- Calendar sub-flow (week 2). Only after everything else is stable.
Skip the "let's design the whole system" phase. Ship the classifier on day one, live with it for 48 hours, then decide what to build next based on what you actually saw in the logs.
Where bizflowai.io fits in
This is the exact pattern we productize for clients at bizflowai.io — inbox triage, lead routing to whatever channel you already check (Telegram, Slack, SMS), draft-first reply generation, and calendar coordination as a sub-flow, all with the human on the send button. If you'd rather not spend a weekend wiring Gmail and Calendar APIs together and maintaining it yourself, the hosted version runs the same architecture I described here — same autonomy boundaries, same draft-not-send default — configured against your templates and your inbox in an afternoon.
Want more like this?
I publish practical AI automation, GenAI engineering, and faceless content workflows on YouTube every week.
Subscribe to bizflowai.io on YouTube — never miss a new tutorial.
Planning an AI automation project or need a second opinion on your architecture?
Connect with me on LinkedIn — Lazar Milicevic, GenAI Engineer & bizflowai.io Founder.
Visit bizflowai.io for our services, case studies, and AI consulting.
Frequently asked questions
What is the fastest way for a solopreneur to prioritize which tasks to automate with an AI agent?
Skip the ranking matrix. If you're a solopreneur, you already know the four things eating 30+ minutes of your day. Instead, write the job description you'd give a virtual assistant and treat every bullet point as an agent spec. The list is already prioritized by the fact that you were willing to pay a human to do it. Ranking exercises are procrastination dressed up as strategy.
How do I replace a virtual assistant with an AI email agent?
Identify the repetitive, rule-based tasks in your VA job description, then build an agent around APIs you already use. A typical stack: Gmail API pulls inbound mail every few minutes, a classifier agent sorts emails into buckets (buyer intent, existing client, admin, template reply), and outputs either Telegram notifications or Gmail drafts. Run it on a home server with a scheduled job. Marginal cost is a few euros per month in model calls.
Why should an AI email agent draft replies instead of sending them automatically?
Keeping a human on the send button is the design choice that makes email agents reliable instead of embarrassing. The agent handles reading, classifying, extracting details, and drafting responses, but every outbound message waits for approval as a Gmail draft. This preserves oversight on tone and accuracy while still eliminating the time cost of composing replies from scratch.
When should I hire a virtual assistant vs build an AI agent?
If the tasks are repetitive, rule-based, and touch systems with API access (like Gmail, calendar, or messaging tools), build an agent. A part-time VA typically costs 600–900 euros per month, while an agent runs for a few euros in model calls. Hire a human when tasks require judgment, relationship-building, or handling unstructured situations that don't fit clear rules.
What does an AI email triage agent actually do?
It pulls new inbound email via the Gmail API every few minutes and classifies each message into four buckets: buyer intent (summarized and pushed to Telegram with key details), existing client (draft reply written in Gmail), admin/noise (labeled and ignored), and template replies (drafted from an approved response library). A sub-flow handles calendar scheduling by checking availability and drafting replies with three concrete time slots.