DEV Community

Arham Mirkar
Arham Mirkar

Posted on

The problem we kept hitting

Every agency founder I talked to had the same story: they'd set up HubSpot (or Pipedrive, or Attio), import their contacts, spend a week configuring it — and then watch it slowly become irrelevant as client delivery work took over.

The CRM wasn't bad. The architecture was wrong for how small agencies actually operate.

A standalone CRM only sees CRM data. When a deal goes cold, it can flag "this deal is old." But it cannot see that the deal is cold because a deliverable task has been blocked for a week waiting for client sign-off. That information lives in a different tool.

We built Kobin as a unified workspace where tasks, inbox, CRM, vault, and calendar all share the same Postgres database. And then we built a proactive AI layer on top of it.

Here's how the cross-module risk detection actually works.

The architecture

All modules share foreign keys. A task has a project_id. A project has a client_id. A CRM relationship has a client_id (or maps to one by email). When we scan for risk, we can join across all three in a single query.

-- Simplified: blocked tasks for relationships with stale deals
SELECT r.full_name, r.deal_value, r.pipeline_stage, t.title as blocked_task
FROM relationships r
JOIN projects p ON p.founder_id = r.user_id  -- same workspace
JOIN tasks t ON t.project_id = p.id AND t.status = 'blocked'
WHERE r.user_id = $1
  AND r.stage_entered_at < NOW() - INTERVAL '21 days'
  AND r.pipeline_stage IN ('proposal', 'negotiating', 'meeting_booked')
Enter fullscreen mode Exit fullscreen mode

No Zapier. No webhook sync. One query.

The four intelligence routines

We run four background routines per founder:

1. Risk Detection (multiple times/day via Vercel Cron)
Scans: overdue high-priority tasks + blocked tasks + stale deals. Formats as a structured inbox message. Delivered via our sendAIMessage() function to the founder's dedicated AI room.

2. Revenue Intelligence (3×/week)

Scans: deals closing within 7 days, deals >70% probability, high-value deals ($5k+) stale 14+ days. Calculates weighted revenue. Formats and delivers.

3. Morning Brief (8am via Groq + cron)

Fetches tasks due today, today's events, stale CRM contacts, blocked tasks. Passes to Groq (Llama 4) with a tightly scoped prompt. Max 200 words. One action at the end.

4. Gmail Intelligence (real-time via Pub/Sub)

When Gmail is connected: register a Pub/Sub watch via gmail.users.watch. Google pushes historyId changes to our webhook. We fetch new messages, match senders to CRM contacts by email, run Groq analysis with 8 intent types.

The Gmail analysis prompt

const analysis = await groq.chat.completions.create({
  model: GROQ_MODEL_STD,
  messages: [{
    role: "user",
    content: `Analyze this email for sales pipeline signals.

Intent: interested|not_interested|requesting_info|requesting_meeting|
        following_up|neutral|objection|ready_to_close
Sentiment: positive|neutral|negative
Urgency: high|medium|low
score_delta: -20 to 20
suggested_stage: new_lead|contacted|meeting_booked|proposal|
                 negotiating|closed_won|closed_lost|null
action_items: ["short actionable task title"]

Contact: ${rel.full_name} | Stage: ${rel.pipeline_stage}
Thread: ${emailContent}

Respond ONLY with valid JSON.`
  }]
})
Enter fullscreen mode Exit fullscreen mode

The score_delta is applied to the contact's lead_score field immediately. Pipeline stage is auto-advanced if the AI's suggestion is forward-only (never backwards, except closed_lost).

Auto lead detection

For emails from unknown senders (not in CRM), we run a second AI check:

const relevance = await checkLeadRelevance(
  senderEmail, senderName, subject, snippet
)
// Returns: { relevant: boolean, reason: string, suggestedName: string }
Enter fullscreen mode Exit fullscreen mode

If relevant → auto-create contact as new_lead, tag auto-detected, analyze the thread. If not → ignore. This means your CRM grows automatically from inbound email.

What this unlocks

The morning brief now says things like:

"Tom Williams (VC Fund) — 20 days stale, $45,000. Last email: 'objection' intent, negative sentiment. The proposal from two weeks ago went unanswered."

That's a HubSpot + Gmail + task data synthesis in one sentence. No standalone CRM can produce it.


We're in closed beta at kobin.team. Full technical writeup of the proactive CRM: https://www.kobin.team/blog/proactive-crm-for-agencies

Happy to answer questions on the Pub/Sub watch setup or the cross-module query architecture in the comments.

Top comments (0)