SitelineCRM: capture sales data
where the conversation already is.
A Telegram-native B2B sales CRM built for Stylework, an Indian coworking-space aggregator. A rep forwards a WhatsApp chat, sends a voice note, or shares a screenshot. No forms. The model extracts contact, company, seat count, city, space type, budget, move-in date, stage, and next action.
The short
version.
At a glance
| Role | Solo PM and builder. No engineering team. |
| When | July 2026. About 51 hours from first commit to latest. |
| Built for | Stylework, an Indian coworking aggregator. A job-application artifact. |
| What shipped | A Telegram-native sales CRM. A rep forwards a chat, sends a voice note or shares a screenshot, and the model fills the record. A dashboard and an eval harness came with it. |
| Result | 93.5% field accuracy (129/138) on 23 synthetic transcripts. Stage alone scored 14/23, or 60.9%. |
| Limit | Synthetic data, demo-grade auth, no customers. |
| See it | Live product ↗ GitHub ↗ |
This page is the build record for SitelineCRM. It covers the data-capture problem, the extraction pipeline, the eval harness that measures it, and the honest state of what shipped versus what didn’t.
Project overview
OverviewSitelineCRM was built solo as a job-application artifact for an “AI Product Builder” role at Stylework, an Indian coworking-space aggregator. It is live. Landing at siteline.gauravg.dev, dashboard at /dashboard, source at github.com/argaur/siteline-crm.
Built by
Gaurav Gupta. Solo build, first commit 2026-07-16 13:20, latest 2026-07-18 16:16.
Deals don’t die from bad selling.
They go cold.
01 · Problem
A 50-seat inquiry and a 10,000-seat managed-office RFP both start the same way. An unstructured conversation happens: WhatsApp, a call, a walk-in.
A human then has to re-key it into a CRM, chase it, and remember to follow up. It’s a data-capture problem. Today it’s solved with headcount.
Where deals actually die
Re-keying is the tax
Every conversation a rep has must be manually retyped into a CRM before it’s usable pipeline data. That retyping is where the process breaks down first.
The conversation is already structured, in someone’s head
Seat count, budget, move-in date, next action: a rep already knows all of it after the call. The CRM asks them to say it twice.
Nobody retyped it in time
Deals rarely die from a bad pitch. They go cold because the last conversation never made it into the system before the next one arrived.
Capture stays where the
conversation already is.
02 · Solution
No forms. A rep forwards a WhatsApp chat, sends a voice note, or shares a screenshot to a Telegram bot. The model extracts contact, company, seat count, city, space type, budget per seat, move-in date, stage, and next action from raw text, audio, or images.
Forwarded text
Rep forwards the WhatsApp thread as-is. ai.extract_from_text() pulls
the structured fields, then a quality gate checks the extraction before it saves.
Voice note
Whisper transcribes, then intent classification routes it: “capture” extracts a new update, “recall” generates a spoken-style brief on the deal instead. There’s no quality gate. Voice goes straight through.
Screenshot
gpt-4o-mini vision reads a shared screenshot, whether it’s a
proposal PDF page, a WhatsApp screenshot, or a form, the same way it would read
the text version.
What’s actually built
and working.
03 · Capabilities
Pipeline & heat
7-stage pipeline: Inquiry → Qualified → Site Visit → Proposal → Negotiation → Closed-Won / Closed-Lost, self-updating from every capture.
Heat scoring is recomputed on every read, never stored: recency (60%), interaction count (15%), deal size (25%). A never-touched lead reads Cold by design. It cannot drift out of date, because it’s never written.
Nudges & matching
Stalled-deal nudges: the bot DMs the assigned rep when a lead goes quiet past a threshold.
Space matching: city and available seats are hard filters. The 0-100 score is budget fit (45) + space type (30) + capacity right-sizing (25). A 50-seat lead into a 60-seat space outscores the same lead into a 500-seat space.
Manager & dashboard
Manager (“Team”) view: team funnel, rep leaderboard, stalled-deal list. It’s role-gated server-side. Reps hitting these endpoints get HTTP 403.
Dashboard home: pipeline funnel, heat strip, site-visit radar with weather, inventory pressure, a “Needs a Human Today” panel, live activity feed, and city footprint.
Demo mode
A visitor who owns no leads reads the seeded pipeline behind a sample-data banner. The product demonstrates itself.
It’s read-only: cross-user writes still return 403, even in demo mode.
The extraction isn’t just demoed.
It’s measured.
04 · Eval Harness
bot/eval/score_extraction.py runs against
bot/eval/dataset.jsonl: 23 hand-written labelled transcripts, including
Hinglish and informal phrasing that matches real usage, not clean English.
What’s scored, and what’s deliberately not
Six fields per row are graded: stage (exact match against the 7-value
enum) plus presence checks for contact_name, company,
budget_signal, seat_count, and city.
Free-text fields, summary and next_action, are
deliberately excluded. Grading prose needs a human or an LLM-judge, and that
reintroduces the non-determinism the metric exists to avoid.
A --min-accuracy flag makes the harness usable as a CI gate or a
tuning-loop stop condition.
Read the 93.5% with its scope. stage is the only exact-match
field, and it scored 14 of 23, or 60.9%. The five presence-only fields scored 115 of 115,
but a presence check confirms a value exists, not that it is correct. The pooled number
hides the weakest field, and that is the field that decides where a deal sits in the
pipeline. The set is 23 text transcripts, with no separate held-out set and no voice or
screenshot cases.
A documented trust boundary
When tuning extraction, only the prompt in ai.py may be edited. Never
the dataset or the scorer. Editing either of those to make the number go up would be
reward-hacking the eval instead of improving extraction.
The known weakness
The model under-reads stage, defaulting to Inquiry where
Qualified or unknown is correct. This was found by the eval and
confirmed three independent ways.
All 9 misses are this one failure mode. It’s a prompt fix, deliberately not attempted under deadline.
No framework, no bundler,
one provider.
05 · Tech
| Layer | Technology | Details |
|---|---|---|
| Bot backend | Python · FastAPI · python-telegram-bot | Single asyncio process, deploys to Railway. FastAPI lifespan wires bot polling + nudge JobQueue + /api/* together. |
| Database | Neon Postgres · asyncpg | Fully async. Every db.* call is awaited. Five tables: users, companies, leads, interactions, spaces. |
| AI · extraction & vision | OpenAI gpt-4o-mini | Text extraction, vision (screenshots), and reasoning. One provider, one key. |
| AI · transcription | OpenAI Whisper | Voice note transcription ahead of intent classification. |
| Dashboard | Static HTML/JS · no framework, no bundler | Deploys to GitHub Pages via Actions. Authenticates against the bot’s /api/* endpoints via signed per-user HMAC tokens. No credentials shipped to the browser. |
What this is,
and what it isn’t.
06 · Limitations
This candour is deliberate. A build story that hides its limitations is less useful than one that names them.
Runs on seeded data
The pipeline runs on seeded sample data, labelled in-product as such. It’s a working product, not a customer deployment. No revenue.
Auth is demo-grade
Signed HMAC tokens with server-verified roles, but no expiry or revocation. This is a deliberate one-day-demo simplification, not production-grade auth.
The eval dataset is synthetic
Hand-written rather than drawn from real bot traffic, so 93.5% is indicative of extraction quality, not field-proven against production usage.
Complexity the product earns,
not imposes.
07 · Where This Goes
Most CRMs fail because they impose enterprise process on a five-person sales team. SitelineCRM is designed to earn its complexity as the org around it grows. The rep’s own experience never gets heavier.
| Org shape | What unlocks |
|---|---|
| Solo rep | The bot, and nothing else: capture, pipeline, heat score, nudges. |
| Add reps | Assignment and a leaderboard. |
| Add a manager | Team funnel and stalled-deal escalation, already built. |
| Add a sales head over multiple managers | Region roll-ups, forecasting, quota tracking. |
| CEO level | The revenue view. |
Structure accretes above the rep, not on top of them. That’s the thesis this build is arguing for.
Where it started:
Rethink CRM.
08 · Version 0
SitelineCRM began as Rethink CRM, a research concept for founders who sell on their own. Founder interviews showed the same pattern each time. They meant to use a CRM, logged by hand for a few days, and gave up by week four.
Rethink CRM bet that the chat is the record. It became a PRD and a scrappy Telegram bot for solo founders. It never reached a real team.
| Rethink CRM (v0) | SitelineCRM (v1) | |
|---|---|---|
| User | A solo founder who sells | A sales team at Stylework, with reps and a manager |
| Stage | Research, PRD and a rough bot | Shipped and live on seeded data |
| Proof | Founder interviews | An eval harness that scores field extraction |
| Kept | The core bet: capture sales data where the conversation already is. | |